// =================================================================
// paywall-app.jsx — App shell for the Operator Dashboard.
//   Route-aware sidebar, hash routing, theme persistence, tweaks.
// =================================================================

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#5b5bf5",
  "density": "comfy",
  "theme": "light",
  "environment": "Production",
  "mode": "live"
}/*EDITMODE-END*/;

// ---- Theme persistence (mirrors the Helix shell) ----
const PW_THEME_KEY = "krafts.paywall.theme.v1";
const PW_ROLE_KEY  = "krafts.paywall.role.v1";
const FONT_STACKS = {
  "Geist": "'Geist', system-ui, sans-serif",
  "Inter": "'Inter', system-ui, sans-serif",
  "IBM Plex Sans": "'IBM Plex Sans', system-ui, sans-serif",
  "system": "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
};
function deriveAccentShades(hex) {
  const c = hex.replace("#", "");
  if (c.length !== 6) return { strong: hex, soft: "#eeefff" };
  const r = parseInt(c.slice(0, 2), 16), g = parseInt(c.slice(2, 4), 16), b = parseInt(c.slice(4, 6), 16);
  const strong = `#${Math.max(0, Math.round(r * .75)).toString(16).padStart(2, "0")}${Math.max(0, Math.round(g * .75)).toString(16).padStart(2, "0")}${Math.max(0, Math.round(b * .75)).toString(16).padStart(2, "0")}`;
  const soft = `#${Math.round(r + (255 - r) * .92).toString(16).padStart(2, "0")}${Math.round(g + (255 - g) * .92).toString(16).padStart(2, "0")}${Math.round(b + (255 - b) * .92).toString(16).padStart(2, "0")}`;
  return { strong, soft };
}
const loadStored = (k, def) => { try { const r = localStorage.getItem(k); return r ? { ...def, ...JSON.parse(r) } : def; } catch (e) { return def; } };
const saveStored = (k, v) => { try { localStorage.setItem(k, JSON.stringify(v)); } catch (e) {} };
function applyTheme(t) {
  const root = document.documentElement;
  const { strong, soft } = deriveAccentShades(t.accent);
  root.style.setProperty("--accent", t.accent);
  root.style.setProperty("--accent-strong", strong);
  root.style.setProperty("--accent-soft", soft);
  root.style.setProperty("--r-md", t.radius + "px");
  root.style.setProperty("--r-sm", Math.max(4, t.radius - 4) + "px");
  root.style.setProperty("--r-lg", (t.radius + 4) + "px");
  root.style.setProperty("--font", FONT_STACKS[t.font] || FONT_STACKS["Geist"]);
  document.body.dataset.density = t.density;
  document.body.dataset.theme = t.theme;
  document.body.dataset.sidebar = t.sidebar || "rail";
}

const ICON_MAP = {
  IconChart, IconReceipt, IconList, IconUsers, IconCoin, IconGift, IconTag,
  IconAd, IconSliders, IconGauge, IconRocket, IconStore, IconTicket, IconBuilding, IconActivity,
  IconDownload, IconUpload,
};

const DEFAULT_ROUTE = { publisher: "overview", operator: "op-overview", advertiser: "advertiser-login" };
const OPERATOR_ROUTES = new Set(["op-overview", "saas-plans", "brands", "ad-creatives", "ad-campaigns", "discount-templates", "publisher-config"]);
const PUBLISHER_ROUTES = new Set(["overview", "analytics", "my-plan", "plans", "subscribers", "integration-kits", "engagement-rules", "coins", "coupon-offers", "brand-codes", "recommendations", "ad-detail", "ad-tiers", "ad-defaults", "ad-placements", "ad-debugger"]);
const ADVERTISER_ROUTES = new Set(["advertiser-login", "advertiser-ads", "advertiser-ad-detail", "advertiser-campaign", "advertiser-bulk"]);
const roleForRoute = (route, fallback = "publisher") => OPERATOR_ROUTES.has(route) ? "operator" : ADVERTISER_ROUTES.has(route) ? "advertiser" : PUBLISHER_ROUTES.has(route) ? "publisher" : fallback;

