/* global React, ReactDOM */
const DS = window.RecnoteHealthCenterDesignSystem_522961;
const {
  SiteHeader, SearchBar, CollectionCard, ArticleRow, SearchResultCard,
  Breadcrumbs, TocSidebar, ReactionBar, ChatLauncher, SiteFooter, Icon
} = DS;
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ---------- helpers ----------
const api = async (url, opts = {}) => {
  const r = await fetch(url, { headers: { "Content-Type": "application/json" }, ...opts });
  if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error || r.statusText);
  return r.json();
};

function getVisitorId() {
  let id = localStorage.getItem("recnote-visitor");
  if (!id) {
    id = Math.random().toString(36).slice(2) + Date.now().toString(36);
    localStorage.setItem("recnote-visitor", id);
  }
  return id;
}
const VISITOR_ID = getVisitorId();

function useHashRoute() {
  const parse = () => {
    const h = location.hash.replace(/^#\/?/, "");
    const [seg, id] = h.split("/");
    if (seg === "collection" && id) return { s: "collection", id };
    if (seg === "article" && id) return { s: "article", id };
    return { s: "home" };
  };
  const [route, setRoute] = useState(parse);
  useEffect(() => {
    const on = () => { setRoute(parse()); window.scrollTo(0, 0); };
    window.addEventListener("hashchange", on);
    return () => window.removeEventListener("hashchange", on);
  }, []);
  return route;
}
const nav = (path) => { location.hash = path; };

function slugify(s) {
  return s.toLowerCase().replace(/[åä]/g, "a").replace(/ö/g, "o")
    .replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "sektion";
}

// Parse article body html: give every h3 an id, build TOC
function processBody(html) {
  const div = document.createElement("div");
  div.innerHTML = html || "";
  const toc = [];
  const seen = {};
  div.querySelectorAll("h3").forEach(h => {
    let id = h.id || slugify(h.textContent);
    while (seen[id]) id += "-2";
    seen[id] = true;
    h.id = id;
    toc.push({ id, label: h.textContent });
  });
  return { html: div.innerHTML, toc };
}

const timeAgo = (iso) => {
  const s = (Date.now() - new Date(iso).getTime()) / 1000;
  if (s < 60) return "nyss";
  if (s < 3600) return Math.floor(s / 60) + " min sedan";
  if (s < 86400) return Math.floor(s / 3600) + " tim sedan";
  return Math.floor(s / 86400) + " dagar sedan";
};

const wrap = { maxWidth: "var(--container-max)", margin: "0 auto", padding: "0 40px" };

// ---------- screens ----------
function Hero({ big, q, setQ, title }) {
  return (
    <div style={{ background: "#FFFFFF url('/assets/hero-motif-light.svg') center/cover no-repeat" }}>
      <div className="wrap">
        <SiteHeader onBrandClick={() => { setQ(""); nav("/"); }} />
        {big && <h1 className="hero-title">{title}</h1>}
        <div style={{ padding: "8px 0 36px", "--surface-field-hero": "#fdfdfc", "--border-field-hero": "#E5E2DA" }}>
          <SearchBar value={q} onChange={setQ} onClear={() => setQ("")} />
        </div>
      </div>
    </div>
  );
}

function HomeGrid({ collections }) {
  return (
    <div className="wrap section-home">
      <div className="home-grid">
        {collections.map(c => (
          <CollectionCard key={c.id} title={c.title} count={c.count} onClick={() => nav("/collection/" + c.id)} />
        ))}
      </div>
    </div>
  );
}

function SearchResults({ q }) {
  const [results, setResults] = useState(null);
  useEffect(() => {
    let live = true, trackT = null;
    const t = setTimeout(() => {
      api("/api/search?q=" + encodeURIComponent(q)).then(r => {
        if (!live) return;
        setResults(r);
        // spåra sökningen först när användaren slutat skriva
        trackT = setTimeout(() => {
          api("/api/track/search", { method: "POST", body: JSON.stringify({ q, hits: r.length }) }).catch(() => {});
        }, 1200);
      }).catch(() => {});
    }, 200);
    return () => { live = false; clearTimeout(t); clearTimeout(trackT); };
  }, [q]);
  return (
    <div className="wrap section-search">
      <div style={{ font: "600 var(--text-card-title) var(--font-ui)", color: "var(--text-heading)", marginBottom: 20 }}>
        <span style={{ fontWeight: 400, color: "var(--text-body)" }}>Sökresultat för: </span>{q}
      </div>
      <div style={{ display: "grid", gap: 16 }}>
        {results && results.length === 0 && (
          <div style={{ color: "var(--text-body)" }}>Inga artiklar matchade din sökning.</div>
        )}
        {(results || []).map(r => (
          <SearchResultCard key={r.id} title={r.title} excerptHtml={r.excerptHtml} onClick={() => nav("/article/" + r.id)} />
        ))}
      </div>
    </div>
  );
}

function CollectionPage({ id }) {
  const [col, setCol] = useState(null);
  const [err, setErr] = useState(null);
  useEffect(() => { setCol(null); api("/api/collections/" + id).then(setCol).catch(e => setErr(e.message)); }, [id]);
  if (err) return <div style={{ ...wrap, padding: 60 }}>Samlingen hittades inte.</div>;
  if (!col) return <div style={{ ...wrap, padding: 60 }} />;
  return (
    <div className="narrow-page">
      <Breadcrumbs items={[{ label: "Alla samlingar", onClick: () => nav("/") }, { label: col.title }]} />
      <h1 className="page-title">{col.title}</h1>
      <div style={{ font: "400 var(--text-small) var(--font-ui)", color: "var(--ink-500)", marginBottom: 28 }}>{col.articles.length} artiklar</div>
      <div className="list-card">
        {col.articles.length === 0 && <div style={{ padding: "24px 0", color: "var(--text-body)" }}>Inga artiklar i denna samling ännu.</div>}
        {col.articles.map(a => (
          <div key={a.id} className="hover-row">
            <ArticleRow title={a.title} description={a.description} onClick={() => nav("/article/" + a.id)} />
          </div>
        ))}
      </div>
    </div>
  );
}

function useIsMobile() {
  const [m, setM] = useState(() => window.matchMedia("(max-width: 760px)").matches);
  useEffect(() => {
    const mq = window.matchMedia("(max-width: 760px)");
    const on = e => setM(e.matches);
    mq.addEventListener("change", on);
    return () => mq.removeEventListener("change", on);
  }, []);
  return m;
}

function MobileToc({ items, activeId, onSelect }) {
  const [open, setOpen] = useState(false);
  const active = items.find(t => t.id === activeId);
  return (
    <div className="toc-box" style={{ padding: 0, overflow: "hidden" }}>
      <button onClick={() => setOpen(o => !o)}
        style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, width: "100%", background: "none", border: "none", cursor: "pointer", padding: "13px 16px", font: "600 14px var(--font-ui)", color: "var(--text-heading)", textAlign: "left" }}>
        <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
          Innehåll{active && !open ? <span style={{ fontWeight: 400, color: "var(--ink-500)" }}> · {active.label}</span> : null}
        </span>
        <Icon name="chevron-down" size={16} color="var(--ink-500)" style={{ flex: "none", transform: open ? "rotate(180deg)" : "none", transition: "transform 150ms ease" }} />
      </button>
      {open && (
        <div style={{ padding: "2px 16px 14px", borderTop: "1px solid var(--cream-100)" }}>
          <div style={{ paddingTop: 12 }}>
            <TocSidebar items={items} activeId={activeId} onSelect={(tid) => { setOpen(false); onSelect(tid); }} />
          </div>
        </div>
      )}
    </div>
  );
}

