/* Collab features — Wiki + Voice notes + Threads + Reactions + Universal search */

/* ─── 32. Wiki interne markdown ───────────────────────────────────── */
const WIKI_SEED = [
  { id: "sop-rfq",     section: "Procédures · sourcing",   title: "Lancer une RFQ fournisseur",        author: "kevin",   updated: "il y a 3j",  emoji: "📋" },
  { id: "sop-qc",      section: "Procédures · sourcing",   title: "Contrôle qualité lot entrant",       author: "kevin",   updated: "il y a 1 sem.", emoji: "🔍" },
  { id: "sop-launch",  section: "Procédures · produits",   title: "Lancer un nouveau produit",          author: "carly",   updated: "il y a 2j",  emoji: "🚀" },
  { id: "sop-listing", section: "Procédures · produits",   title: "Optimiser un listing Amazon",         author: "carly",   updated: "il y a 5j",  emoji: "✨" },
  { id: "sop-recon",   section: "Procédures · finance",    title: "Réconciliation mensuelle CIBC",       author: "clarens", updated: "il y a 12h", emoji: "🏦" },
  { id: "sop-2fa",     section: "Procédures · sécurité",   title: "Récupération 2FA · procédure",         author: "clarens", updated: "il y a 1 mois", emoji: "🔐" },
  { id: "tpl-rfq",     section: "Templates",               title: "Template email RFQ (FR/EN)",          author: "kevin",   updated: "il y a 2 sem.", emoji: "📧" },
  { id: "tpl-launch",  section: "Templates",               title: "Checklist lancement 30 points",       author: "carly",   updated: "il y a 1 mois", emoji: "✅" },
];