// =================================================================
function App() {
  const cfg = window.PAYWALL_CONFIG;
  const [data, setData] = useBoundStore(window.PAYWALL_DATA);
  const { session, remainingMs, signOut, extend } = useSession();
  const [connOpen, setConnOpen] = React.useState(false);

  const initialHash = parseHash().route;
  const [role, setRoleState] = React.useState(() => roleForRoute(initialHash, loadStored(PW_ROLE_KEY, { role: cfg.defaultTheme && "publisher" }).role || "publisher"));
  const [route, routeParam, setHashRoute] = useHashRoute(DEFAULT_ROUTE[role] || cfg.initialRoute);
  const setRoute = React.useCallback((r, p) => setHashRoute(r, p), [setHashRoute]);
  const [drawerOpen, setDrawerOpen] = React.useState(false);
  const [paletteOpen, setPaletteOpen] = React.useState(false);
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  const [theme, setThemeState] = React.useState(() => loadStored(PW_THEME_KEY, cfg.defaultTheme));
  const setTheme = (patch) => setThemeState(prev => { const next = { ...prev, ...patch }; saveStored(PW_THEME_KEY, next); return next; });
  React.useEffect(() => { applyTheme(theme); }, [theme]);
  React.useEffect(() => { setTheme({ accent: tweaks.accent, density: tweaks.density, theme: tweaks.theme }); /* eslint-disable-next-line */ }, [tweaks.accent, tweaks.density, tweaks.theme]);

  const [environment, setEnvironment] = React.useState(cfg.defaultEnvironment);
  React.useEffect(() => { if (tweaks.environment) setEnvironment(tweaks.environment); }, [tweaks.environment]);
  // Drive the data layer from the env/mode tweaks → re-bootstrap when they change.
  React.useEffect(() => {
    const c = window.__api.getConfig();
    if (tweaks.environment && tweaks.environment !== c.environment) window.__api.setConfig({ environment: tweaks.environment });
  }, [tweaks.environment]);
  React.useEffect(() => {
    const c = window.__api.getConfig();
    if (tweaks.mode && tweaks.mode !== c.mode) window.__api.setConfig({ mode: tweaks.mode });
  }, [tweaks.mode]);

  // Expose the acting role to the client (sets X-Acting-Role on live calls).
  React.useEffect(() => { window.__actingRole = role; }, [role]);
  React.useEffect(() => {
    const nextRole = roleForRoute(route, role);
    if (nextRole !== role) {
      setRoleState(nextRole);
      saveStored(PW_ROLE_KEY, { role: nextRole });
    }
  }, [route, role]);

  // Bootstrap collections once a session exists (mock = no-op seed, live = fetch).
  React.useEffect(() => { if (session) window.__api.bootstrap(); }, [session && session.token]);

  const setRole = React.useCallback((r) => {
    setRoleState(r); saveStored(PW_ROLE_KEY, { role: r });
    setRoute(DEFAULT_ROUTE[r]); setDrawerOpen(false);
  }, [setRoute]);
  React.useEffect(() => {
    window.__nav = (r, p) => { setRoute(r, p); setDrawerOpen(false); };
    window.__openPalette = () => setPaletteOpen(true);
    window.__setRole = setRole;
  }, [setRoute, setRole]);

  React.useEffect(() => {
    const onKey = (e) => { if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") { e.preventDefault(); setPaletteOpen(o => !o); } };
    window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey);
  }, []);
  React.useEffect(() => { setDrawerOpen(false); }, [route]);

  const nav = role === "publisher" ? cfg.navPublisher : role === "advertiser" ? cfg.navAdvertiser : cfg.navOperator;

  const screen = (() => {
    switch (route) {
      // Publisher
      case "overview":      return <OverviewScreen data={data} setData={setData}/>;
      case "analytics":     return <AnalyticsScreen data={data} setData={setData}/>;
      case "my-plan":       return <MyPlanScreen data={data} setData={setData}/>;
      case "plans":         return <ConsumerPlansScreen data={data} setData={setData}/>;
      case "subscribers":   return <SubscribersScreen data={data} setData={setData}/>;
      case "integration-kits": return <IntegrationKitsScreen data={data} setData={setData}/>;
      case "engagement-rules": return <EngagementRulesScreen data={data} setData={setData}/>;
      case "coins":         return <CoinsScreen data={data} setData={setData}/>;
      case "coupon-offers": return <CouponOffersScreen data={data} setData={setData}/>;
      case "brand-codes":   return <BrandCodesScreen data={data} setData={setData}/>;
      case "ad-tiers":      return <AdTiersScreen data={data} setData={setData}/>;
      case "ad-defaults":   return <AdDefaultsScreen data={data} setData={setData}/>;
      case "recommendations": return <AdPlacementsScreen data={data} setData={setData}/>;
      case "ad-detail": return <AdDetailScreen data={data} setData={setData} campaignId={routeParam} mode="publisher"/>;
      case "ad-placements": return <AdPlacementsScreen data={data} setData={setData}/>;
      case "ad-debugger":   return <AdDebuggerScreen data={data} setData={setData}/>;
      // Operator
      case "op-overview":         return <OpOverviewScreen data={data} setData={setData}/>;
      case "saas-plans":          return <SaasPlansScreen data={data} setData={setData}/>;
      case "brands":              return <BrandsScreen data={data} setData={setData}/>;
      case "ad-creatives":        return <AdCreativesScreen data={data} setData={setData}/>;
      case "ad-campaigns":        return <AdCampaignsScreen data={data} setData={setData}/>;
      case "discount-templates":  return <DiscountTemplatesScreen data={data} setData={setData}/>;
      case "publisher-config":    return <PublisherConfigScreen data={data} setData={setData}/>;
      // Advertiser
      case "advertiser-login":    return <AdvertiserLoginScreen data={data} setData={setData}/>;
      case "advertiser-ads":      return <AdvertiserAdsScreen data={data} setData={setData}/>;
      case "advertiser-ad-detail": return <AdDetailScreen data={data} setData={setData} campaignId={routeParam} mode="advertiser"/>;
      case "advertiser-campaign": return <AdvertiserCampaignScreen data={data} setData={setData}/>;
      case "advertiser-bulk":     return <AdvertiserBulkUploadScreen data={data} setData={setData}/>;
      default:                    return <OverviewScreen data={data} setData={setData}/>;
    }
  })();

  // Breadcrumbs
  const findItem = (id) => { for (const g of nav) { const it = g.items.find(i => i.id === id); if (it) return { item: it, group: g.group }; } return null; };
  const found = findItem(route);
  const roleLabel = cfg.roles.find(r => r.id === role)?.label || "";
  const crumbs = found ? [{ label: roleLabel }, { label: found.group }, { label: found.item.label }] : [{ label: roleLabel }];

  return (
    <div className="hx-app">
      <TopBar cfg={cfg} role={role} setRole={setRole} environment={environment}
        onMenuClick={() => setDrawerOpen(o => !o)} drawerOpen={drawerOpen}
        openPalette={() => setPaletteOpen(true)} openConn={() => setConnOpen(true)}
        session={session} remainingMs={remainingMs} signOut={signOut} extend={extend}/>

      <div className="hx-shell" data-shell="with-sidebar">
        <Sidebar cfg={cfg} nav={nav} role={role} route={route} environment={environment}
          onNav={(r) => { setRoute(r); setDrawerOpen(false); }} drawerOpen={drawerOpen} onClose={() => setDrawerOpen(false)}/>
        <main className="hx-main" data-screen-label={`${roleLabel} / ${found?.item.label || route}`}>
          <div className="hx-main-inner">
            {crumbs.length > 1 && <Crumbs items={crumbs} onClick={(it) => it.route && setRoute(it.route)}/>}
            <ErrorBoundary key={route}>{screen}</ErrorBoundary>
          </div>
        </main>
      </div>

      <ToastHost/>
      <CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} nav={nav}/>
      <ConnectionModal open={connOpen} onClose={() => setConnOpen(false)}/>

      <TweaksPanel title="Tweaks">
        <TweakSection title="Connection">
          <TweakRadio label="Data source" value={tweaks.mode} onChange={(v) => setTweak("mode", v)} options={[{ label: "Mock", value: "mock" }, { label: "Live", value: "live" }]}/>
          <TweakSelect label="Environment" value={tweaks.environment} onChange={(v) => setTweak("environment", v)} options={cfg.environments.map(e => ({ label: e, value: e }))}/>
          <TweakButton label="Connection settings…" onClick={() => setConnOpen(true)}/>
        </TweakSection>
        <TweakSection title="Theme">
          <TweakRadio label="Mode" value={tweaks.theme} onChange={(v) => setTweak("theme", v)} options={[{ label: "Light", value: "light" }, { label: "Dark", value: "dark" }]}/>
          <TweakColor label="Accent" value={tweaks.accent} onChange={(v) => setTweak("accent", v)} options={["#5b5bf5", "#0fb67e", "#1d4ed8", "#7c3aed", "#e55a2b", "#0b0d12"]}/>
          <TweakSelect label="Density" value={tweaks.density} onChange={(v) => setTweak("density", v)} options={[{ label: "Compact", value: "compact" }, { label: "Comfortable", value: "comfy" }, { label: "Airy", value: "airy" }]}/>
        </TweakSection>
        <TweakSection title="Jump to">
          <TweakButton label="Ad Tiers (showpiece)" onClick={() => setRoute("ad-tiers")}/>
          <TweakButton label="Policy Debugger" onClick={() => setRoute("ad-debugger")}/>
          <TweakButton label="Operator · Discount Codes" onClick={() => setRoute("discount-templates")}/>
        </TweakSection>
      </TweaksPanel>

      <PaywallStyles/>
    </div>
  );
}

