// app.jsx — App shell + router + tweaks
const { useState, useEffect, useMemo, useCallback, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "light",
  "accent": "sodium",
  "density": "regular",
  "heading": "display",
  "navStyle": "rail",
  "showGrid": false,
  "heroVariant": "editorial",
  "firstName": "Paul",
  "greetIndex": -1,
  "territoryPicker": "chips",
  "territoryGranularity": "tis",
  "fxMode": "wallets",
  "reportingCcy": "USD",
  "conflictStrictness": "warn",
  "showTerritoryMap": true
} /*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [route, setRoute] = useState({ name: 'dashboard', payload: null });
  const [paletteOpen, setPaletteOpen] = useState(false);
  const [auth, setAuth] = useState(() => window.AstroAuth?.state || { ready: false, signedIn: false });

  // Hydrate from localStorage once on mount (so Settings/header changes survive reload)
  useEffect(() => {
    try {
      const ls = (k) => localStorage.getItem('astro_' + k);
      const next = {};
      ['theme', 'accent', 'density', 'heading'].forEach((k) => {const v = ls(k);if (v) next[k] = v;});
      Object.entries(next).forEach(([k, v]) => setTweak(k, v));
    } catch {}
    // eslint-disable-next-line
  }, []);

  // Apply theme tokens to root — supports auto via prefers-color-scheme
  useEffect(() => {
    const r = document.documentElement;
    const apply = () => {
      const resolved = t.theme === 'auto' ?
      window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' :
      t.theme;
      r.dataset.theme = resolved;
    };
    apply();
    r.dataset.accent = t.accent;
    r.dataset.density = t.density;
    r.dataset.heading = t.heading;

    // Live updates from Settings page / header toggle
    const onPrefs = (e) => {
      const d = e.detail || {};
      Object.entries(d).forEach(([k, v]) => setTweak(k, v));
    };
    window.addEventListener('astro-prefs', onPrefs);

    if (t.theme === 'auto') {
      const mq = window.matchMedia('(prefers-color-scheme: dark)');
      mq.addEventListener('change', apply);
      return () => {mq.removeEventListener('change', apply);window.removeEventListener('astro-prefs', onPrefs);};
    }
    return () => window.removeEventListener('astro-prefs', onPrefs);
  }, [t]);

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

  // Body-scroll lock when any modal/drawer overlay is open.
  // Detection: any element in the DOM with computed position:fixed AND
  // (inset:0 backdrop OR z-index >= 50) — covers every modal pattern in this app
  // without each modal having to opt in. Counts overlays on every mutation; locks
  // <body> overflow + preserves scrollbar gutter while ≥1 overlay is mounted.
  useEffect(() => {
    let prevOverflow = '';
    let prevPaddingRight = '';
    let locked = false;
    const lock = () => {
      if (locked) return;
      const sbw = window.innerWidth - document.documentElement.clientWidth;
      prevOverflow = document.body.style.overflow;
      prevPaddingRight = document.body.style.paddingRight;
      document.body.style.overflow = 'hidden';
      if (sbw > 0) document.body.style.paddingRight = `${sbw}px`;
      locked = true;
    };
    const unlock = () => {
      if (!locked) return;
      document.body.style.overflow = prevOverflow;
      document.body.style.paddingRight = prevPaddingRight;
      locked = false;
    };
    const isOverlay = (el) => {
      if (!(el instanceof HTMLElement)) return false;
      const cs = getComputedStyle(el);
      if (cs.position !== 'fixed') return false;
      // Treat as overlay if it's a fullscreen backdrop OR has dialog-level z-index.
      const insetFull = cs.inset === '0px' || (cs.top === '0px' && cs.left === '0px' && cs.right === '0px' && cs.bottom === '0px');
      const z = parseInt(cs.zIndex, 10);
      const highZ = !isNaN(z) && z >= 50;
      // Skip the always-mounted toolbar/HUD chrome by requiring either backdrop bg OR aria-modal.
      if (insetFull) {
        const bg = cs.backgroundColor || '';
        const hasBg = bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent';
        if (hasBg) return true;
        if (el.getAttribute('role') === 'dialog' || el.getAttribute('aria-modal') === 'true') return true;
      }
      // Side drawers / centered dialogs without a fullscreen wrapper.
      if (highZ && (el.getAttribute('role') === 'dialog' || el.tagName === 'ASIDE')) return true;
      return false;
    };
    const scan = () => {
      // Look at every element with a `style="position: fixed"` inline style — fast filter.
      const candidates = document.querySelectorAll('[style*="fixed"], [role="dialog"], aside');
      for (const el of candidates) {
        if (isOverlay(el)) { lock(); return; }
      }
      unlock();
    };
    const obs = new MutationObserver(scan);
    obs.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class', 'role', 'aria-modal'] });
    scan();
    return () => { obs.disconnect(); unlock(); };
  }, []);

  // Open an artist profile from anywhere (writer typeahead, etc.)
  useEffect(() => {
    const onOpenArtist = (e) => {
      const p = e.detail?.profile || (window.ARTISTS || []).find((a) => a.id === e.detail?.id);
      if (p) setRoute({ name: 'public', payload: p });
    };
    window.addEventListener('astro-open-artist', onOpenArtist);
    return () => window.removeEventListener('astro-open-artist', onOpenArtist);
  }, []);

  // Deep-link via query string — used by typeahead "↗" buttons that open in a new tab
  // so in-progress work in the originating tab isn't lost. `aid` is the ASTRO ID
  // (canonical UUID) used by every entity type in the database — same column name,
  // not "artist id". We disambiguate which table to look in by also passing `kind`.
  //   ?aid=<uuid>&kind=writer     → route to public artist profile
  //   ?aid=<uuid>&kind=publisher  → fire astro-open-publisher (drawer)
  // Backwards-compat: bare ?aid=<uuid> tries writers first, then publishers.
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const aid = params.get('aid');
    const kind = params.get('kind');
    if (aid) {
      const inWriters = window.findProfileByUuid(window.ARTISTS || [], aid);
      const inPublishers = window.findProfileByUuid(window.__PUBLISHERS || [], aid);
      if ((kind === 'writer' || !kind) && inWriters) {
        setRoute({ name: 'public', payload: inWriters });
      } else if ((kind === 'publisher' || !kind) && inPublishers) {
        setTimeout(() => window.dispatchEvent(new CustomEvent('astro-open-publisher', { detail: { id: inPublishers.id } })), 0);
      }
      // Clean the URL so refreshes don't keep re-firing
      const url = new URL(window.location.href);
      url.searchParams.delete('aid');
      url.searchParams.delete('kind');
      window.history.replaceState({}, '', url.toString());
    }
  }, []);

  const go = useCallback((name, payload = null) => {
    setRoute({ name, payload });
    setPaletteOpen(false);
    window.scrollTo({ top: 0, behavior: 'instant' });  window.dispatchEvent(new CustomEvent('astro-route', { detail: { name, payload } }));
  }, []);

  // Expose `go` globally so deep components (SocietyLink etc.) can navigate without prop drilling
  useEffect(() => { window.__astroGo = go; }, [go]);

  useEffect(() => {
    const onAuth = (e) => setAuth(e.detail || { ready: false, signedIn: false });
    window.addEventListener('astro-auth', onAuth);
    if (window.AstroAuth?.state) setAuth({ ...window.AstroAuth.state });
    return () => window.removeEventListener('astro-auth', onAuth);
  }, []);

  const publicRoutes = new Set(['public']);

  if (!auth.signedIn && publicRoutes.has(route.name)) {
    return <PublicRouteShell route={route} go={go} auth={auth} />;
  }

  if (!auth.signedIn) {
    return <SignedOutGate auth={auth} />;
  }

  return (
    <div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column', background: 'var(--bg)',
      backgroundImage: t.showGrid ? 'linear-gradient(var(--grid) 1px,transparent 1px),linear-gradient(90deg,var(--grid) 1px,transparent 1px)' : 'none',
      backgroundSize: '24px 24px' }}>

      <Header go={go} route={route.name} openPalette={() => setPaletteOpen(true)} />

      <Ticker />

      <div data-shell-grid style={{ flex: 1, paddingLeft: t.navStyle === 'rail' ? 64 : 0, paddingBottom: 56 }}>
        {t.navStyle === 'rail' && <Rail go={go} route={route.name} />}
        <main style={{ minWidth: 0, padding: '32px 40px 88px', maxWidth: 1500, width: '100%', margin: '0 auto', boxSizing: 'border-box' }}>
          {route.name === 'dashboard' && <ScreenDashboard go={go} heroVariant={t.heroVariant} firstName={t.firstName} greetIndex={t.greetIndex >= 0 ? t.greetIndex : undefined} />}
          {route.name === 'catalog' && <ScreenCatalog go={go} payload={route.payload} />}
          {route.name === 'directory' && <ScreenDirectory go={go} />}
          {route.name === 'work' && <ScreenWork go={go} work={route.payload} />}
          {route.name === 'recording' && <ScreenRecording go={go} payload={route.payload} />}
          {route.name === 'society' && <ScreenSociety go={go} payload={route.payload} />}
          {route.name === 'claims' && <ScreenClaims go={go} />}
          {route.name === 'cwr' && (window.ScreenCwrAcks ? <window.ScreenCwrAcks go={go} payload={route.payload} /> : <ScreenCwr go={go} />)}
          {route.name === 'caf' && (window.ScreenCaf ? <window.ScreenCaf go={go} payload={route.payload} /> : null)}
          {route.name === 'blackbox' && <ScreenBlackBox go={go} />}
          {route.name === 'mlc' && window.ScreenMlcSync && <window.ScreenMlcSync go={go} payload={route.payload} />}
          {route.name === 'inbox' && window.ScreenInbox && <window.ScreenInbox go={go} payload={route.payload} />}
          {route.name === 'automations' && window.ScreenAutomations && <window.ScreenAutomations go={go} payload={route.payload} />}
          {route.name === 'notifications' && window.ScreenInbox && <window.ScreenInbox go={go} payload={{ tab: 'messages' }} />}
          {route.name === 'audit' && window.ScreenAudit && <window.ScreenAudit go={go} payload={route.payload} />}
          {route.name === 'agreement' && <ScreenAgreement go={go} payload={route.payload} />}
          {route.name === 'agreement-templates' && window.ScreenAgreementTemplates && <window.ScreenAgreementTemplates go={go} payload={route.payload} />}
          {route.name === 'agreement-renewals' && window.ScreenAgreementRenewals && <window.ScreenAgreementRenewals go={go} payload={route.payload} />}
          {route.name === 'agreement-counterparty' && window.ScreenAgreementCounterparty && <window.ScreenAgreementCounterparty go={go} payload={route.payload} />}
          {route.name === 'localization' && window.ScreenLocalization && <window.ScreenLocalization go={go} payload={route.payload} />}
          {route.name === 'analytics' && window.ScreenAnalytics && <window.ScreenAnalytics go={go} payload={route.payload} />}
          {route.name === 'audience' && <ScreenAudience go={go} />}
          {route.name === 'royalties' && <ScreenRoyalties go={go} />}
          {route.name === 'reconciliation' && window.ScreenReconciliation && <window.ScreenReconciliation go={go} payload={route.payload} />}
          {route.name === 'statement-out' && window.ScreenStatementOut && <window.ScreenStatementOut go={go} payload={route.payload} />}
          {route.name === 'subpubs' && window.ScreenSubpubs && <window.ScreenSubpubs go={go} payload={route.payload} />}
          {route.name === 'issues' && <ScreenIssues go={go} payload={route.payload} />}
          {route.name === 'conformance' && window.ScreenConformance && <window.ScreenConformance go={go} payload={route.payload} />}
          {route.name === 'copyright' && <ScreenCopyright go={go} />}
          {route.name === 'public' && <ScreenPublic go={go} profile={route.payload} />}
          {route.name === 'settings' && (
            <RequireSignedIn go={go}>
              <ScreenSettings go={go} payload={route.payload} />
            </RequireSignedIn>
          )}
          {route.name === 'search' && (paletteOpen ? null : <ScreenCatalog go={go} />)}
          {route.name === 'rs-catalog' && window.ScreenRSCatalog && <window.ScreenRSCatalog go={go} />}
          {route.name === 'integrations' && window.ScreenIntegrations && <window.ScreenIntegrations go={go} payload={route.payload} />}
          {route.name === 'enrichment-policy' && window.ScreenEnrichmentPolicy && <window.ScreenEnrichmentPolicy go={go} payload={route.payload} />}
          {route.name === 'insights' && window.ScreenInsights && <window.ScreenInsights go={go} payload={route.payload} />}
          {route.name === 'reports' && window.ScreenReports && <window.ScreenReports go={go} payload={route.payload} />}
          {route.name === 'audio-fp' && window.ScreenAudioFP && <window.ScreenAudioFP go={go} payload={route.payload} />}
          {route.name === 'cultural' && window.ScreenCulturalMarket && <window.ScreenCulturalMarket go={go} payload={route.payload} />}
          {route.name === 'future-proof' && window.ScreenFutureProof && <window.ScreenFutureProof go={go} payload={route.payload} />}
          {route.name === 'stmt-parser' && window.ScreenStmtParser && <window.ScreenStmtParser go={go} payload={route.payload} />}
          {route.name === 'stmt-custom' && window.ScreenStmtCustom && <window.ScreenStmtCustom go={go} payload={route.payload} />}
          {route.name === 'fee-engine' && window.ScreenFeeEngine && <window.ScreenFeeEngine go={go} payload={route.payload} />}
          {route.name === 'writer-payments' && window.ScreenWriterPayments && <window.ScreenWriterPayments go={go} payload={route.payload} />}
          {route.name === 'royalty-viz' && window.ScreenRoyaltyViz && <window.ScreenRoyaltyViz go={go} payload={route.payload} />}
          {route.name === 'bulk-import' && window.ScreenBulkImport && <window.ScreenBulkImport go={go} payload={route.payload} />}
          {route.name === 'dsp-import' && window.ScreenDspImport && <window.ScreenDspImport go={go} payload={route.payload} />}
          {route.name === 'bulk-reg' && window.ScreenBulkReg && <window.ScreenBulkReg go={go} payload={route.payload} />}
          {route.name === 'mandate' && window.ScreenMandate && <window.ScreenMandate go={go} payload={route.payload} />}
          {route.name === 'id-codes' && window.ScreenIdCodes && <window.ScreenIdCodes go={go} payload={route.payload} />}
          {route.name === 'territory' && window.ScreenTerritory && <window.ScreenTerritory go={go} payload={route.payload} />}
          {route.name === 'imprints' && window.ScreenImprintHierarchy && <window.ScreenImprintHierarchy go={go} payload={route.payload} />}
          {route.name === 'releases-id' && window.ScreenReleasesId && <window.ScreenReleasesId go={go} payload={route.payload} />}
          {route.name === 'mam' && window.ScreenMam && <window.ScreenMam go={go} payload={route.payload} />}
          {route.name === 'bulk-export' && window.ScreenBulkExport && <window.ScreenBulkExport go={go} payload={route.payload} />}
          {route.name === 'mojibake' && window.ScreenMojibake && <window.ScreenMojibake go={go} payload={route.payload} />}
          {route.name === 'dedup' && window.ScreenDedup && <window.ScreenDedup go={go} payload={route.payload} />}
          {route.name === 'api' && window.ScreenApi && <window.ScreenApi go={go} payload={route.payload} />}
          {route.name === 'pro-lookup' && window.ScreenPROLookup && <window.ScreenPROLookup go={go} payload={route.payload} />}
        </main>
      </div>

      <Footer />
      <CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} go={go} />
      <GlobalRecordingDrawer go={go} />
      <GlobalAddRecordingModal />
      <GlobalAddSongModal />
      {window.GlobalAddReleaseModal ? <window.GlobalAddReleaseModal/> : null}
      {window.GlobalAddEditionModal ? <window.GlobalAddEditionModal/> : null}
      {window.GlobalAddAgreementModal ? <window.GlobalAddAgreementModal/> : null}
      {window.GlobalVideoDrawer ? <window.GlobalVideoDrawer/> : null}
      {window.SplitSheetOverlay ? <window.SplitSheetOverlay/> : null}
      {window.GlobalAddVideoModal ? <window.GlobalAddVideoModal/> : null}
      {window.NewSubpubWizard ? <window.NewSubpubWizard/> : null}
      <GlobalEntityDrawers go={go} />
      {window.GlobalStatementDrawer ? <window.GlobalStatementDrawer/> : null}
      {window.RoyaltiesImportModal ? <window.RoyaltiesImportModal/> : null}
      {window.RoyaltiesSourceHistory ? <window.RoyaltiesSourceHistory/> : null}
      {window.RoyaltyOptimizer ? <window.RoyaltyOptimizer/> : null}
      <ToastHost />

      <TweaksPanel>
        <TweakSection label="Theme" />
        <TweakRadio label="Mode" value={t.theme} options={['light', 'dark', 'auto']} onChange={(v) => setTweak('theme', v)} />
        <TweakSelect label="Accent" value={t.accent}
        options={[
        { value: 'sodium', label: 'Sodium yellow' },
        { value: 'ember', label: 'Ember orange' },
        { value: 'signal', label: 'Signal green' },
        { value: 'ultra', label: 'Ultra blue' },
        { value: 'mono', label: 'Monochrome' }]
        }
        onChange={(v) => setTweak('accent', v)} />
        <TweakSection label="Layout" />
        <TweakRadio label="Density" value={t.density} options={['compact', 'regular', 'cozy']} onChange={(v) => setTweak('density', v)} />
        <TweakRadio label="Nav" value={t.navStyle} options={['rail', 'none']} onChange={(v) => setTweak('navStyle', v)} />
        <TweakToggle label="Show grid" value={t.showGrid} onChange={(v) => setTweak('showGrid', v)} />
        <TweakSection label="Type" />
        <TweakRadio label="Headings" value={t.heading} options={['display', 'serif', 'mono']} onChange={(v) => setTweak('heading', v)} />
        <TweakSection label="Dashboard hero" />
        <TweakToggle label="First-run onboarding"
          value={!!(window.__rsOnboarding && window.__rsOnboarding.isActive())}
          onChange={(v) => {
            if (v) window.__rsOnboarding && window.__rsOnboarding.activate();
            else window.__rsOnboarding && window.__rsOnboarding.dismiss();
          }} />
        <TweakRadio label="Treatment" value={t.heroVariant} options={['editorial', 'noir', 'neon']} onChange={(v) => setTweak('heroVariant', v)} />
        <TweakText label="First name" value={t.firstName} onChange={(v) => setTweak('firstName', v)} />
        <TweakSlider label="Greeting #" min={-1} max={9} step={1} value={t.greetIndex} onChange={(v) => setTweak('greetIndex', v)} />
        <TweakButton label="Cycle greeting (reload)" onClick={() => {try {localStorage.removeItem('astro_greet_idx');} catch {}window.location.reload();}} />
        <TweakSection label="Territories &amp; FX" />
        <TweakRadio label="Picker default" value={t.territoryPicker} options={['chips', 'tree', 'map']} onChange={(v) => { setTweak('territoryPicker', v); try { localStorage.setItem('astro_territory_picker_mode', v); } catch {} }} />
        <TweakRadio label="Granularity" value={t.territoryGranularity} options={['tis', 'iso', 'bloc']} onChange={(v) => setTweak('territoryGranularity', v)} />
        <TweakRadio label="FX mode" value={t.fxMode} options={['wallets', 'report']} onChange={(v) => setTweak('fxMode', v)} />
        <TweakSelect label="Reporting ccy" value={t.reportingCcy}
          options={['USD','EUR','GBP','JPY','AUD','CAD','BRL','SEK','CHF'].map(c => ({ value: c, label: c }))}
          onChange={(v) => { setTweak('reportingCcy', v); try { localStorage.setItem('astro_report_ccy', v); } catch {} }} />
        <TweakRadio label="Conflicts" value={t.conflictStrictness} options={['warn', 'block', 'off']} onChange={(v) => setTweak('conflictStrictness', v)} />
        <TweakToggle label="Show world map" value={t.showTerritoryMap} onChange={(v) => setTweak('showTerritoryMap', v)} />
      </TweaksPanel>
    </div>);

}

// ───────────────────────── Workspace switcher (real dropdown)
const WORKSPACES = [
{ id: 'pluralis', name: 'Pluralis Music', glyph: 'P', role: 'Owner', kind: 'Publisher', ipi: '00578913241', members: 14, palette: '#FFE65A' },
{ id: 'half-tone', name: 'Half-Tone Records', glyph: 'H', role: 'Admin', kind: 'Label', ipi: '00712054088', members: 6, palette: '#3F8F6E' },
{ id: 'sk-pub', name: 'Solange Knowles Pub.', glyph: 'S', role: 'Contributor', kind: 'Writer admin', ipi: '00892331140', members: 3, palette: '#D9602B' },
{ id: 'eos-coop', name: 'EOS Cooperative', glyph: 'E', role: 'Owner', kind: 'CMO group', ipi: '01122907615', members: 38, palette: '#3056C8' }];


function WorkspaceSwitcher() {
  const [cur, setCur] = useState(() => {
    try {const id = localStorage.getItem('astro_ws');return WORKSPACES.find((w) => w.id === id) || WORKSPACES[0];} catch {return WORKSPACES[0];}
  });
  const [open, setOpen] = useState(false);
  const wrapRef = useRef(null);
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => {if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);};
    const onKey = (e) => {if (e.key === 'Escape') setOpen(false);};
    const onRoute = () => setOpen(false);
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    window.addEventListener('astro-route', onRoute);
    window.addEventListener('hashchange', onRoute);
    return () => {document.removeEventListener('mousedown', onDoc);document.removeEventListener('keydown', onKey);window.removeEventListener('astro-route', onRoute);window.removeEventListener('hashchange', onRoute);};
  }, [open]);
  const pick = (ws) => {
    setCur(ws);
    try {localStorage.setItem('astro_ws', ws.id);} catch {}
    setOpen(false);
  };
  return (
    <div ref={wrapRef} data-hide-mobile style={{ position: 'relative' }}>
      <button onClick={() => setOpen((o) => !o)} aria-expanded={open}
      style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '6px 10px', border: '1px solid var(--rule)', background: open ? 'var(--surface-2)' : 'transparent' }}>
        <span style={{ width: 18, height: 18, background: cur.palette, color: '#0b0b0b', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 700 }}>{cur.glyph}</span>
        <span style={{ fontSize: 13, fontWeight: 500 }}>{cur.name}</span>
        <Ic.Down2 width={12} height={12} style={{ color: 'var(--ink-3)', transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .12s' }} />
      </button>
      {open &&
      <div style={{ position: 'absolute', top: 'calc(100% + 6px)', left: 0, minWidth: 340, background: 'var(--bg)', border: '1px solid var(--rule)', boxShadow: '0 10px 40px rgba(0,0,0,.18)', zIndex: 80 }}>
          {/* Current header */}
          <div style={{ padding: '14px 14px 12px', borderBottom: '1px solid var(--rule)', background: 'var(--surface)' }}>
            <div className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em', marginBottom: 8 }}>CURRENT WORKSPACE</div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <span style={{ width: 32, height: 32, background: cur.palette, color: '#0b0b0b', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, fontWeight: 700 }}>{cur.glyph}</span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14, fontWeight: 600, lineHeight: 1.2 }}>{cur.name}</div>
                <div className="ff-mono" style={{ fontSize: 10, color: 'var(--ink-3)', marginTop: 2 }}>{cur.kind} · IPI {cur.ipi}</div>
              </div>
              <span className="ff-mono upper" style={{ fontSize: 9, letterSpacing: '.1em', padding: '3px 7px', background: 'var(--ink)', color: 'var(--bg)' }}>{cur.role}</span>
            </div>
            <div style={{ display: 'flex', gap: 14, marginTop: 12, fontSize: 11, color: 'var(--ink-2)' }}>
              <span><b style={{ color: 'var(--ink)' }}>{cur.members}</b> members</span>
              <span style={{ color: 'var(--rule)' }}>·</span>
              <span>Production env</span>
            </div>
          </div>
          {/* Switch list */}
          <div style={{ padding: '8px 0' }}>
            <div className="ff-mono upper" style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.12em', padding: '6px 14px' }}>SWITCH TO</div>
            {WORKSPACES.filter((w) => w.id !== cur.id).map((w) =>
          <button key={w.id} onClick={() => pick(w)}
          style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '8px 14px', border: 0, background: 'transparent', cursor: 'pointer', textAlign: 'left' }}
          onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface)'}
          onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
                <span style={{ width: 24, height: 24, background: w.palette, color: '#0b0b0b', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 700 }}>{w.glyph}</span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 500 }}>{w.name}</div>
                  <div className="ff-mono" style={{ fontSize: 10, color: 'var(--ink-3)', marginTop: 1 }}>{w.kind} · {w.role}</div>
                </div>
                <Ic.Right width={12} height={12} style={{ color: 'var(--ink-3)' }} />
              </button>
          )}
          </div>
          {/* Footer actions */}
          <div style={{ borderTop: '1px solid var(--rule)', padding: '4px 0' }}>
            <button onClick={() => setOpen(false)}
          style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '9px 14px', border: 0, background: 'transparent', cursor: 'pointer', textAlign: 'left', fontSize: 12 }}
          onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface)'}
          onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
              <Ic.Plus width={13} height={13} /><span>Create workspace</span>
            </button>
            <button onClick={() => setOpen(false)}
          style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '9px 14px', border: 0, background: 'transparent', cursor: 'pointer', textAlign: 'left', fontSize: 12 }}
          onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface)'}
          onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
              <Ic.Settings width={13} height={13} /><span>Workspace settings</span>
            </button>
          </div>
        </div>
      }
    </div>);

}