const Wiki = () => {
  const toast = useToast();
  const LS_DOCS = "kcc:wiki-docs";
  const LS_CONTENT = "kcc:wiki-content";
  const loadLS = (k, fb) => { try { const v = localStorage.getItem(k); return v ? JSON.parse(v) : fb; } catch { return fb; } };
  const [docs, setDocsRaw] = useState(() => loadLS(LS_DOCS, WIKI_SEED));
  const [contents, setContentsRaw] = useState(() => loadLS(LS_CONTENT, {}));
  const [selectedDoc, setSelectedDoc] = useState(docs[0]?.id || "sop-rfq");
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState("");

  const setDocs = (updater) => {
    setDocsRaw((prev) => {
      const next = typeof updater === "function" ? updater(prev) : updater;
      try { localStorage.setItem(LS_DOCS, JSON.stringify(next)); } catch {}
      fetch("/api/sync", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ col: "wiki-docs", items: next }) }).catch(() => null);
      return next;
    });
  };
  const setContents = (updater) => {
    setContentsRaw((prev) => {
      const next = typeof updater === "function" ? updater(prev) : updater;
      try { localStorage.setItem(LS_CONTENT, JSON.stringify(next)); } catch {}
      fetch("/api/sync", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ col: "wiki-content", items: next }) }).catch(() => null);
      return next;
    });
  };
  const newDoc = () => {
    const title = prompt("Titre du nouveau document"); if (!title) return;
    const section = prompt("Section (ex: Procédures · sourcing)", "Procédures") || "Procédures";
    const id = "doc-" + Date.now().toString(36);
    setDocs((d) => [...d, { id, section, title, author: "clarens", updated: "à l'instant", emoji: "📄" }]);
    setContents((c) => ({ ...c, [id]: `## ${title}\n\nÀ rédiger…` }));
    setSelectedDoc(id);
    toast({ message: `Document « ${title} » créé`, tone: "green" });
  };
  const saveEdit = () => {
    setContents((c) => ({ ...c, [selectedDoc]: draft }));
    setDocs((d) => d.map((x) => x.id === selectedDoc ? { ...x, updated: "à l'instant", author: "clarens" } : x));
    setEditing(false);
    toast({ message: "Document sauvegardé", tone: "green" });
  };
  const grouped = docs.reduce((acc, d) => { (acc[d.section] = acc[d.section] || []).push(d); return acc; }, {});
  const doc = docs.find((d) => d.id === selectedDoc);

  const SEED_CONTENT = `
## ${doc?.title || ""}

**Quand utiliser** — chaque fois qu'on évalue un nouveau fournisseur et qu'on veut comparer des prix sur un produit candidat. Compte 2-3 jours de cycle complet entre la première relance et la réponse finale.

### Étapes

1. **Préparer le brief** dans la fiche produit (catégorie, MOQ visé, target price, échantillon requis).
2. **Identifier 3 à 5 fournisseurs** sur Alibaba ou par référencement direct.
3. **Envoyer la RFQ standardisée** depuis le template \`tpl-rfq\` — inclure :
   - Volumes annuels prévisionnels
   - Termes de paiement préférés (T/T 30/70 ou Net 30)
   - Incoterms (FOB ou EXW)
   - Délai de production cible
4. **Suivre les retours dans /opportunity** pendant 48-72h.
5. **Bénéficier de la grille de comparaison automatique** sur /supplier-cmp pour décider.

### Points d'attention

- Toujours mentionner que vous avez 3+ devis en cours · crée la pression saine
- Ne jamais accepter le premier prix · marge moyenne de négociation 8-15%
- Demander un échantillon dans le pricing initial · pas en option payante

### Liens

- [annuaire] · annuaire fournisseurs complet
- [calc] · ProfitCalcPro pour valider la cible price
- Template email : \`/wiki/tpl-rfq\`
`;
  const content = contents[selectedDoc] || SEED_CONTENT;

  // Tiny markdown render
  const md = content.split("\n").map((line, i) => {
    if (line.startsWith("## "))   return <h2 key={i} style={{ fontFamily: "var(--font-display)", fontSize: 26, fontWeight: 500, letterSpacing: "-0.02em", margin: "14px 0 8px" }}>{line.slice(3)}</h2>;
    if (line.startsWith("### "))  return <h3 key={i} style={{ fontSize: 14, fontWeight: 600, margin: "18px 0 6px", color: "var(--text)" }}>{line.slice(4)}</h3>;
    if (line.startsWith("- "))    return <div key={i} style={{ display: "flex", gap: 8, padding: "3px 0", fontSize: 13.5 }}><span style={{ color: "var(--accent)" }}>•</span><span dangerouslySetInnerHTML={{ __html: line.slice(2).replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/`([^`]+)`/g, '<code style="font-family:var(--font-mono);background:var(--bg-3);padding:1px 5px;border-radius:3px;font-size:11.5px;color:var(--accent)">$1</code>').replace(/\[([^\]]+)\]/g, '<span style="color:var(--accent);text-decoration:underline;cursor:pointer">[$1]</span>') }}/></div>;
    if (/^\d+\. /.test(line))     return <div key={i} style={{ display: "flex", gap: 8, padding: "5px 0", fontSize: 13.5 }}><span style={{ color: "var(--text-dim)", minWidth: 18, fontFamily: "var(--font-mono)" }}>{line.match(/^(\d+)\./)[1]}.</span><span dangerouslySetInnerHTML={{ __html: line.replace(/^\d+\. /, "").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/`([^`]+)`/g, '<code style="font-family:var(--font-mono);background:var(--bg-3);padding:1px 5px;border-radius:3px;font-size:11.5px;color:var(--accent)">$1</code>') }}/></div>;
    if (line.trim() === "") return <div key={i} style={{ height: 6 }}/>;
    return <p key={i} style={{ fontSize: 13.5, lineHeight: 1.65, color: "var(--text-muted)", margin: "6px 0" }} dangerouslySetInnerHTML={{ __html: line.replace(/\*\*(.+?)\*\*/g, "<strong style=\"color:var(--text)\">$1</strong>").replace(/`([^`]+)`/g, '<code style="font-family:var(--font-mono);background:var(--bg-3);padding:1px 5px;border-radius:3px;font-size:11.5px;color:var(--accent)">$1</code>').replace(/\[([^\]]+)\]/g, '<span style="color:var(--accent);text-decoration:underline;cursor:pointer">[$1]</span>') }}/>;
  });

  return (
    <div style={{ display: "grid", gridTemplateColumns: "280px 1fr", height: "100%" }}>
      <div style={{ borderRight: "1px solid var(--border-subtle)", overflow: "auto" }}>
        <div style={{ padding: "14px 16px", borderBottom: "1px solid var(--border-subtle)" }}>
          <div style={{ fontSize: 14, fontWeight: 600 }}>Wiki interne</div>
          <div style={{ fontSize: 11.5, color: "var(--text-dim)", marginTop: 2 }}>{docs.length} documents · markdown</div>
          <button className="btn" data-variant="primary" data-size="sm" style={{ width: "100%", marginTop: 10, justifyContent: "center" }} onClick={newDoc}><Icon name="plus" size={11}/> Nouveau document</button>
        </div>
        <div style={{ padding: "8px 4px" }}>
          {Object.entries(grouped).map(([sec, items]) => (
            <div key={sec} style={{ marginBottom: 10 }}>
              <div style={{ padding: "6px 10px 4px", fontSize: 10, color: "var(--text-faint)", textTransform: "uppercase", letterSpacing: ".08em", fontWeight: 500 }}>{sec}</div>
              {items.map((d) => (
                <div key={d.id} onClick={() => setSelectedDoc(d.id)} style={{
                  display: "flex", alignItems: "center", gap: 8,
                  padding: "6px 10px", margin: "1px 0", borderRadius: 6,
                  background: d.id === selectedDoc ? "var(--bg-3)" : "transparent",
                  cursor: "pointer", fontSize: 12.5,
                  color: d.id === selectedDoc ? "var(--text)" : "var(--text-muted)",
                  fontWeight: d.id === selectedDoc ? 600 : 450,
                }}>
                  <span style={{ fontSize: 14 }}>{d.emoji}</span>
                  <span style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{d.title}</span>
                </div>
              ))}
            </div>
          ))}
        </div>
      </div>

      <div style={{ overflow: "auto", padding: "20px 32px 40px", maxWidth: 820 }}>
        <div className="row" style={{ marginBottom: 16, gap: 10 }}>
          <span style={{ fontSize: 28 }}>{doc.emoji}</span>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 11, color: "var(--text-dim)" }}>{doc.section}</div>
            <div className="row" style={{ gap: 8, marginTop: 4, fontSize: 11.5, color: "var(--text-dim)" }}>
              <Avatar user={doc.author} size="sm"/>
              <span>Édité par <span style={{ color: "var(--text)" }}>{({clarens:"Clarens",kevin:"Kevin",carly:"Carly"})[doc.author]}</span></span>
              <span>·</span>
              <span>{doc.updated}</span>
            </div>
          </div>
          {editing ? (
            <>
              <button className="btn" data-size="sm" data-variant="primary" onClick={saveEdit}><Icon name="check" size={11}/> Sauvegarder</button>
              <button className="btn" data-size="sm" onClick={() => setEditing(false)}>Annuler</button>
            </>
          ) : (
            <>
              <button className="btn" data-size="sm" onClick={() => { setDraft(content); setEditing(true); }}><Icon name="edit" size={11}/> Éditer</button>
              <button className="btn" data-size="sm" onClick={() => { navigator.clipboard?.writeText(content); toast({ message: "Markdown copié dans le presse-papiers", tone: "green" }); }}><Icon name="copy" size={11}/> Partager</button>
            </>
          )}
        </div>
        {editing ? (
          <textarea value={draft} onChange={(e) => setDraft(e.target.value)}
            style={{ width: "100%", minHeight: 500, fontFamily: "var(--font-mono)", fontSize: 12.5, padding: 16, border: "1px solid var(--border-subtle)", borderRadius: 8, background: "var(--bg-1)", color: "var(--text)", outline: "none", resize: "vertical" }}/>
        ) : (
          <div>{md}</div>
        )}
      </div>
    </div>
  );
};

/* ─── 31, 29, 34. Voice notes + threads + reactions inside Messages preview ─ */
const ThreadsDemo = () => {
  const toast = useToast();
  const VOICE_TEXT = "Voici l'audio de la réunion avec Lin Mei. Elle accepte MOQ 175 si on s'engage sur Q3 et Q4. Je propose qu'on valide ensemble.";
  const [playing, setPlaying] = useState(false);
  const [reactions, setReactions] = useState({ "👍": 2, "🔥": 1, "🤔": 1 });
  const [mine, setMine] = useState({});
  const playVoice = () => {
    if (!("speechSynthesis" in window)) { toast({ message: "Synthèse vocale indisponible", tone: "amber" }); return; }
    if (playing) { window.speechSynthesis.cancel(); setPlaying(false); return; }
    const u = new SpeechSynthesisUtterance(VOICE_TEXT);
    u.lang = "fr-CA"; u.rate = 1.05;
    u.onend = () => setPlaying(false);
    u.onerror = () => setPlaying(false);
    window.speechSynthesis.cancel();
    window.speechSynthesis.speak(u);
    setPlaying(true);
  };
  const toggleReaction = (e) => {
    const has = mine[e];
    setReactions((r) => ({ ...r, [e]: Math.max(0, (r[e] || 0) + (has ? -1 : 1)) }));
    setMine((m) => ({ ...m, [e]: !has }));
  };
  const addReaction = () => {
    const e = (prompt("Emoji de réaction :", "🎉") || "").trim();
    if (!e) return;
    setReactions((r) => ({ ...r, [e]: (r[e] || 0) + 1 }));
    setMine((m) => ({ ...m, [e]: true }));
    toast({ message: `Réaction ${e} ajoutée`, tone: "green" });
  };
  return (
    <div className="page" style={{ maxWidth: 820 }}>
      <div className="page-head">
        <div>
          <div className="page-title">Threads, voice notes, réactions</div>
          <div className="page-sub">Aperçu des extensions Messages · disponibles depuis n'importe quel message</div>
        </div>
      </div>

      <div className="card" style={{ padding: 0 }}>
        {/* Parent message */}
        <div style={{ padding: 16, display: "flex", gap: 12 }}>
          <Avatar user="kevin"/>
          <div style={{ flex: 1 }}>
            <div className="row" style={{ gap: 8 }}>
              <span style={{ fontSize: 13, fontWeight: 600, color: "var(--user-kevin)" }}>Kevin</span>
              <span className="mono" style={{ fontSize: 11, color: "var(--text-faint)" }}>14:18</span>
            </div>
            <div style={{ fontSize: 13.5, marginTop: 4 }}>
              Voici l'audio de la réunion avec Lin Mei. Elle accepte MOQ 175 si on s'engage sur Q3 + Q4. Je propose qu'on valide ensemble.
            </div>

            {/* Voice note */}
            <div style={{ marginTop: 10, padding: 10, background: "var(--bg-2)", borderRadius: 10, display: "flex", alignItems: "center", gap: 10, maxWidth: 380 }}>
              <button onClick={playVoice} title={playing ? "Arrêter" : "Lire la note vocale"} className="icon-btn" style={{ width: 32, height: 32, background: "var(--accent)", color: "white", borderRadius: 999 }}>
                <Icon name={playing ? "pause" : "play"} size={13}/>
              </button>
              <div style={{ display: "flex", alignItems: "center", gap: 1.5, flex: 1, height: 22 }}>
                {Array.from({ length: 32 }, (_, i) => {
                  const h = 4 + Math.abs(Math.sin(i * 0.4)) * 16;
                  return <div key={i} style={{ flex: 1, height: h, background: i < 12 ? "var(--accent)" : "var(--bg-4)", borderRadius: 1 }}/>;
                })}
              </div>
              <span className="mono" style={{ fontSize: 10.5, color: "var(--text-faint)" }}>1:42</span>
            </div>

            {/* Reactions */}
            <div className="row" style={{ gap: 4, marginTop: 8 }}>
              {Object.entries(reactions).filter(([, n]) => n > 0).map(([e, n]) => (
                <button key={e} onClick={() => toggleReaction(e)} title={mine[e] ? "Retirer ma réaction" : "Réagir"} style={{
                  display: "inline-flex", alignItems: "center", gap: 4,
                  padding: "2px 8px", borderRadius: 999,
                  background: mine[e] ? "var(--accent-soft)" : "var(--bg-2)",
                  border: `1px solid ${mine[e] ? "var(--accent)" : "var(--border-subtle)"}`,
                  fontSize: 12, cursor: "pointer", color: "var(--text)",
                }}>
                  {e} <span className="mono" style={{ fontSize: 10.5, color: "var(--text-dim)" }}>{n}</span>
                </button>
              ))}
              <button onClick={addReaction} className="icon-btn" style={{ width: 22, height: 22 }} title="Ajouter une réaction">
                <Icon name="plus" size={11}/>
              </button>
            </div>

            {/* Thread */}
            <div style={{ marginTop: 12, borderLeft: "2px solid var(--accent)", paddingLeft: 14 }}>
              <div className="row" style={{ gap: 6, marginBottom: 8, fontSize: 11.5 }}>
                <Icon name="link" size={11} style={{ color: "var(--accent)" }}/>
                <span style={{ color: "var(--accent)", fontWeight: 500 }}>Fil de discussion · 2 réponses</span>
              </div>
              <div style={{ display: "flex", gap: 8, padding: "6px 0", fontSize: 12.5 }}>
                <Avatar user="carly" size="sm"/>
                <div>
                  <div className="row" style={{ gap: 6 }}><span style={{ fontSize: 11.5, fontWeight: 600, color: "var(--user-carly)" }}>Carly</span><span className="mono" style={{ fontSize: 10, color: "var(--text-faint)" }}>14:21</span></div>
                  <div style={{ marginTop: 2 }}>Si on commit sur Q3+Q4, je peux pousser le launch de la couverture pondérée à juin pour augmenter le volume.</div>
                </div>
              </div>
              <div style={{ display: "flex", gap: 8, padding: "6px 0", fontSize: 12.5 }}>
                <Avatar user="clarens" size="sm"/>
                <div>
                  <div className="row" style={{ gap: 6 }}><span style={{ fontSize: 11.5, fontWeight: 600, color: "var(--user-clarens)" }}>Clarens</span><span className="mono" style={{ fontSize: 10, color: "var(--text-faint)" }}>14:24</span></div>
                  <div style={{ marginTop: 2 }}>+1 pour MOQ 175. J'updaterai le cashflow projection après confirmation.</div>
                </div>
              </div>
              <input className="input" placeholder="Répondre au fil…" style={{ marginTop: 8 }}/>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

/* ─── 46. Universal search command palette extended ──────────────── */
const UniversalSearchDemo = () => {
  const [q, setQ] = useState("");
  // Lecture des données réelles depuis localStorage et globaux
  const loadLS = (k, fb) => { try { const v = localStorage.getItem(k); return v ? JSON.parse(v) : fb; } catch { return fb; } };
  const products  = loadLS("kcc:products", []);
  const suppliers = loadLS("kcc:suppliers", []);
  const tasks     = loadLS("kcc:tasks", []);
  const wikiDocs  = loadLS("kcc:wiki-docs", []);
  const wsPages   = loadLS("kcc:workspace-pages", []);

  const PAGE_INDEX = [
    { id: "dashboard", k: "Dashboard", sub: "Pilotage · KPIs temps réel", icon: "chart" },
    { id: "research", k: "Recherche de produits", sub: "Sourcing · grille filtrable", icon: "search" },
    { id: "asin", k: "Bibliothèque ASIN", sub: "Sourcing · inventaire ASIN", icon: "box" },
    { id: "opportunity", k: "OpportunityFinder", sub: "Sourcing · pipeline RFQ", icon: "target" },
    { id: "supplier", k: "Annuaire fournisseurs", sub: "Sourcing · fiche fournisseur", icon: "users" },
    { id: "supplier-cmp", k: "Comparatif fournisseurs", sub: "Sourcing · décision multi-critères", icon: "flask" },
    { id: "alerts", k: "Alertes sourcing", sub: "Sourcing · Keepa temps réel", icon: "bell" },
    { id: "inbox", k: "Inbox fournisseurs", sub: "Intelligence · classification email", icon: "mail" },
    { id: "restock", k: "Restock", sub: "Sourcing · recos de réapprovisionnement", icon: "refresh" },
    { id: "jarvis", k: "JARVIS", sub: "Intelligence · agent IA", icon: "jarvis" },
    { id: "self-improve", k: "Auto-amélioration", sub: "Intelligence · audits & suggestions", icon: "sparkles" },
    { id: "finance", k: "Finances", sub: "Finance & Ops · P&L", icon: "chart" },
    { id: "cashflow", k: "Cashflow 90 jours", sub: "Finance · projection", icon: "chart" },
    { id: "cibc-recon", k: "Réconciliation CIBC", sub: "Finance · matching transactions", icon: "dollar" },
    { id: "taxes", k: "Taxes QC/CA", sub: "Finance · GST/QST", icon: "receipt" },
    { id: "anomalies", k: "Anomalies", sub: "Finance · détection automatique", icon: "alert" },
    { id: "debts", k: "Dettes & paiements", sub: "Finance · comptes ouverts", icon: "dollar" },
    { id: "expenses", k: "Dépenses", sub: "Finance · catégorisation", icon: "receipt" },
    { id: "shipments", k: "Expéditions FBA", sub: "Ops · tracking", icon: "truck" },
    { id: "returns", k: "Retours", sub: "Ops · gestion retours", icon: "refresh" },
    { id: "prep", k: "Prep Center", sub: "Ops · étiquetage", icon: "cube" },
    { id: "calendar", k: "Calendrier", sub: "Système · équipe", icon: "calendar" },
    { id: "workshop", k: "Atelier SQL", sub: "Système · requêtes D1", icon: "wrench" },
    { id: "settings", k: "Paramètres & 2FA", sub: "Système · profil/équipe", icon: "shield" },
    { id: "wiki", k: "Wiki interne", sub: "Collab · SOPs/templates", icon: "book" },
    { id: "workspace", k: "Workspace", sub: "Collab · pages/blocs", icon: "book" },
  ];

  const norm = (s) => String(s || "").toLowerCase();
  const query = norm(q);
  const filter = (items, fields) => items.filter((it) => !query || fields.some((f) => norm(it[f]).includes(query)));

  const groups = [
    { name: "Pages", icon: "chart",  items: filter(PAGE_INDEX, ["k", "sub", "id"]).slice(0, 8).map(p => ({ icon: p.icon, k: p.k, sub: p.sub, nav: p.id })) },
    { name: "Produits", icon: "box", items: filter(products, ["title", "asin", "category", "supplier"]).slice(0, 6).map(p => ({ icon: "box", k: p.title || p.name || p.asin, sub: `${p.asin || "—"} · stock ${p.stock ?? "?"} · marge ${p.margin ?? "?"}%`, nav: "research" })) },
    { name: "Fournisseurs", icon: "users", items: filter(suppliers, ["name", "country", "category"]).slice(0, 6).map(s => ({ icon: "users", k: s.name, sub: `Score ${s.score ?? "?"} · ${s.country || ""} · ${s.products || 0} produits`, nav: "supplier" })) },
    { name: "Tâches", icon: "check", items: filter(tasks, ["title", "assignee"]).slice(0, 6).map(t => ({ icon: "check", k: t.title, sub: `${t.status || "todo"} · ${t.assignee || "—"}`, nav: "team-board" })) },
    { name: "Documents wiki", icon: "book", items: filter(wikiDocs, ["title", "section"]).slice(0, 6).map(d => ({ icon: "book", k: d.title, sub: `${d.section} · ${d.updated || ""}`, nav: "wiki" })) },
    { name: "Pages workspace", icon: "book", items: filter(wsPages, ["title"]).slice(0, 6).map(p => ({ icon: "book", k: p.title, sub: `Workspace · ${p.icon || ""}`, nav: "workspace" })) },
  ].filter(g => g.items.length);

  const total = groups.reduce((s, g) => s + g.items.length, 0);

  return (
    <div className="page" style={{ maxWidth: 720 }}>
      <div className="page-head">
        <div>
          <div className="page-title">Recherche universelle ⌘K</div>
          <div className="page-sub">{total} résultats sur produits, fournisseurs, tâches, wiki, workspace, pages</div>
        </div>
      </div>
      <div className="card" style={{ padding: 0, maxWidth: 580 }}>
        <div style={{ padding: "12px 14px", borderBottom: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 10 }}>
          <Icon name="search"/>
          <input autoFocus value={q} onChange={(e) => setQ(e.target.value)}
            style={{ flex: 1, background: "transparent", border: "none", outline: "none", fontSize: 14, color: "var(--text)" }}
            placeholder="Cherchez n'importe quoi…"/>
          {q && <button className="icon-btn" onClick={() => setQ("")} style={{ width: 22, height: 22 }}><Icon name="x" size={11}/></button>}
        </div>
        <div style={{ padding: 6, maxHeight: 480, overflow: "auto" }}>
          {groups.length === 0 && (
            <div style={{ padding: "30px 14px", textAlign: "center", color: "var(--text-dim)", fontSize: 12.5 }}>
              Aucun résultat pour « {q} »
            </div>
          )}
          {groups.map((g) => (
            <div key={g.name}>
              <div style={{ padding: "8px 12px 4px", fontSize: 10.5, color: "var(--text-faint)", textTransform: "uppercase", letterSpacing: ".08em", fontWeight: 500 }}>{g.name}</div>
              {g.items.map((it, i) => (
                <div key={i} onClick={() => it.nav && window.kccNavigate?.(it.nav)}
                  style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 12px", borderRadius: 6, cursor: "pointer", fontSize: 13 }}
                  onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-3)"}
                  onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
                  <Icon name={it.icon} size={14} style={{ color: "var(--accent)" }}/>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{it.k}</div>
                    <div className="mono" style={{ fontSize: 10.5, color: "var(--text-faint)", marginTop: 1 }}>{it.sub}</div>
                  </div>
                </div>
              ))}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

Object.assign(window, { Wiki, ThreadsDemo, UniversalSearchDemo });