// =================================================================
// Top bar
// =================================================================
const ENV_TONE = { Production: "var(--good)", Staging: "var(--warn)", Local: "var(--muted-2)" };

const TopBar = ({ cfg, role, environment, onMenuClick, drawerOpen, openPalette, openConn, session, remainingMs, signOut, extend }) => (
  <header className="hx-topnav">
    <div className="hx-topnav-left">
      <button className="hx-hamburger" onClick={onMenuClick} aria-label="Toggle menu" aria-expanded={drawerOpen}><IconMenu size={18}/></button>
      <a className="hx-brand" href="#" onClick={(e) => e.preventDefault()}>
        <span className="pw-logo"><IconCoin size={18}/></span>
        <span className="hx-brand-name">{cfg.brand.name}<span className="hx-brand-dot">{cfg.brand.suffix}</span></span>
      </a>
      <ConnectionBadge onClick={openConn}/>
    </div>

    <div className="hx-topnav-right">
      <Tooltip side="bottom" content={<>Search <kbd className="hx-kbd">⌘K</kbd></>}>
        <button className="hx-tn-icon" aria-label="Search" onClick={openPalette}><IconSearch size={16}/></button>
      </Tooltip>
      <PwNotifications/>
      <PwAvatar cfg={cfg} session={session} remainingMs={remainingMs} signOut={signOut} extend={extend} openConn={openConn}/>
    </div>
  </header>
);