// ───────────────────────── Theme toggle (sun/moon/auto cycle)
function ThemeToggle() {
  const [pref, setPref] = useState(() => {try {return localStorage.getItem('astro_theme') || 'light';} catch {return 'light';}});
  useEffect(() => {
    const onPrefs = (e) => {if (e.detail?.theme) setPref(e.detail.theme);};
    window.addEventListener('astro-prefs', onPrefs);
    return () => window.removeEventListener('astro-prefs', onPrefs);
  }, []);
  const cycle = () => {
    const order = ['light', 'dark', 'auto'];
    const next = order[(order.indexOf(pref) + 1) % order.length];
    setPref(next);
    try {localStorage.setItem('astro_theme', next);} catch {}
    window.dispatchEvent(new CustomEvent('astro-prefs', { detail: { theme: next } }));
  };
  const Icon = pref === 'dark' ? Ic.Moon : pref === 'auto' ? Ic.ThemeAuto : Ic.Sun;
  const label = pref === 'dark' ? 'Dark' : pref === 'auto' ? 'Auto' : 'Light';
  return (
    <button data-hide-mobile onClick={cycle}
    title={`Theme: ${label} — click to cycle (Light · Dark · Auto)`}
    style={{ padding: 8, border: '1px solid var(--rule)', display: 'inline-flex', alignItems: 'center' }}>
      <Icon width={14} height={14} />
    </button>);

}