function ArticlePage({ id }) {
  const [art, setArt] = useState(null);
  const [err, setErr] = useState(null);
  const [activeToc, setActiveToc] = useState(null);
  const isMobile = useIsMobile();
  const scrollLock = useRef(false);
  const lockTimer = useRef(null);

  useEffect(() => { setArt(null); api("/api/articles/" + id).then(setArt).catch(e => setErr(e.message)); }, [id]);
  const body = useMemo(() => art ? processBody(art.body) : { html: "", toc: [] }, [art]);

  // spåra sidvisning
  useEffect(() => {
    if (art) api("/api/track/view", { method: "POST", body: JSON.stringify({ articleId: art.id }) }).catch(() => {});
  }, [art && art.id]);

  useEffect(() => {
    if (body.toc.length) setActiveToc(body.toc[0].id);
    const onScroll = () => {
      if (scrollLock.current || !body.toc.length) return;
      let current = body.toc[0].id;
      for (const t of body.toc) {
        const el = document.getElementById(t.id);
        if (el && el.getBoundingClientRect().top <= 120) current = t.id;
      }
      setActiveToc(current);
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, [body]);

  // initiera Video.js-spelare för videoblock i artikeln
  useEffect(() => {
    if (!window.videojs) return;
    const players = [...document.querySelectorAll(".article-body video.video-js")]
      .map(el => window.videojs(el, { fluid: true, preload: "metadata" }));
    return () => players.forEach(p => { try { p.dispose(); } catch {} });
  }, [body]);

  const gotoToc = (tid) => {
    setActiveToc(tid);
    scrollLock.current = true;
    clearTimeout(lockTimer.current);
    lockTimer.current = setTimeout(() => { scrollLock.current = false; }, 800);
    const el = document.getElementById(tid);
    if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 16, behavior: "smooth" });
  };

  if (err) return <div style={{ ...wrap, padding: 60 }}>Artikeln hittades inte.</div>;
  if (!art) return <div style={{ ...wrap, padding: 60 }} />;
  const colTitle = art.collectionTitle;
  return (
    <div className="article-page">
      <Breadcrumbs items={[
        { label: "Alla samlingar", onClick: () => nav("/") },
        { label: "Samling", onClick: () => nav("/collection/" + art.collectionId) },
        { label: art.title }
      ]} />
      <div className={"article-grid" + (body.toc.length ? "" : " no-toc")}>
        <article>
          <h1 className="article-title">{art.title}</h1>
          {art.description && <p style={{ margin: "0 0 14px", fontSize: 17, lineHeight: "var(--leading-body)", color: "var(--text-body)" }}>{art.description}</p>}
          <div style={{ font: "400 var(--text-meta) var(--font-ui)", color: "var(--ink-400)", margin: "6px 0 30px" }}>Uppdaterad {timeAgo(art.updatedAt)}</div>
          <div className="article-body" dangerouslySetInnerHTML={{ __html: body.html }} />
          <div style={{ margin: "44px 0" }}>
            <ReactionBar onReact={(emoji) => api("/api/articles/" + art.id + "/react", { method: "POST", body: JSON.stringify({ emoji }) }).catch(() => {})} />
          </div>
          {art.related.length > 0 && <>
            <h3 style={{ font: "700 var(--text-h3) var(--font-ui)", color: "var(--text-heading)", margin: "0 0 16px" }}>Relaterade artiklar</h3>
            <div className="list-card tight">
              {art.related.map(t => (
                <div key={t.id} className="hover-row">
                  <ArticleRow title={t.title} onClick={() => nav("/article/" + t.id)} />
                </div>
              ))}
            </div>
          </>}
        </article>
        {body.toc.length > 0 && (
          <div className="toc-col">
            <div className="toc-sticky">
              {isMobile
                ? <MobileToc items={body.toc} activeId={activeToc} onSelect={gotoToc} />
                : <TocSidebar items={body.toc} activeId={activeToc} onSelect={gotoToc} />}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// ---------- chat widget ----------
function ChatSuggestionList({ query, onOpen }) {
  const [all, setAll] = useState([]);
  useEffect(() => { api("/api/articles").then(setAll).catch(() => {}); }, []);
  const items = query.trim()
    ? all.filter(a => a.title.toLowerCase().includes(query.trim().toLowerCase())).slice(0, 5)
    : all.slice(0, 4);
  // spåra chatt-sökningar när användaren slutat skriva
  useEffect(() => {
    if (!query.trim() || !all.length) return;
    const t = setTimeout(() => {
      api("/api/track/search", { method: "POST", body: JSON.stringify({ q: query, hits: items.length }) }).catch(() => {});
    }, 1200);
    return () => clearTimeout(t);
  }, [query, all.length]);
  return <>
    {items.map(a => (
      <div key={a.id} className="chat-item" onClick={() => onOpen(a.id)}
        style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, padding: "13px 16px", cursor: "pointer", transition: "background 150ms ease" }}>
        <div style={{ font: "400 14px var(--font-ui)", color: "#5A7050", lineHeight: 1.45 }}>{a.title}</div>
        <Icon name="chevron-right" size={14} color="#364531" style={{ flex: "none" }} />
      </div>
    ))}
  </>;
}

function ChatSearchBox({ value, onChange }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "0 16px", height: 48, borderBottom: "1px solid var(--border-card)" }}>
      <input value={value} onChange={e => onChange(e.target.value)} placeholder="Sök efter hjälp"
        style={{ flex: 1, border: "none", outline: "none", background: "transparent", font: "600 14px var(--font-ui)", color: "var(--ink-900)" }} />
      <Icon name="search" size={16} color="#353535" />
    </div>
  );
}