const PwNotifications = () => {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef();
  React.useEffect(() => { if (!open) return; const f = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener("click", f); return () => document.removeEventListener("click", f); }, [open]);
  const items = [
    { icon: IconGift, title: "Coupon revealed", body: "Brew & Bean 30% · 250 coins", at: "21 min ago", unread: true },
    { icon: IconUsers, title: "New subscriber", body: "fatima.a@gmail.com · Monthly", at: "8 min ago", unread: true },
    { icon: IconReceipt, title: "Plan renewed", body: "Growth · $49.00 · Stripe", at: "Yesterday", unread: false },
  ];
  const unread = items.filter(i => i.unread).length;
  return (
    <div className="hx-dd" ref={ref}>
      <button className="hx-tn-icon" aria-label="Notifications" onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}>
        <IconBell size={16}/>{unread > 0 && <span className="hx-dot"/>}
      </button>
      {open && (
        <div className="hx-dd-menu hx-notif-menu" onClick={e => e.stopPropagation()}>
          <div className="hx-dd-head"><span style={{ fontWeight: 600, fontSize: 14 }}>Notifications</span></div>
          <div className="hx-notif-list">
            {items.map((n, i) => { const I = n.icon; return (
              <div key={i} className={`hx-notif-row ${n.unread ? "unread" : ""}`}>
                <span className="hx-notif-icon"><I size={14}/></span>
                <span className="hx-notif-meta"><span className="hx-notif-title">{n.title}</span><span className="hx-notif-body">{n.body}</span><span className="hx-notif-time">{n.at}</span></span>
              </div>); })}
          </div>
        </div>
      )}
    </div>
  );
};