// ───────────────────────── User menu (account dropdown)
function UserMenu({ go }) {
  const [open, setOpen] = useState(false);
  const wrapRef = useRef(null);
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => {if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);};
    const onKey = (e) => {if (e.key === 'Escape') setOpen(false);};
    const onRoute = () => setOpen(false);
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    window.addEventListener('astro-route', onRoute);
    window.addEventListener('hashchange', onRoute);
    return () => {document.removeEventListener('mousedown', onDoc);document.removeEventListener('keydown', onKey);window.removeEventListener('astro-route', onRoute);window.removeEventListener('hashchange', onRoute);};
  }, [open]);
  const close = () => setOpen(false);
  const item = (icon, label, kbd, onClick, danger) =>
  <button onClick={() => {onClick && onClick();close();}}
  style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '9px 14px', border: 0, background: 'transparent', cursor: 'pointer', textAlign: 'left', fontSize: 12, color: danger ? '#c0392b' : 'inherit' }}
  onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface)'}
  onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
      {icon ? React.cloneElement(icon, { width: 13, height: 13 }) : <span style={{ width: 13 }} />}
      <span style={{ flex: 1 }}>{label}</span>
      {kbd && <span className="ff-mono" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.05em' }}>{kbd}</span>}
    </button>;

  return (
    <div ref={wrapRef} data-hide-mobile style={{ position: 'relative' }}>
      <button onClick={() => setOpen((o) => !o)} aria-expanded={open}
      style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '4px 8px 4px 4px', border: '1px solid var(--rule)', background: open ? 'var(--surface-2)' : 'transparent', cursor: 'pointer' }}>
        <span style={{ width: 24, height: 24, background: '#5c2a8a', color: '#fff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 600 }}>AC</span>
        <span style={{ fontSize: 12, fontWeight: 500 }}>a.cohen</span>
      </button>
      {open &&
      <div style={{ position: 'absolute', top: 'calc(100% + 6px)', right: 0, minWidth: 280, background: 'var(--bg)', border: '1px solid var(--rule)', boxShadow: '0 10px 40px rgba(0,0,0,.18)', zIndex: 80 }}>
          {/* Identity card */}
          <div style={{ padding: '14px', borderBottom: '1px solid var(--rule)', background: 'var(--surface)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <span style={{ width: 40, height: 40, background: '#5c2a8a', color: '#fff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 15, fontWeight: 600 }}>AC</span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 600, lineHeight: 1.2 }}>Avery Cohen</div>
                <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>avery@pluralis.music</div>
              </div>
            </div>
            <div style={{ display: 'flex', gap: 8, marginTop: 10, flexWrap: 'wrap' }}>
              <span className="ff-mono upper" style={{ fontSize: 9, letterSpacing: '.1em', padding: '3px 6px', border: '1px solid var(--rule)' }}>RIGHTS OPS</span>
              <span className="ff-mono upper" style={{ fontSize: 9, letterSpacing: '.1em', padding: '3px 6px', background: 'var(--accent)', color: 'var(--accent-ink)' }}>ADMIN</span>
              <span className="ff-mono" style={{ fontSize: 9, color: 'var(--ink-3)', padding: '3px 0' }}>2FA ON</span>
            </div>
          </div>

          {/* Personal */}
          <div style={{ padding: '4px 0', borderBottom: '1px solid var(--rule)' }}>
            {item(<Ic.User />, 'Profile & preferences', null, () => go('settings', { tab: 'profile' }))}
            {item(<Ic.Bell />, 'Notifications', null, () => go('settings', { tab: 'notifications' }))}
            {item(<Ic.Shield />, 'Security & API tokens', null, () => go('settings', { tab: 'security' }))}
          </div>

          {/* Workspace context */}
          <div style={{ padding: '4px 0', borderBottom: '1px solid var(--rule)' }}>
            {item(<Ic.Settings />, 'Workspace settings', null, () => go('settings', { tab: 'workspace' }))}
            {item(<Ic.Layers />, 'Platform mandate', null, () => go('mandate'))}
            {item(<Ic.File />, 'Audit log', null, () => go('audit'))}
            {item(<Ic.Build />, 'Import & Conform', null, () => go('conformance'))}
            {item(<Ic.Layers />, 'Bulk catalog import', null, () => go('bulk-import'))}
            {item(<Ic.Layers />, 'DSP analytics import', null, () => go('dsp-import'))}
            {item(<Ic.Build />, 'Bulk registrations', null, () => go('bulk-reg'))}
            {item(<Ic.Build />, 'Identifier codes', null, () => go('id-codes'))}
            {item(<Ic.Globe />, 'Territories & FX', null, () => go('territory'))}
            {item(<Ic.Layers />, 'API integrations', null, () => go('integrations'))}
            {item(<Ic.Layers />, 'Enrichment policy', null, () => go('enrichment-policy'))}
            {item(<Ic.Build />, 'Developer API', null, () => go('api'))}
            {item(<Ic.Globe />, 'PRO Lookup', null, () => go('pro-lookup'))}
            {item(<Ic.Globe />, 'Localization', null, () => go('localization'))}
            {item(<Ic.Build />, 'Billing & seats', null, () => go('settings', { tab: 'billing' }))}
          </div>

          {/* Operational surfaces — folded out of primary nav. Each warrants its
              own page; users reach them from Issues, Catalog, or this menu. */}
          <div style={{ padding: '4px 0', borderBottom: '1px solid var(--rule)' }}>
            {item(<Ic.Disc />, 'Claims & disputes', null, () => go('claims'))}
            {item(<Ic.Build />, 'CWR · DDEX transmissions', null, () => go('cwr'))}
            {item(<Ic.Coin />, 'Black-box pools', null, () => go('blackbox'))}
            {item(<Ic.Build />, 'MLC sync', null, () => go('mlc'))}
            {item(<Ic.Shield />, 'Copyright registrations', null, () => go('copyright'))}
            {item(<Ic.Layers />, 'Sub-publisher deals', null, () => go('subpubs'))}
            {item(<Ic.Layers />, 'Imprint hierarchy', null, () => go('imprints'))}
            {item(<Ic.Disc />, 'Releases ID tracker', null, () => go('releases-id'))}
            {item(<Ic.Image />, 'Multimedia assets', null, () => go('mam'))}
            {item(<Ic.Disc />, 'Bulk-registration exports', null, () => go('bulk-export'))}
            {item(<Ic.Refresh />, 'Mojibake decoder', null, () => go('mojibake'))}
            {item(<Ic.Layers />, 'Catalog dedup', null, () => go('dedup'))}
          </div>

          {/* Help */}
          <div style={{ padding: '4px 0', borderBottom: '1px solid var(--rule)' }}>
            {item(<Ic.Cmd />, 'Command menu', '⌘K', () => {window.dispatchEvent(new CustomEvent('astro-open-palette'));})}
            {item(<Ic.Refresh />, 'What\u2019s new', null)}
            {item(<Ic.Eye />, 'Keyboard shortcuts', '?')}
          </div>

          {/* Sign out */}
          <div style={{ padding: '4px 0' }}>
            {item(<Ic.Right />, 'Sign out', null, null, true)}
          </div>
        </div>
      }
    </div>);

}

// ───────────────────────── Header
function Header({ go, route, openPalette }) {
  return (
    <header style={{ borderBottom: '1px solid var(--rule)', padding: '14px 24px', display: 'flex', alignItems: 'center', gap: 18, background: 'var(--bg)', position: 'sticky', top: 0, zIndex: 10 }}>
      <button onClick={() => go('dashboard')} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <Ic.Logo width={28} height={28} />
        <span className="ff-display" style={{ fontSize: 20, fontWeight: 700, letterSpacing: '-0.05em' }}>ASTRO</span>
        <span className="ff-mono upper" style={{ fontSize: 9, fontWeight: 500, color: 'var(--ink-3)', padding: '2px 6px', border: '1px solid var(--rule)' }}>V1.0</span>
      </button>

      <span data-hide-mobile style={{ width: 1, height: 22, background: 'var(--rule)' }} />

      {/* Workspace switcher */}
      <WorkspaceSwitcher />

      <span style={{ flex: 1 }} />

      {/* Cmd-K trigger */}
      <button data-search-trigger onClick={openPalette} className="ff-mono" style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 10px 6px 12px', border: '1px solid var(--rule)', background: 'var(--paper)', minWidth: 280 }}>
        <Ic.Search width={14} height={14} style={{ color: 'var(--ink-3)' }} />
        <span data-search-label style={{ fontSize: 12, color: 'var(--ink-3)', flex: 1, textAlign: 'left' }}>Search ASTRO…</span>
        <Kbd>⌘K</Kbd>
      </button>

      <ThemeToggle />

      <AuthStatus />

      <button data-hide-mobile onClick={() => go('inbox')} title="Inbox"
        style={{ padding: 8, border: '1px solid var(--rule)', position: 'relative', background: 'transparent', color: 'inherit', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
        <Ic.Bell width={14} height={14} />
        {(((window.__INBOX_TODAY || 0) + (window.__NOTIFICATIONS_UNREAD || 0)) > 0) && (
          <span className="ff-mono num" style={{ position: 'absolute', top: -6, right: -6, minWidth: 16, height: 16, padding: '0 4px',
            background: 'var(--accent)', color: 'var(--accent-ink)', fontSize: 9, fontWeight: 600,
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
            {(window.__INBOX_TODAY || 0) + (window.__NOTIFICATIONS_UNREAD || 0)}
          </span>
        )}
      </button>

      <div data-hide-mobile>
        <UserMenu go={go} />
      </div>
    </header>);

}

function AuthStatus() {
  const userButtonRef = useRef(null);
  const [auth, setAuth] = useState(() => window.AstroAuth?.state || { ready: false, signedIn: false });
  const [backend, setBackend] = useState({ ok: false, checks: {} });
  const [live, setLive] = useState(null);

  useEffect(() => {
    const onAuth = (e) => setAuth(e.detail || {});
    const onBackend = (e) => setBackend(e.detail || { ok: false, checks: {} });
    const onLive = (e) => setLive(e.detail || null);
    window.addEventListener('astro-auth', onAuth);
    window.addEventListener('astro-backend', onBackend);
    window.addEventListener('astro-live-data', onLive);
    if (window.AstroAuth?.state) setAuth({ ...window.AstroAuth.state });
    return () => {
      window.removeEventListener('astro-auth', onAuth);
      window.removeEventListener('astro-backend', onBackend);
      window.removeEventListener('astro-live-data', onLive);
    };
  }, []);

  useEffect(() => {
    if (auth.signedIn && userButtonRef.current) {
      window.AstroAuth?.mountUserButton(userButtonRef.current);
    }
  }, [auth.signedIn]);

  const tone = auth.signedIn && backend.ok ? 'var(--ok)' : auth.error || backend.error ? 'var(--danger)' : 'var(--ink-3)';
  const label = !auth.ready ? 'Auth…' : auth.signedIn ? 'Live' : 'Sign in';
  const detail = auth.signedIn ? (
    live?.counts ? `${(live.counts.works || 0).toLocaleString()} works` : backend.ok ? 'backend ready' : 'checking backend'
  ) : auth.error ? 'auth setup' : 'secure data';

  return (
    <div data-hide-mobile style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
      <button
        onClick={() => { if (!auth.signedIn) window.AstroAuth?.signIn(); }}
        title={auth.signedIn ? 'Signed in with Clerk' : 'Sign in with Clerk'}
        className="ff-mono upper"
        style={{ display: 'inline-flex', alignItems: 'center', gap: 7, padding: '6px 9px', border: '1px solid var(--rule)', background: 'var(--paper)', cursor: auth.signedIn ? 'default' : 'pointer' }}>
        <span style={{ width: 7, height: 7, borderRadius: 999, background: tone, display: 'inline-block' }} />
        <span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '.08em' }}>{label}</span>
        <span style={{ fontSize: 9, color: 'var(--ink-3)', letterSpacing: '.04em' }}>{detail}</span>
      </button>
      {auth.signedIn && <span ref={userButtonRef} style={{ display: 'inline-flex', width: 30, height: 30, alignItems: 'center', justifyContent: 'center' }} />}
    </div>
  );
}

function RequireSignedIn({ children, go }) {
  const [auth, setAuth] = useState(() => window.AstroAuth?.state || { ready: false, signedIn: false });

  useEffect(() => {
    const onAuth = (e) => setAuth(e.detail || { ready: false, signedIn: false });
    window.addEventListener('astro-auth', onAuth);
    if (window.AstroAuth?.state) setAuth({ ...window.AstroAuth.state });
    return () => window.removeEventListener('astro-auth', onAuth);
  }, []);

  if (!auth.ready) {
    return (
      <div style={{ maxWidth: 640, margin: '80px auto', borderTop: '1px solid var(--rule)', paddingTop: 24 }}>
        <div className="ff-mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.1em', marginBottom: 12 }}>Private workspace</div>
        <h1 className="ff-display" style={{ fontSize: 48, lineHeight: .95, margin: 0 }}>Checking session.</h1>
      </div>
    );
  }

  if (!auth.signedIn) {
    return (
      <div style={{ maxWidth: 640, margin: '80px auto', borderTop: '1px solid var(--rule)', paddingTop: 24 }}>
        <div className="ff-mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.1em', marginBottom: 12 }}>Private workspace</div>
        <h1 className="ff-display" style={{ fontSize: 48, lineHeight: .95, margin: 0 }}>Sign in to open settings.</h1>
        <p style={{ fontSize: 14, color: 'var(--ink-2)', lineHeight: 1.5, maxWidth: 520, marginTop: 18 }}>
          Workspace, billing, team, API, and security settings are only available to signed-in users.
        </p>
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 22 }}>
          <Btn variant="primary" onClick={() => window.AstroAuth?.signIn()}>Sign in</Btn>
          <Btn onClick={() => go('dashboard')}>Back to home</Btn>
        </div>
      </div>
    );
  }

  return children;
}

function SignedOutGate({ auth }) {
  const checks = [
    ['Works, recordings, releases', 'Catalog metadata and identifiers'],
    ['Royalties and analytics', 'Statements, charts, revenue streams'],
    ['CWR, CAF, DDEX delivery', 'Registrations and transmission tools'],
    ['R2 media assets', 'Artwork, audio, video, profile files']
  ];
  const status = !auth.ready ? 'Preparing secure workspace' : auth.error ? 'Authentication setup needs attention' : 'Secure workspace';
  const canLaunchAuth = auth.ready && !auth.error;

  return (
    <div style={{ minHeight: '100vh', background: 'var(--bg)', color: 'var(--ink)', display: 'grid', gridTemplateRows: 'auto 1fr auto' }}>
      <header style={{ height: 64, borderBottom: '1px solid var(--rule)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 28px', boxSizing: 'border-box' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ width: 28, height: 28, border: '1px solid var(--ink)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontWeight: 800 }}>A</div>
          <div>
            <div className="ff-mono upper" style={{ fontSize: 10, letterSpacing: '.12em', fontWeight: 700 }}>ASTRO RIGHTS</div>
            <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>Music rights operating system</div>
          </div>
        </div>
        <button
          className="ff-mono upper"
          disabled={!canLaunchAuth}
          onClick={() => window.AstroAuth?.signIn()}
          style={{ border: '1px solid var(--rule)', background: 'var(--paper)', padding: '9px 12px', fontSize: 10, fontWeight: 700, letterSpacing: '.08em', opacity: canLaunchAuth ? 1 : .55 }}>
          Sign in
        </button>
      </header>

      <main style={{ width: 'min(1120px, calc(100vw - 48px))', margin: '0 auto', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: 40, alignItems: 'center', padding: '56px 0 72px' }}>
        <section>
          <div className="ff-mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.12em', fontWeight: 700, marginBottom: 18 }}>{status}</div>
          <h1 className="heading-swap ff-display" style={{ fontSize: 'clamp(54px, 8vw, 104px)', lineHeight: .86, letterSpacing: '-0.05em', margin: 0 }}>
            Manage music rights with real catalog data.
          </h1>
          <p style={{ maxWidth: 620, fontSize: 16, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 26 }}>
            Sign in to access works, recordings, releases, royalties, analytics, CWR delivery, agreements, profiles, and secured media assets.
          </p>
          {auth.error && (
            <div style={{ marginTop: 18, borderLeft: '3px solid var(--danger)', paddingLeft: 12, color: 'var(--danger)', fontSize: 13 }}>
              {auth.error}
            </div>
          )}
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 28 }}>
            <Btn variant="primary" disabled={!canLaunchAuth} onClick={() => window.AstroAuth?.signIn()}>Sign in</Btn>
            <Btn disabled={!canLaunchAuth} onClick={() => window.AstroAuth?.signUp()}>Create account</Btn>
          </div>
        </section>

        <aside style={{ borderTop: '1px solid var(--rule)', borderBottom: '1px solid var(--rule)', padding: '10px 0' }}>
          {checks.map(([label, sub]) => (
            <div key={label} style={{ display: 'grid', gridTemplateColumns: '14px 1fr', gap: 12, padding: '15px 0', borderBottom: '1px solid var(--rule-soft)' }}>
              <span style={{ width: 8, height: 8, background: 'var(--accent)', marginTop: 6 }} />
              <div>
                <div style={{ fontSize: 14, fontWeight: 700 }}>{label}</div>
                <div className="ff-mono" style={{ fontSize: 10, color: 'var(--ink-3)', marginTop: 3 }}>{sub}</div>
              </div>
            </div>
          ))}
          <div className="ff-mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '.08em', paddingTop: 16 }}>
            Clerk auth · Neon Postgres · Cloudflare R2
          </div>
        </aside>
      </main>

      <footer style={{ borderTop: '1px solid var(--rule)', padding: '14px 28px', fontSize: 11, color: 'var(--ink-3)' }}>
        Private workspace. Public profile links stay shareable.
      </footer>
    </div>
  );
}

function PublicRouteShell({ route, go, auth }) {
  return (
    <div style={{ minHeight: '100vh', background: 'var(--bg)', color: 'var(--ink)', display: 'flex', flexDirection: 'column' }}>
      <header style={{ height: 64, borderBottom: '1px solid var(--rule)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 28px', boxSizing: 'border-box' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ width: 28, height: 28, border: '1px solid var(--ink)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontWeight: 800 }}>A</div>
          <div>
            <div className="ff-mono upper" style={{ fontSize: 10, letterSpacing: '.12em', fontWeight: 700 }}>ASTRO RIGHTS</div>
            <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>Public profile</div>
          </div>
        </div>
        <button
          className="ff-mono upper"
          disabled={!auth.ready || auth.error}
          onClick={() => window.AstroAuth?.signIn()}
          style={{ border: '1px solid var(--rule)', background: 'var(--paper)', padding: '9px 12px', fontSize: 10, fontWeight: 700, letterSpacing: '.08em', opacity: auth.ready && !auth.error ? 1 : .55 }}>
          Sign in
        </button>
      </header>
      <main style={{ flex: 1, minWidth: 0, padding: '32px 40px 88px', maxWidth: 1500, width: '100%', margin: '0 auto', boxSizing: 'border-box' }}>
        {route.name === 'public' && <ScreenPublic go={go} profile={route.payload} />}
      </main>
    </div>
  );
}

// ───────────────────────── Ticker
function Ticker() {
  const items = [
  'CWR · ASCAP · 144 works · ACK 99.2%',
  'GEMA · awaiting ack · seq #003',
  'Royalty parse complete · SoundExchange Q3',
  'NEW conflict · 10% (T-998.221.001-4) · KAY vs Sony/ATV',
  'Spotify import 71%',
  'PRS rejected CW260418PRS.V30 · re-send queued',
  'YouTube Channel UC0918 · 1,204 ISRCs matched',
  'Apple Music DDEX ERN 4.3 delivered · EU',
  'New profile claim · Solange Knowles · IPI 00578913241',
  'Catalog +212 works (30d)'];

  const doubled = [...items, ...items];
  return (
    <div style={{ borderBottom: '1px solid var(--rule)', background: 'var(--ink)', color: 'var(--bg)', padding: '6px 0', overflow: 'hidden' }}>
      <div className="ticker-track ff-mono upper" style={{ fontSize: 10, letterSpacing: '.08em' }}>
        {doubled.map((it, i) =>
        <span key={i} style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 6, height: 6, background: 'var(--accent)' }} />
            {it}
          </span>
        )}
      </div>
    </div>);

}

// ───────────────────────── Icon rail
function Rail({ go, route }) {
  // Live counts from the central catalog-stats object
  const claimsBadge = window.CATALOG_STATS?.claims?.open || 0;
  const issuesBadge = window.__ISSUES_OPEN_COUNT || 0;
  const blackboxBadge = window.__BLACKBOX_URGENT || 0;
  // Simplified primary nav — five screens.
  // Cut from rail (still routable for back-compat / deep links):
  //   claims, cwr, blackbox, copyright, subpubs → folded into Issues / Catalog / Settings.
  //   royalties → folded into Earnings as side-panel ingest.
  //   audience, public → moved to secondary surfaces.
  // Inbox lives in the top-bar bell — no rail entry. Bell badge below sums
  // today's tasks + unread messages.
  const items = [
  { k: 'dashboard', i: Ic.Bar, l: 'Home' },
  { k: 'catalog', i: Ic.Disc, l: 'Catalog' },
  { k: 'directory', i: Ic.User, l: 'Directory' },
  { k: 'royalties', i: Ic.Coin, l: 'Earnings' },
  { k: 'analytics', i: Ic.Bar, l: 'Analytics' },
  { k: 'insights', i: Ic.Spark, l: 'Insights' },
  { k: 'reports', i: Ic.Doc || Ic.File || Ic.Bar, l: 'Reports' },
  { k: 'automations', i: Ic.Settings, l: 'Automations' },
  { k: 'issues', i: Ic.Eye, l: 'Issues', badge: issuesBadge }];

  return (
    <aside data-rail style={{ borderRight: '1px solid var(--rule)', background: 'var(--bg)', padding: '14px 0', display: 'flex', flexDirection: 'column', gap: 6, position: 'fixed', top: 64, left: 0, bottom: 56, width: 64, zIndex: 30, overflow: 'hidden' }}>
      {items.map((it) => {
        const Icon = it.i;
        const active = route === it.k || it.k === 'catalog' && route === 'work' || it.k === 'public' && route === 'public';
        return (
          <button key={it.k} onClick={() => go(it.k)} title={it.l} data-active={active}
          style={{ width: 64, height: 48, position: 'relative', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            color: active ? 'var(--ink)' : 'var(--ink-3)', background: active ? 'var(--bg-2)' : 'transparent',
            borderLeft: active ? '3px solid var(--ink)' : '3px solid transparent' }}>
            <Icon width={20} height={20} />
            {it.badge && <span className="ff-mono num" style={{ position: 'absolute', top: 6, right: 8, fontSize: 9,
              background: 'var(--accent)', color: 'var(--accent-ink)', padding: '1px 4px', fontWeight: 600 }}>{it.badge}</span>}
          </button>);

      })}
      <span data-rail-spacer style={{ flex: 1 }} />
      <button onClick={() => go('settings')} title="Settings" data-active={route === 'settings'} style={{ width: 64, height: 48, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: route === 'settings' ? 'var(--ink)' : 'var(--ink-3)', background: route === 'settings' ? 'var(--bg-2)' : 'transparent', borderLeft: route === 'settings' ? '3px solid var(--ink)' : '3px solid transparent' }}>
        <Ic.Settings width={20} height={20} />
      </button>
    </aside>);

}

// ───────────────────────── Footer
function Footer() {
  return (
    <footer style={{ borderTop: '1px solid var(--rule)', padding: '18px 40px', display: 'flex', justifyContent: 'space-between',
      fontSize: 11, color: 'var(--ink-3)', position: 'fixed', bottom: 0, left: 0, right: 0, background: 'var(--bg)', zIndex: 30, height: 56, boxSizing: 'border-box', alignItems: 'center' }} className="ff-mono">
      <span>© Noah-Milan Investments LLC · ASTRO · all rights reserved</span>
      <span/>
    </footer>);

}

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