function bubbleStyle(from) {
  const user = from === "user";
  return {
    maxWidth: "78%", padding: "10px 14px", borderRadius: 14,
    font: "400 14px var(--font-ui)", lineHeight: 1.5, whiteSpace: "pre-wrap",
    background: user ? "#364531" : "#FFFFFF",
    color: user ? "#FFFFFF" : "var(--text-body)",
    border: user ? "none" : "1px solid var(--border-card)"
  };
}

function ChatThread({ conv, onBack, settings }) {
  const [msgs, setMsgs] = useState(null);
  const [input, setInput] = useState("");
  const scrollRef = useRef(null);

  const scrollDown = () => setTimeout(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, 50);

  useEffect(() => {
    api("/api/chat/conversations/" + conv.id + "/messages").then(m => { setMsgs(m); scrollDown(); }).catch(() => {});
  }, [conv.id]);

  useEffect(() => {
    const on = (e) => {
      if (e.detail.conversationId === conv.id) {
        setMsgs(m => (m || []).some(x => x.id === e.detail.message.id) ? m : [...(m || []), e.detail.message]);
        scrollDown();
      }
    };
    window.addEventListener("chat-message", on);
    return () => window.removeEventListener("chat-message", on);
  }, [conv.id]);

  const send = async () => {
    const text = input.trim();
    if (!text) return;
    setInput("");
    const m = await api("/api/chat/conversations/" + conv.id + "/messages", { method: "POST", body: JSON.stringify({ text }) }).catch(() => null);
    if (m) setMsgs(x => (x || []).some(y => y.id === m.id) ? x : [...(x || []), m]);
    scrollDown();
  };

  return <>
    <div ref={scrollRef} style={{ flex: 1, overflowY: "auto", padding: 16, display: "flex", flexDirection: "column", gap: 10 }}>
      {(msgs || []).map(m => m.from === "agent" ? (
        <div key={m.id} style={{ display: "flex", gap: 8, alignItems: "flex-end" }}>
          {m.authorAvatar
            ? <img src={m.authorAvatar} alt="" style={{ width: 28, height: 28, borderRadius: "50%", objectFit: "cover", flex: "none" }} />
            : <div style={{ width: 28, height: 28, borderRadius: "50%", background: "#364531", color: "#FFF", display: "flex", alignItems: "center", justifyContent: "center", font: "600 11px var(--font-ui)", flex: "none" }}>{(m.authorName || "S").slice(0, 1).toUpperCase()}</div>}
          <div style={{ maxWidth: "78%" }}>
            <div style={{ font: "400 11px var(--font-ui)", color: "var(--ink-400)", margin: "0 0 3px 2px" }}>{m.authorName || "Support"}</div>
            <div style={{ ...bubbleStyle("agent"), maxWidth: "100%" }}>{m.text}</div>
          </div>
        </div>
      ) : (
        <div key={m.id} style={{ display: "flex", justifyContent: m.from === "user" ? "flex-end" : "flex-start" }}>
          <div style={bubbleStyle(m.from)}>{m.text}</div>
        </div>
      ))}
      {msgs && msgs.length === 0 && (
        <div style={{ display: "flex", justifyContent: "flex-start" }}>
          <div style={bubbleStyle("bot")}>Hej! Hur kan vi hjälpa dig?</div>
        </div>
      )}
    </div>
    <div style={{ display: "flex", gap: 8, padding: 12, borderTop: "1px solid var(--border-card)", background: "#FFFFFF" }}>
      <input value={input} onChange={e => setInput(e.target.value)} onKeyDown={e => { if (e.key === "Enter") send(); }}
        placeholder="Skriv ett meddelande ..." autoFocus
        style={{ flex: 1, border: "1px solid var(--border-card)", borderRadius: 12, padding: "0 14px", height: 40, font: "400 14px var(--font-ui)", color: "var(--ink-900)", outline: "none", background: "#FFFFFF" }} />
      <button onClick={send} aria-label="Skicka"
        style={{ background: "#364531", color: "#FFFFFF", border: "none", borderRadius: 12, height: 40, padding: "0 16px", font: "600 14px var(--font-ui)", cursor: "pointer" }}>
        Skicka
      </button>
    </div>
  </>;
}