const fmtRemaining = (ms) => {
  const s = Math.max(0, Math.round(ms / 1000));
  const m = Math.floor(s / 60), sec = s % 60;
  return `${m}:${String(sec).padStart(2, "0")}`;
};

const PwAvatar = ({ cfg, session, remainingMs, signOut, extend, openConn }) => {
  const [open, setOpen] = React.useState(false);
  const [, tick] = React.useReducer(x => x + 1, 0);
  const ref = React.useRef();
  React.useEffect(() => { if (!open) return; const f = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener("click", f); return () => document.removeEventListener("click", f); }, [open]);
  React.useEffect(() => { if (!open) return; const i = setInterval(tick, 1000); return () => clearInterval(i); }, [open]);
  const user = session?.user || cfg.operator;
  const remain = remainingMs ? remainingMs() : 0;
  const low = remain > 0 && remain < 5 * 60000;
  return (
    <div className="hx-dd" ref={ref}>
      <button className="hx-avatar-btn" aria-label="Account" onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}><Avatar name={user.name} size={30}/></button>
      {open && (
        <div className="hx-dd-menu hx-avatar-menu" onClick={e => e.stopPropagation()}>
          <div className="hx-dd-user">
            <Avatar name={user.name} size={40}/>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontWeight: 600, fontSize: 14 }}>{user.name}</div>
              <div style={{ color: "var(--muted)", fontSize: 12, overflow: "hidden", textOverflow: "ellipsis" }}>{user.email}</div>
            </div>
          </div>
          <div className="hx-dd-sep"/>
          <div className="pw-session-row">
            <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontSize: 12.5, color: low ? "var(--warn)" : "var(--muted)" }}>
              <IconClock size={13}/>Session {fmtRemaining(remain)}
            </span>
            <button className="pw-session-extend" onClick={() => { extend && extend(); }}>Extend</button>
          </div>
          <div className="hx-dd-sep"/>
          <button className="hx-dd-item" onClick={() => { setOpen(false); openConn && openConn(); }}><IconServer size={14}/>Connection<span style={{ marginLeft: "auto", fontSize: 11, color: "var(--muted)" }}>{window.__api.getConfig().live ? "Live" : "Mock"}</span></button>
          <button className="hx-dd-item" onClick={() => { setOpen(false); window.__openPalette(); }}><IconCommand size={14}/>Command palette<span className="hx-kbd" style={{ marginLeft: "auto" }}>⌘K</span></button>
          <div className="hx-dd-sep"/>
          <button className="hx-dd-item danger" onClick={() => { setOpen(false); signOut && signOut("manual"); }}><IconLogout size={14}/>Sign out</button>
        </div>
      )}
    </div>
  );
};

// =================================================================
// Sidebar
// =================================================================
const Sidebar = ({ cfg, nav, role, route, environment, onNav, drawerOpen, onClose }) => {
  const ctx = role === "publisher" ? cfg.publisherContext.name : "All publishers";
  return (
    <>
      {drawerOpen && <div className="hx-drawer-backdrop" onClick={onClose}/>}
      <aside className={`hx-sidebar ${drawerOpen ? "hx-sidebar-open" : ""}`}>
        <div className="hx-sidebar-close-row"><button className="hx-sidebar-close" onClick={onClose} aria-label="Close menu"><IconClose size={16}/></button></div>
        <div className="pw-ctx">
          <span className="pw-ctx-icon">{role === "publisher" ? <IconBuilding size={16}/> : <IconStore size={16}/>}</span>
          <div style={{ minWidth: 0 }}>
            <div className="pw-ctx-label">{role === "publisher" ? "Publisher" : "Platform"}</div>
            <div className="pw-ctx-name">{ctx}</div>
          </div>
        </div>
        {nav.map(g => (
          <div className="hx-side-group" key={g.group}>
            <div className="hx-side-label">{g.group}</div>
            <nav className="hx-side-items">
              {g.items.map(it => {
                const IconC = ICON_MAP[it.icon] || IconList;
                return (
                  <button key={it.id} className={`hx-side-item ${it.id === route ? "on" : ""}`} onClick={() => onNav(it.id)}>
                    <IconC size={15}/><span>{it.label}</span>
                  </button>
                );
              })}
            </nav>
          </div>
        ))}
      </aside>
    </>
  );
};

// =================================================================
// Command palette
// =================================================================
const CommandPalette = ({ open, onClose, nav }) => {
  const [q, setQ] = React.useState("");
  const [active, setActive] = React.useState(0);
  const inputRef = React.useRef();
  React.useEffect(() => { if (open) { setQ(""); setActive(0); setTimeout(() => inputRef.current?.focus(), 30); } }, [open]);
  const items = React.useMemo(() => {
    const out = [];
    nav.forEach(g => g.items.forEach(it => out.push({ id: it.id, label: it.label, group: g.group, icon: ICON_MAP[it.icon] || IconList, action: () => window.__nav(it.id) })));
    return out;
  }, [nav]);
  const filtered = q.trim() === "" ? items.slice(0, 12) : items.filter(i => i.label.toLowerCase().includes(q.toLowerCase())).slice(0, 14);
  React.useEffect(() => { setActive(0); }, [q]);
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      if (e.key === "ArrowDown") { e.preventDefault(); setActive(a => Math.min(filtered.length - 1, a + 1)); }
      if (e.key === "ArrowUp") { e.preventDefault(); setActive(a => Math.max(0, a - 1)); }
      if (e.key === "Enter") { e.preventDefault(); const it = filtered[active]; if (it) { it.action(); onClose(); } }
    };
    window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey);
  }, [open, filtered, active, onClose]);
  if (!open) return null;
  const grouped = filtered.reduce((acc, it) => { (acc[it.group] = acc[it.group] || []).push(it); return acc; }, {});
  let cursor = 0;
  return (
    <div className="hx-pal-overlay" onClick={onClose}>
      <div className="hx-pal" onClick={e => e.stopPropagation()}>
        <div className="hx-pal-input"><IconSearch size={16}/><input ref={inputRef} value={q} onChange={e => setQ(e.target.value)} placeholder="Search screens and actions…"/><kbd className="hx-kbd">esc</kbd></div>
        <div className="hx-pal-list">
          {filtered.length === 0 ? <div className="hx-pal-empty">No results for "{q}"</div> :
            Object.entries(grouped).map(([group, list]) => (
              <div key={group} className="hx-pal-group">
                <div className="hx-pal-group-label">{group}</div>
                {list.map(it => { const idx = cursor++; const I = it.icon; return (
                  <button key={it.id} className={`hx-pal-item ${idx === active ? "on" : ""}`} onMouseEnter={() => setActive(idx)} onClick={() => { it.action(); onClose(); }}>
                    <span className="hx-pal-icon"><I size={14}/></span><span className="hx-pal-label">{it.label}</span><IconChevR size={12} className="hx-pal-chev"/>
                  </button>); })}
              </div>
            ))}
        </div>
      </div>
      <style>{`
        .hx-pal-overlay { position: fixed; inset: 0; background: rgba(13,17,28,.45); z-index: 95; display: flex; align-items: flex-start; justify-content: center; padding: 80px 16px 16px; animation: hxfade .12s ease both; }
        .hx-pal { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow-modal); width: 100%; max-width: 580px; display: flex; flex-direction: column; overflow: hidden; animation: hxpop .14s cubic-bezier(.2,.9,.3,1.2) both; }
        .hx-pal-input { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line-2); color: var(--muted); }
        .hx-pal-input input { flex: 1; border: none; outline: none; background: transparent; font: inherit; font-size: 15px; color: var(--ink); }
        .hx-pal-list { overflow-y: auto; padding: 6px; max-height: 50vh; }
        .hx-pal-empty { padding: 40px 16px; text-align: center; color: var(--muted); font-size: 13.5px; }
        .hx-pal-group-label { padding: 6px 10px 4px; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 600; }
        .hx-pal-item { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; padding: 9px 10px; width: 100%; background: transparent; border: none; cursor: pointer; border-radius: 8px; font: inherit; text-align: left; color: var(--ink); }
        .hx-pal-item.on { background: var(--hover); }
        .hx-pal-icon { color: var(--muted); display: inline-flex; }
        .hx-pal-item.on .hx-pal-icon { color: var(--accent); }
        .hx-pal-label { font-size: 13.5px; }
        .hx-pal-chev { color: var(--muted-2); }
      `}</style>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("app")).render(<ErrorBoundary><SessionGate><App/></SessionGate></ErrorBoundary>);