function ChatWidget({ settings }) {
  const [open, setOpen] = useState(false);
  const [tab, setTab] = useState("hem");
  const [query, setQuery] = useState("");
  const [convs, setConvs] = useState([]);
  const [activeConv, setActiveConv] = useState(null);
  const wsRef = useRef(null);

  const loadConvs = useCallback(() => {
    api("/api/chat/conversations?visitorId=" + VISITOR_ID).then(setConvs).catch(() => {});
  }, []);

  useEffect(() => { loadConvs(); }, [loadConvs]);

  // websocket for live updates
  useEffect(() => {
    let ws, closed = false;
    const connect = () => {
      ws = new WebSocket((location.protocol === "https:" ? "wss://" : "ws://") + location.host + "/ws?visitorId=" + VISITOR_ID);
      wsRef.current = ws;
      ws.onmessage = (ev) => {
        try {
          const data = JSON.parse(ev.data);
          if (data.type === "message") {
            window.dispatchEvent(new CustomEvent("chat-message", { detail: data }));
            loadConvs();
          }
        } catch {}
      };
      ws.onclose = () => { if (!closed) setTimeout(connect, 2000); };
    };
    connect();
    return () => { closed = true; ws && ws.close(); };
  }, [loadConvs]);

  const [contact, setContact] = useState(() => {
    try { return JSON.parse(localStorage.getItem("recnote-chat-contact")) || { name: "", email: "" }; }
    catch { return { name: "", email: "" }; }
  });
  const [contactForm, setContactForm] = useState(false);
  const [contactErr, setContactErr] = useState(null);

  const newConversation = () => { setTab("msgs"); setActiveConv(null); setContactErr(null); setContactForm(true); };

  const startConversation = async () => {
    const name = contact.name.trim(), email = contact.email.trim();
    if (!name || !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) { setContactErr("Ange ditt namn och en giltig e-postadress."); return; }
    localStorage.setItem("recnote-chat-contact", JSON.stringify({ name, email }));
    const c = await api("/api/chat/conversations", { method: "POST", body: JSON.stringify({ visitorId: VISITOR_ID, name, email }) })
      .catch(e => { setContactErr(e.message); return null; });
    if (c) { setConvs(v => [c, ...v]); setActiveConv(c); setContactForm(false); }
  };

  const openMessages = () => {
    setTab("msgs");
    if (convs.length === 0) newConversation();
    else if (convs.length === 1) setActiveConv(convs[0]);
  };

  const openArticle = (id) => { nav("/article/" + id); };

  const tabBtn = (active) => ({
    flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4,
    padding: "10px 0 12px", background: "none", border: "none", cursor: "pointer",
    font: `${active ? 600 : 400} 12px var(--font-ui)`, color: active ? "#364531" : "#B8B4B2"
  });

  return <>
    {open && (
      <div className="chat-panel">

        {tab === "hem" && (
          <div style={{ flex: 1, overflowY: "auto", padding: "20px 20px 12px", display: "flex", flexDirection: "column" }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
              <img src="/assets/recnote-logo.svg" alt="Recnote" style={{ height: 18, width: "auto", display: "block" }} />
              <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                <div style={{ display: "flex" }}>
                  {[["EL", "#364531"], ["JS", "#5A7050"], ["MA", "#7E9A6F"]].map(([t, bg], i) => (
                    <div key={t} style={{ width: 32, height: 32, borderRadius: "50%", background: bg, color: "#FFF", display: "flex", alignItems: "center", justifyContent: "center", font: "600 12px var(--font-ui)", border: "2px solid #FFF", marginLeft: i ? -8 : 0 }}>{t}</div>
                  ))}
                </div>
                <button onClick={() => setOpen(false)} aria-label="Stäng" style={{ background: "none", border: "none", cursor: "pointer", color: "#353535", fontSize: 22, lineHeight: 1, padding: 4 }}>×</button>
              </div>
            </div>
            <div style={{ margin: "36px 0 20px" }}>
              <div style={{ font: "600 26px var(--font-ui)", color: "#353535" }}>{settings.greeting}</div>
              <div style={{ font: "700 26px var(--font-ui)", color: "#353535" }}>{settings.greeting2}</div>
            </div>
            <div style={{ background: "#FFF", border: "1px solid var(--border-card)", borderRadius: 12, overflow: "hidden" }}>
              <ChatSearchBox value={query} onChange={setQuery} />
              <ChatSuggestionList query={query} onOpen={openArticle} />
            </div>
            <div className="chat-item" onClick={openMessages}
              style={{ background: "#FFF", border: "1px solid var(--border-card)", borderRadius: 12, padding: 16, marginTop: 16, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, cursor: "pointer", transition: "background 150ms ease" }}>
              <div>
                <div style={{ font: "700 14px var(--font-ui)", color: "#353535" }}>Skicka ett meddelande till oss</div>
                <div style={{ font: "400 13px var(--font-ui)", color: "var(--ink-500)", marginTop: 3 }}>{settings.replyEta}</div>
              </div>
              <Icon name="chevron-right" size={18} color="#364531" style={{ flex: "none" }} />
            </div>
          </div>
        )}

        {tab === "msgs" && (
          <>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "14px 16px", background: "#FFF", borderBottom: "1px solid var(--border-card)" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                {activeConv && convs.length > 1 && (
                  <button onClick={() => setActiveConv(null)} aria-label="Tillbaka" style={{ background: "none", border: "none", cursor: "pointer", color: "#364531", padding: 2, display: "flex" }}>
                    <Icon name="chevron-right" size={16} style={{ transform: "rotate(180deg)" }} />
                  </button>
                )}
                <div style={{ font: "700 15px var(--font-ui)", color: "#364531" }}>Recnote Support</div>
              </div>
              <button onClick={() => setOpen(false)} aria-label="Stäng" style={{ background: "none", border: "none", cursor: "pointer", color: "#353535", fontSize: 20, lineHeight: 1, padding: 4 }}>×</button>
            </div>
            {contactForm ? (
              <div style={{ flex: 1, overflowY: "auto", padding: 20 }}>
                <div style={{ background: "#FFF", border: "1px solid var(--border-card)", borderRadius: 12, padding: 18 }}>
                  <div style={{ font: "700 15px var(--font-ui)", color: "#353535", marginBottom: 4 }}>Innan vi börjar 👋</div>
                  <div style={{ font: "400 13px var(--font-ui)", color: "var(--ink-500)", lineHeight: 1.5, marginBottom: 14 }}>Ange ditt namn och din e-postadress så att vi kan återkomma till dig.</div>
                  <input value={contact.name} onChange={e => setContact(c => ({ ...c, name: e.target.value }))} placeholder="Ditt namn"
                    style={{ width: "100%", boxSizing: "border-box", border: "1px solid var(--border-card)", borderRadius: 10, padding: "0 12px", height: 42, font: "400 14px var(--font-ui)", color: "var(--ink-900)", outline: "none", marginBottom: 8 }} />
                  <input value={contact.email} onChange={e => setContact(c => ({ ...c, email: e.target.value }))} placeholder="E-postadress" type="email"
                    onKeyDown={e => { if (e.key === "Enter") startConversation(); }}
                    style={{ width: "100%", boxSizing: "border-box", border: "1px solid var(--border-card)", borderRadius: 10, padding: "0 12px", height: 42, font: "400 14px var(--font-ui)", color: "var(--ink-900)", outline: "none" }} />
                  {contactErr && <div style={{ font: "400 12px var(--font-ui)", color: "#B05B5B", marginTop: 8 }}>{contactErr}</div>}
                  <button onClick={startConversation}
                    style={{ width: "100%", background: "#364531", color: "#FFF", border: "none", borderRadius: 10, height: 42, font: "600 14px var(--font-ui)", cursor: "pointer", marginTop: 12 }}>
                    Starta chatt
                  </button>
                  {convs.length > 0 && (
                    <button onClick={() => setContactForm(false)}
                      style={{ width: "100%", background: "none", border: "none", color: "var(--ink-500)", font: "400 13px var(--font-ui)", cursor: "pointer", marginTop: 8 }}>
                      Avbryt
                    </button>
                  )}
                </div>
              </div>
            ) : activeConv
              ? <ChatThread conv={activeConv} settings={settings} onBack={() => setActiveConv(null)} />
              : (
                <div style={{ flex: 1, overflowY: "auto", padding: 16, display: "flex", flexDirection: "column", gap: 10 }}>
                  {convs.map(c => (
                    <div key={c.id} className="chat-item" onClick={() => setActiveConv(c)}
                      style={{ background: "#FFF", border: "1px solid var(--border-card)", borderRadius: 12, padding: "12px 14px", cursor: "pointer" }}>
                      <div style={{ font: "600 13px var(--font-ui)", color: "#353535", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                        {c.lastMessage ? c.lastMessage.text : "Ny konversation"}
                      </div>
                      <div style={{ font: "400 12px var(--font-ui)", color: "var(--ink-400)", marginTop: 3 }}>{timeAgo(c.lastMessageAt)}</div>
                    </div>
                  ))}
                  <button onClick={newConversation}
                    style={{ background: "#364531", color: "#FFF", border: "none", borderRadius: 12, height: 40, font: "600 14px var(--font-ui)", cursor: "pointer", marginTop: 4 }}>
                    Ny konversation
                  </button>
                </div>
              )}
          </>
        )}

        {tab === "help" && (
          <>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "14px 16px", background: "#FFF", borderBottom: "1px solid var(--border-card)" }}>
              <div style={{ font: "700 15px var(--font-ui)", color: "#364531" }}>Hjälp</div>
              <button onClick={() => setOpen(false)} aria-label="Stäng" style={{ background: "none", border: "none", cursor: "pointer", color: "#353535", fontSize: 20, lineHeight: 1, padding: 4 }}>×</button>
            </div>
            <div style={{ flex: 1, overflowY: "auto", padding: 16 }}>
              <div style={{ background: "#FFF", border: "1px solid var(--border-card)", borderRadius: 12, overflow: "hidden" }}>
                <ChatSearchBox value={query} onChange={setQuery} />
                <ChatSuggestionList query={query} onOpen={openArticle} />
              </div>
            </div>
          </>
        )}

        <div style={{ display: "flex", borderTop: "1px solid var(--border-card)", background: "#FFF" }}>
          <button onClick={() => setTab("hem")} style={tabBtn(tab === "hem")}>
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 10.5L12 3l9 7.5"></path><path d="M5 9.5V21h14V9.5"></path></svg>
            Hem
          </button>
          <button onClick={() => { setTab("msgs"); }} style={tabBtn(tab === "msgs")}>
            <Icon name="chat" size={20} />
            Meddelanden
          </button>
          <button onClick={() => setTab("help")} style={tabBtn(tab === "help")}>
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"></circle><path d="M9.5 9a2.5 2.5 0 0 1 4.9.8c0 1.6-2.4 2.2-2.4 3.4"></path><circle cx="12" cy="17" r="0.5" fill="currentColor"></circle></svg>
            Hjälp
          </button>
        </div>
      </div>
    )}
    <ChatLauncher onClick={() => setOpen(o => !o)} />
  </>;
}

// ---------- app ----------
function App() {
  const route = useHashRoute();
  const [q, setQ] = useState("");
  const [boot, setBoot] = useState(null);

  useEffect(() => { api("/api/bootstrap").then(setBoot).catch(() => {}); }, [route.s]);

  const setQnav = (v) => { setQ(v); if (route.s !== "home") nav("/"); };
  if (!boot) return null;
  const searching = route.s === "home" && q.trim().length > 0;

  return (
    <div style={{ minHeight: "100vh", background: "var(--surface-page)", color: "var(--text-body)" }}>
      <Hero big={route.s === "home"} q={q} setQ={setQnav} title={boot.settings.heroTitle} />
      {route.s === "home" && searching && <SearchResults q={q} />}
      {route.s === "home" && !searching && <HomeGrid collections={boot.collections} />}
      {route.s === "collection" && <CollectionPage id={route.id} />}
      {route.s === "article" && <ArticlePage id={route.id} />}
      <div className="wrap"><SiteFooter /></div>
      <ChatWidget settings={boot.settings} />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
