/* site.jsx — PUBLIC front-end (separate red theme). Homepage + Atlassian-style
   spec docs. Shares COMPONENTS / TOKENS data with the admin console. The red
   theme is the THEMES entry id 'site' (editable in the backend Themes manager). */
const { useState: useStateST, useEffect: useEffectST, useMemo: useMemoST } = React;

function siteTheme() {
  const t = (typeof THEMES !== 'undefined') && THEMES.find(x => x.id === 'site');
  return t || { id: 'site', name: 'Public Site', accent: { 400:'#E2434C', 500:'#C7000B', 600:'#9E0009' } };
}

/* theme wrapper — sets the accent vars for the whole front-end subtree.
   Defaults to the red 'site' theme; a ?theme= deep-link can swap in any brand. */
function SiteThemeVars({ theme, children }) {
  const a = (theme && theme.accent) || siteTheme().accent;
  return <div className="h-full" style={{ '--accent': a[500], '--accent-weak': 'color-mix(in srgb, ' + a[500] + ' 10%, transparent)' }}>{children}</div>;
}

/* top nav */
function SiteNav({ page, setPage, role, onEnterAdmin, loggedIn, onLogin, onLogout, lang, onSetLang }) {
  const [menu, setMenu] = useStateST(false);
  return (
    <header className="shrink-0 h-16 border-b border-line bg-panel/90 backdrop-blur flex items-center px-8 gap-6 z-10">
      <button onClick={() => setPage('home')} className="flex items-center gap-2.5 shrink-0">
        <span className="w-8 h-8 rounded-[8px] flex items-center justify-center text-white" style={{ background: 'var(--accent)' }}><Icon name="cube" size={18} stroke={1.8} /></span>
        <span className="text-[16px] font-semibold text-ink">{SESSION.product}</span>
      </button>
      <nav className="flex items-center gap-1 ml-2">
        <button onClick={() => setPage('home')} className={cx('h-8 px-3 rounded-[8px] text-[13.5px] font-medium transition', page === 'home' ? 'text-accent bg-accentWeak' : 'text-ink2 hover:text-ink')}>{tr('Home', '首页')}</button>
        <button onClick={() => setPage('spec')} className={cx('h-8 px-3 rounded-[8px] text-[13.5px] font-medium transition', page === 'spec' ? 'text-accent bg-accentWeak' : 'text-ink2 hover:text-ink')}>{tr('Guidelines', '设计规范')}</button>
        <button onClick={() => setPage('icons')} className={cx('h-8 px-3 rounded-[8px] text-[13.5px] font-medium transition', page === 'icons' ? 'text-accent bg-accentWeak' : 'text-ink2 hover:text-ink')}>{tr('Icons', '图标库')}</button>
        <button onClick={() => setPage('content')} className={cx('h-8 px-3 rounded-[8px] text-[13.5px] font-medium transition', page === 'content' ? 'text-accent bg-accentWeak' : 'text-ink2 hover:text-ink')}>{tr('Content', '内容规范')}</button>
        <button onClick={() => setPage('develop')} className={cx('h-8 px-3 rounded-[8px] text-[13.5px] font-medium transition', page === 'develop' ? 'text-accent bg-accentWeak' : 'text-ink2 hover:text-ink')}>{tr('AI integration', 'AI 接入')}</button>
      </nav>
      <div className="ml-auto flex items-center gap-3">
        <Segmented size="sm" value={lang} onChange={(v) => { onSetLang(v); setAppLang(v); }} options={[{ value: 'en', label: 'EN' }, { value: 'zh', label: '中文' }]} />
        {!loggedIn ? (
          <Button variant="primary" onClick={onLogin}>{tr('Log in', '登录')}</Button>
        ) : (
          <div className="relative">
            <button onClick={() => setMenu(o => !o)} className="flex items-center gap-2 h-9 pl-1 pr-2 rounded-full hover:bg-hover transition">
              <span className="w-7 h-7 rounded-full flex items-center justify-center text-[11px] font-semibold text-white" style={{ background: 'var(--accent)' }}>{SESSION.user.name.split(' ').map(s => s[0]).join('')}</span>
              <span className="text-[13px] text-ink hidden sm:block">{SESSION.user.name}</span>
              <Icon name="chevronD" size={13} className="text-ink3" />
            </button>
            {menu && (
              <>
                <div className="fixed inset-0 z-10" onClick={() => setMenu(false)} />
                <div className="absolute right-0 top-11 z-20 w-56 bg-panel border border-line rounded-[12px] py-1.5 shadow-[0_8px_28px_rgba(0,0,0,0.16)]" style={{ animation: 'fadeIn 120ms ease' }}>
                  <div className="px-3 py-1.5 mb-1 border-b border-line">
                    <div className="text-[13px] font-medium text-ink">{SESSION.user.name}</div>
                    <div className="text-[11.5px] text-ink3">{tr(ROLES[role].label, ROLES[role].labelZh)}</div>
                  </div>
                  {canEdit() || role === 'viewer'
                    ? <button onClick={() => { setMenu(false); onEnterAdmin(); }} className="w-full flex items-center gap-2 px-3 h-9 text-[13px] text-ink hover:bg-hover transition"><Icon name="sliders" size={15} className="text-ink2" />{tr('Spec management', '规范管理')}</button>
                    : null}
                  <button onClick={() => { setMenu(false); onLogout(); }} className="w-full flex items-center gap-2 px-3 h-9 text-[13px] text-ink hover:bg-hover transition"><Icon name="external" size={15} className="text-ink2" />{tr('Log out', '退出登录')}</button>
                </div>
              </>
            )}
          </div>
        )}
      </div>
    </header>
  );
}

/* homepage */
function SiteHome({ setPage }) {
  const stats = [
    { n: TOKENS.length, label: tr('Tokens', 'Token') },
    { n: COMPONENTS.length, label: tr('Components', '组件') },
    { n: THEMES.length, label: tr('Themes', '主题') },
    { n: ASSETS.length, label: tr('Assets', '资源') },
  ];
  const features = [
    ['layers', tr('Design tokens', '设计 Token'), tr('A three-tier token system that drives every product surface.', '三层 token 体系,驱动每一个产品界面。')],
    ['component', tr('Components', '组件'), tr('A documented, bilingual component catalog with live examples.', '有文档、双语、带实时示例的组件清单。')],
    ['diff', tr('Monthly releases', '月度发版'), tr('Every change is reviewed and shipped on a monthly cadence.', '每次改动都经评审,按月发布。')],
  ];
  return (
    <div className="flex-1 overflow-y-auto ds-scroll">
      <section className="max-w-[960px] mx-auto px-8 py-20 text-center">
        <span className="inline-flex items-center gap-1.5 h-7 px-3 rounded-full bg-accentWeak text-accent text-[12.5px] font-medium mb-6">{SESSION.cycle}</span>
        <h1 className="text-[44px] font-semibold text-ink tracking-tight leading-[1.1]">{SESSION.product}<br />{tr('Design System', '设计规范')}</h1>
        <p className="text-[16px] text-ink2 mt-5 max-w-[640px] mx-auto leading-relaxed">{tr('One language for every SiCARRIER product — tokens, components, assets and themes, versioned monthly with a full changelog.', '面向所有 SiCARRIER 产品的同一种设计语言 —— token、组件、资源与主题,按月版本化并附完整变更记录。')}</p>
        <div className="flex items-center justify-center gap-3 mt-8">
          <Button variant="primary" size="lg" onClick={() => setPage('spec')}>{tr('Explore the guidelines', '浏览设计规范')}</Button>
        </div>
        <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mt-16">
          {stats.map(s => (
            <div key={s.label} className="rounded-[12px] border border-line bg-panel p-5">
              <div className="text-[28px] font-semibold text-ink tabular-nums">{s.n}</div>
              <div className="text-[13px] text-ink3 mt-1">{s.label}</div>
            </div>
          ))}
        </div>
      </section>
      <section className="max-w-[960px] mx-auto px-8 pb-24 grid grid-cols-1 sm:grid-cols-3 gap-4">
        {features.map(([ic, t, d]) => (
          <div key={t} className="rounded-[12px] border border-line bg-panel p-6">
            <span className="w-10 h-10 rounded-[12px] bg-accentWeak text-accent flex items-center justify-center mb-3"><Icon name={ic} size={20} /></span>
            <h3 className="text-[15px] font-semibold text-ink">{t}</h3>
            <p className="text-[13px] text-ink2 mt-1.5 leading-snug">{d}</p>
          </div>
        ))}
      </section>
      <footer className="border-t border-line py-8 text-center text-[12.5px] text-ink3">{SESSION.product} · {tr('Design System', '设计规范')} · {SESSION.cycle}</footer>
    </div>
  );
}

/* ---- Design tokens doc — presented like a component (Atlassian "all tokens").
   5 tabs (Examples · Usage · Content · Design · Changelog) mirroring the component
   detail layout. Examples = grouped all-tokens reference; Changelog = derived from
   CHANGE_HISTORY (token-kind items only), never stored. ---- */

/* token-changelog derivation: each release's token-kind items, releases that have any */
function tokenChangelogReleases() {
  const hist = (typeof CHANGE_HISTORY !== 'undefined') ? CHANGE_HISTORY : [];
  return hist
    .map(rel => ({ rel, items: (rel.items || []).filter(it => it.kind === 'token') }))
    .filter(g => g.items.length);
}
/* compact human label for a single token change item */
function tokenChangeLine(it) {
  const m = (typeof ACTION_META !== 'undefined' && ACTION_META[it.action]) || { label: it.action, color: 'var(--text-2)' };
  let detail = '';
  if (it.action === 'renamed' && it.from) detail = it.from + ' → ' + it.to;
  else if (it.action === 'added' && it.to) detail = it.to;
  else if (it.from != null && it.to != null) detail = it.from + ' → ' + it.to;
  else if (it.to != null) detail = String(it.to);
  return { m, detail };
}

function SiteTokenDoc({ ctx }) {
  const zh = getAppLang() === 'zh';
  const [tab, setTab] = useStateST('example');
  const doc = (typeof TOKEN_DOC !== 'undefined') ? TOKEN_DOC : { name: 'Design tokens', nameZh: '设计 Token' };
  const rctx = ctx || { theme: (typeof THEMES !== 'undefined' ? THEMES[0] : null), mode: 'light' };

  /* Examples — group TOKENS by layer (tier) → category, in canonical order */
  const groups = React.useMemo(() => {
    const toks = (typeof TOKENS !== 'undefined') ? TOKENS : [];
    const layers = (typeof LAYERS !== 'undefined') ? LAYERS : [];
    const cats = (typeof CATEGORIES !== 'undefined') ? CATEGORIES : [];
    const out = [];
    layers.forEach(layer => {
      cats.forEach(cat => {
        const items = toks.filter(t => t.layer === layer.id && t.category === cat);
        if (items.length) out.push({ layer, cat, items });
      });
    });
    return out;
  }, []);

  const fmtVal = (token, r) => {
    if (r.cycle) return '⚠ cycle';
    if (token.kind === 'color') return r.value;
    if (token.kind === 'spacing' || token.kind === 'radius') return r.value + 'px';
    if (token.kind === 'type') return r.value + ' / ' + (r.lh || '—') + ' px';
    if (token.kind === 'shadow') return r.value;
    return String(r.value);
  };

  return (
    <div className="flex-1 min-w-0 overflow-y-auto ds-scroll [scrollbar-gutter:stable]">
      <div className="max-w-[820px] mx-auto px-10 py-10">
        <div className="flex items-center gap-2.5 mb-1.5 flex-wrap">
          <h1 className="text-[28px] font-semibold text-ink tracking-tight">{tr(doc.name, doc.nameZh)}</h1>
          <span className="inline-flex items-center gap-1 h-[20px] px-2 rounded-[4px] text-[11px] font-medium bg-accentWeak text-accent">{tr('Foundation', '基础')}</span>
        </div>
        <p className="text-[15px] text-ink2 mb-7 leading-relaxed">{tr(doc.summary, doc.summaryZh)}</p>

        <div className="flex items-center gap-1 border-b border-line mb-7">
          {[['example', tr('Examples', '示例')], ['usage', tr('Usage', '用法')], ['content', tr('Content', '文案')], ['notes', tr('Design', '设计思路')], ['changelog', tr('Changelog', '更新日志')]].map(([k, l]) => (
            <button key={k} onClick={() => setTab(k)} className={cx('h-9 px-3 text-[13.5px] font-medium -mb-px border-b-2 transition', tab === k ? 'border-accent text-accent' : 'border-transparent text-ink2 hover:text-ink')}>{l}</button>
          ))}
        </div>

        {tab === 'example' && (
          <div className="flex flex-col gap-9">
            <p className="text-[14px] text-ink2 leading-relaxed">{tr('Every token in the system, grouped by tier and category, resolved under the current theme. Names are the source ids; use the semantic and component tiers in product code.', '系统中的全部 token,按层级与类目分组,在当前主题下解析。名称为源 id;在产品代码中请使用语义层与组件层。')}</p>
            {groups.map(g => (
              <div key={g.layer.id + '/' + g.cat}>
                <div className="sticky top-0 z-[1] flex items-center gap-2 -mx-2 px-2 h-9 bg-app/92 backdrop-blur border-b border-line mb-2">
                  <span className="text-[12px] font-semibold uppercase tracking-wide text-ink2">{g.layer.name} · {g.cat}</span>
                  <span className="text-[11.5px] text-ink3 tabular-nums">{g.items.length}</span>
                  <span className="text-[11.5px] text-ink3 ml-auto hidden sm:block">{tr(g.layer.hint, g.layer.hint)}</span>
                </div>
                <div className="rounded-[12px] border border-line overflow-hidden">
                  {g.items.map((token, i) => {
                    const r = resolve(token.id, rctx);
                    const deprecated = token.status === 'deprecated';
                    return (
                      <div key={token.id} className={cx('flex items-center gap-3 px-3.5 py-2.5 border-b border-[color:var(--border)] last:border-0', deprecated && 'opacity-55')}>
                        <span className="shrink-0 flex items-center justify-center w-7">
                          {token.kind === 'color' ? <Swatch color={r.value} size={22} /> : <KindPreview token={token} ctx={rctx} size={22} />}
                        </span>
                        <span className="min-w-0 flex-1 flex flex-col gap-0.5">
                          <span className="flex items-center gap-1.5">
                            <span className={cx('font-mono text-[12.5px] truncate', deprecated ? 'text-ink2 line-through' : 'text-ink')}>{token.id}</span>
                            {token.status && token.status !== 'published' && <StatusTag status={token.status} />}
                          </span>
                          {token.description && <span className="text-[11.5px] text-ink3 leading-snug line-clamp-1">{token.description}</span>}
                        </span>
                        <span className="shrink-0 font-mono text-[12px] text-ink2 text-right max-w-[40%] truncate">{fmtVal(token, r)}</span>
                      </div>
                    );
                  })}
                </div>
              </div>
            ))}
          </div>
        )}

        {tab === 'usage' && <MarkdownDoc md={zh ? (doc.usageMdZh || doc.usageMd) : doc.usageMd} />}

        {tab === 'content' && <MarkdownDoc md={zh ? (doc.contentMdZh || doc.contentMd) : doc.contentMd} />}

        {tab === 'notes' && <MarkdownDoc md={zh ? (doc.designMdZh || doc.designMd) : doc.designMd} />}

        {tab === 'changelog' && (() => {
          const releases = tokenChangelogReleases();
          if (!releases.length) return <p className="text-[14px] text-ink3 leading-relaxed">{tr('No token changes recorded yet.', '暂无 token 变更记录。')}</p>;
          return (
            <div className="flex flex-col gap-2">
              <p className="text-[13px] text-ink3 mb-3 inline-flex items-center gap-1.5"><Icon name="diff" size={13} />{tr('Automatically derived from shipped releases — token changes only.', '自动从已发布版本中提取 —— 仅含 token 变更。')}</p>
              {releases.map(({ rel, items }) => (
                <div key={rel.id} className="flex gap-4">
                  <div className="w-24 shrink-0">
                    <span className="font-mono text-[13px] text-ink">#{rel.number}</span>
                    <div className="text-[11px] text-ink3">{rel.date}</div>
                  </div>
                  <ul className="flex-1 border-l border-line pl-4 flex flex-col gap-1.5 pb-3">
                    {items.map(it => {
                      const { m, detail } = tokenChangeLine(it);
                      return (
                        <li key={it.id} className="text-[13px] leading-snug flex items-start gap-2">
                          <span className="inline-flex items-center h-[18px] px-1.5 rounded-[4px] text-[10.5px] font-medium shrink-0 mt-px" style={{ background: 'color-mix(in srgb, ' + m.color + ' 13%, transparent)', color: m.color }}>{m.label}</span>
                          <span className="min-w-0">
                            <span className="font-mono text-ink">{it.target}</span>
                            {detail && <span className="font-mono text-ink3"> · {detail}</span>}
                          </span>
                        </li>
                      );
                    })}
                  </ul>
                </div>
              ))}
            </div>
          );
        })()}
      </div>
    </div>
  );
}

/* Atlassian-style spec docs */
function SiteSpec({ ctx, initialTheme }) {
  const [sel, setSel] = useStateST('__tokens__');
  const [tab, setTab] = useStateST('example');
  const [specTheme, setSpecTheme] = useStateST(initialTheme || null); // null = default red 'site' theme
  const [themeMenu, setThemeMenu] = useStateST(false);
  const [copied, setCopied] = useStateST(false);
  const c = sel && sel !== '__tokens__' && COMPONENT_MAP[sel];
  const zh = getAppLang() === 'zh';
  const allThemes = (typeof THEMES !== 'undefined') ? THEMES : [];
  // preview theme is scoped to Guidelines only — the site chrome stays the red 'site' theme
  const specCtx = useMemoST(() => {
    const fallback = allThemes.find(t => t.id === 'site') || allThemes[0] || null;
    return { theme: specTheme || fallback, mode: (ctx && ctx.mode) || 'light' };
  }, [specTheme, ctx && ctx.mode]);
  const a = (specCtx.theme && specCtx.theme.accent) || {};
  function pickTheme(next) {
    const isOverride = next && next.id !== 'site';
    setSpecTheme(isOverride ? next : null);
    window.history.replaceState(null, '', window.location.pathname + (isOverride ? '?theme=' + encodeURIComponent(next.id) : ''));
  }
  const shareUrl = (specCtx.theme && specCtx.theme.id !== 'site')
    ? window.location.origin + window.location.pathname + '?theme=' + encodeURIComponent(specCtx.theme.id)
    : window.location.origin + window.location.pathname;
  const copyShare = () => { try { navigator.clipboard.writeText(shareUrl); } catch (e) {} setCopied(true); setTimeout(() => setCopied(false), 1400); };
  return (
    <div className="flex-1 min-h-0 flex" style={{ '--accent': a[500] || 'var(--accent)', '--accent-weak': a[500] ? 'color-mix(in srgb, ' + a[500] + ' 10%, transparent)' : 'var(--accent-weak)' }}>
      <div className="w-[240px] shrink-0 border-r border-line bg-[color:var(--bg-rail)] flex flex-col">
        <div className="px-3 py-3 border-b border-line">
          <div className="px-1 pb-1.5 text-[11px] uppercase tracking-wide text-ink3">{tr('Preview theme', '预览主题')}</div>
          <div className="relative">
            <button onClick={() => setThemeMenu(o => !o)}
              className="w-full h-9 px-2.5 rounded-[8px] border border-line bg-app hover:bg-hover transition flex items-center gap-2 text-[13px] text-ink">
              <span className="w-2.5 h-2.5 rounded-full shrink-0" style={{ background: a[500] || 'var(--accent)' }} />
              <span className="flex-1 text-left truncate">{(specCtx.theme && specCtx.theme.name) || tr('Public site', '官网')}</span>
              <Icon name="chevronD" size={13} className="text-ink3 shrink-0" />
            </button>
            {themeMenu && (
              <>
                <div className="fixed inset-0 z-10" onClick={() => setThemeMenu(false)} />
                <div className="absolute left-0 right-0 top-10 z-20 bg-panel border border-line rounded-[10px] py-1.5 shadow-[0_8px_28px_rgba(0,0,0,0.16)]" style={{ animation: 'fadeIn 120ms ease' }}>
                  {allThemes.map(t => (
                    <button key={t.id} onClick={() => { pickTheme(t); setThemeMenu(false); }}
                      className="w-full flex items-center gap-2 px-2.5 h-9 text-[13px] text-ink hover:bg-hover transition">
                      <span className="w-2.5 h-2.5 rounded-full shrink-0" style={{ background: t.accent[500] }} />
                      <span className="flex-1 text-left truncate">{t.name}</span>
                      {specCtx.theme && specCtx.theme.id === t.id && <Icon name="check" size={14} className="text-accent shrink-0" />}
                    </button>
                  ))}
                  <div className="border-t border-line my-1" />
                  <button onClick={copyShare} className="w-full flex items-center gap-2 px-2.5 h-9 text-[13px] text-ink2 hover:text-ink hover:bg-hover transition">
                    <Icon name={copied ? 'check' : 'link'} size={14} className={copied ? 'text-success' : ''} />
                    {copied ? tr('Copied', '已复制') : tr('Copy share link', '复制分享链接')}
                  </button>
                </div>
              </>
            )}
          </div>
        </div>
        <div className="flex-1 overflow-y-auto ds-scroll-hover py-3">
        <div className="mb-2">
          <div className="px-4 py-1 text-[11px] uppercase tracking-wide text-ink3">{tr('Foundations', '基础')}</div>
          <button onClick={() => { setSel('__tokens__'); setTab('example'); }} className={cx('w-full text-left px-4 h-8 text-[13px] transition flex items-center gap-1.5', sel === '__tokens__' ? 'text-accent bg-accentWeak font-medium' : 'text-ink2 hover:text-ink hover:bg-hover')}>
            <Icon name="layers" size={14} className="shrink-0" />
            <span className="truncate flex-1">{tr((typeof TOKEN_DOC !== 'undefined' ? TOKEN_DOC.name : 'Design tokens'), (typeof TOKEN_DOC !== 'undefined' ? TOKEN_DOC.nameZh : '设计 Token'))}</span>
          </button>
        </div>
        {COMP_CATEGORIES.map(cat => (
          <div key={cat} className="mb-2">
            <div className="px-4 py-1 text-[11px] uppercase tracking-wide text-ink3">{tr(cat, COMP_CAT_LABELS[cat])}</div>
            {COMPONENTS.filter(x => x.category === cat).map(x => (
              <button key={x.id} onClick={() => { setSel(x.id); setTab('example'); }} className={cx('w-full text-left px-4 h-8 text-[13px] transition flex items-center gap-1.5', sel === x.id ? 'text-accent bg-accentWeak font-medium' : 'text-ink2 hover:text-ink hover:bg-hover')}>
                <span className="truncate flex-1">{tr(x.name, x.nameZh)}</span>
                {x.caution && <span className="shrink-0 text-[9px] leading-none font-semibold px-1.5 py-0.5 rounded" style={{ background:'rgba(200,105,30,0.14)', color:'var(--warning)' }}>{tr('Caution','谨慎')}</span>}
                {x.status === 'beta' && <span className="shrink-0 text-[9px] leading-none font-semibold px-1.5 py-0.5 rounded" style={{ background:'rgba(10,89,247,0.12)', color:'#0A59F7' }}>{tr('Beta','测试版')}</span>}
                {x.status === 'deprecated' && <span className="shrink-0 text-[9px] leading-none font-semibold px-1.5 py-0.5 rounded line-through text-ink3" style={{ background:'rgba(0,0,0,0.06)' }}>{tr('Deprecated','废弃')}</span>}
              </button>
            ))}
          </div>
        ))}
        </div>
      </div>
      {sel === '__tokens__' ? <SiteTokenDoc ctx={specCtx} /> : (
      <div className="flex-1 min-w-0 overflow-y-auto ds-scroll [scrollbar-gutter:stable]">
        {!c ? <div className="h-full flex items-center justify-center text-ink3">{tr('Select a component', '选择一个组件')}</div> : (
          <div className="max-w-[820px] mx-auto px-10 py-10">
            <div className="flex items-center gap-2.5 mb-1.5 flex-wrap">
              <h1 className="text-[28px] font-semibold text-ink tracking-tight">{tr(c.name, c.nameZh)}</h1>
              <CompStatusTag status={c.status} />{c.caution && <CautionBadge />}
            </div>
            <p className="text-[15px] text-ink2 mb-7 leading-relaxed">{tr(c.summary, c.summaryZh)}</p>
            <div className="flex items-center gap-1 border-b border-line mb-7">
              {[['example', tr('Examples', '示例')], ['usage', tr('Usage', '用法')], ['content', tr('Content', '文案')], ['notes', tr('Design', '设计思路')], ['changelog', tr('Changelog', '更新日志')]].map(([k, l]) => (
                <button key={k} onClick={() => setTab(k)} className={cx('h-9 px-3 text-[13.5px] font-medium -mb-px border-b-2 transition', tab === k ? 'border-accent text-accent' : 'border-transparent text-ink2 hover:text-ink')}>{l}</button>
              ))}
            </div>

            {tab === 'example' && (
              <div className="flex flex-col gap-5">
                {c.examples.filter(e => e.show).map(e => (
                  <div key={e.id} className="rounded-[12px] border border-line overflow-hidden">
                    <div className="p-10 flex items-center justify-center bg-sunken border-b border-line"><DemoPreview demo={e.demo} /></div>
                    <div className="px-4 py-2.5"><span className="text-[13px] font-medium text-ink">{tr(e.title, e.titleZh)}</span><span className="text-[12.5px] text-ink3"> — {tr(e.note, e.noteZh)}</span></div>
                  </div>
                ))}
                {c.examples.filter(e => e.show).length === 0 && <p className="text-[13px] text-ink3">{tr('No examples published.', '暂无公开示例。')}</p>}
              </div>
            )}

            {tab === 'usage' && (
              <div className="flex flex-col gap-7">
                <p className="text-[14.5px] text-ink leading-relaxed">{tr(c.overview, c.overviewZh)}</p>
                <div className="grid grid-cols-1 sm:grid-cols-2 gap-7">
                  <div>
                    <div className="flex items-center gap-1.5 mb-3 text-[13px] font-semibold text-success"><Icon name="check" size={15} />{tr('Do', '推荐')}</div>
                    <ul className="flex flex-col gap-2.5">{(zh && c.dosZh.length ? c.dosZh : c.dos).map((d, i) => <li key={i} className="text-[13px] text-ink2 flex gap-2 leading-snug"><Icon name="check" size={14} className="text-success shrink-0 mt-0.5" />{d}</li>)}</ul>
                  </div>
                  <div>
                    <div className="flex items-center gap-1.5 mb-3 text-[13px] font-semibold text-danger"><Icon name="close" size={15} />{tr("Don't", '避免')}</div>
                    <ul className="flex flex-col gap-2.5">{(zh && c.dontsZh.length ? c.dontsZh : c.donts).map((d, i) => <li key={i} className="text-[13px] text-ink2 flex gap-2 leading-snug"><Icon name="close" size={14} className="text-danger shrink-0 mt-0.5" />{d}</li>)}</ul>
                  </div>
                </div>
              </div>
            )}

            {tab === 'changelog' && (
              <div className="flex flex-col gap-4">
                {c.changelog.map(cl => (
                  <div key={cl.v} className="flex gap-4">
                    <div className="w-20 shrink-0"><span className="font-mono text-[13px] text-ink">v{cl.v}</span><div className="text-[11px] text-ink3">{cl.date}</div></div>
                    <ul className="flex-1 border-l border-line pl-4 flex flex-col gap-1.5 pb-2">{(zh && cl.notesZh && cl.notesZh.length ? cl.notesZh : cl.notes).map((n, i) => <li key={i} className="text-[13px] text-ink2 leading-snug">{n}</li>)}</ul>
                  </div>
                ))}
              </div>
            )}

            {tab === 'notes' && (
              c.interaction
                ? <MarkdownDoc md={c.interaction} />
                : <p className="text-[14px] text-ink3 leading-relaxed">{tr('No design notes published for this component yet.', '该组件暂未发布设计说明。')}</p>
            )}

            {tab === 'content' && (() => {
              const rows = (typeof copyForComponent !== 'undefined') ? copyForComponent(c.id) : [];
              return rows.length
                ? <div className="flex flex-col gap-4">
                    <p className="text-[14px] text-ink2 leading-relaxed">{tr('Standard copy for this component — EN/中文 with meaning and good/avoid examples. Manage these in the Content module.', '该组件的标准文案 —— 中英对照,附含义与推荐/避免示例。可在「内容规范」模块统一维护。')}</p>
                    {rows.map(cp => <CopySpec key={cp.key} item={cp} />)}
                  </div>
                : <p className="text-[14px] text-ink3 leading-relaxed">{tr('No copy standards published for this component yet.', '该组件暂未发布文案标准。')}</p>;
            })()}
          </div>
        )}
      </div>
      )}
    </div>
  );
}

/* serialize a rendered <svg> into a clean standalone SVG string (color baked in) */
function iconSvgString(svgEl, color) {
  if (!svgEl) return '';
  const c = svgEl.cloneNode(true);
  c.removeAttribute('class'); c.removeAttribute('aria-hidden'); c.removeAttribute('style');
  c.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  return c.outerHTML.replace(/currentColor/g, color || '#1D1D1F');
}
function siteDownload(name, content, mime) {
  const blob = new Blob([content], { type: mime });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a'); a.href = url; a.download = name; document.body.appendChild(a); a.click();
  setTimeout(() => { URL.revokeObjectURL(url); a.remove(); }, 0);
}
const ICON_SWATCHES = ['#1D1D1F', '#C7000B', '#0A59F7', '#1E874B', '#C8691E', '#6E6E73'];

/* Icon library — arco-iconbox-style: live color/size/stroke, background preview,
   per-icon detail drawer with copy-name / copy-component / copy-SVG / download-SVG */
function SiteIcons() {
  const zh = getAppLang() === 'zh';
  const icons = (typeof ASSETS !== 'undefined' ? ASSETS : []).filter(a => a.type === 'icon' && a.status !== 'deprecated');
  const cats = Array.from(new Set(icons.map(i => i.category)));
  const [q, setQ] = useStateST('');
  const [cat, setCat] = useStateST('all');
  const [size, setSize] = useStateST(28);
  const [stroke, setStroke] = useStateST(1.6);
  const [color, setColor] = useStateST('#1D1D1F');
  const [bg, setBg] = useStateST('light');
  const [sel, setSel] = useStateST(null);
  const [toast, setToast] = useStateST(null);
  const previewRef = React.useRef(null);
  const shown = icons.filter(i =>
    (cat === 'all' || i.category === cat) &&
    (!q || (i.id + ' ' + i.keywords.join(' ') + ' ' + i.category).toLowerCase().includes(q.toLowerCase())));
  const flash = (msg) => { setToast(msg); setTimeout(() => setToast(null), 1500); };
  const copyText = (text, label) => { try { navigator.clipboard.writeText(text); } catch (e) {} flash(label); };
  const tileBg = bg === 'dark' ? 'bg-[#1D1D1F] border-[color:rgba(255,255,255,0.12)]' : bg === 'checker' ? 'checker border-line' : 'bg-sunken border-line';

  return (
    <div className="flex-1 min-h-0 flex">
      <div className="flex-1 min-w-0 overflow-y-auto ds-scroll [scrollbar-gutter:stable]">
      <section className="max-w-[1120px] mx-auto px-8 py-10">
        <h1 className="text-[30px] font-semibold text-ink tracking-tight">{tr('Icon library', '图标库')}</h1>
        <p className="text-[15px] text-ink2 mt-2">{tr('Every icon in the SiCARRIER system. Tune color, size and stroke, then copy the name, component, SVG, or download it.', 'SiCARRIER 系统的全部图标。可调颜色、尺寸、线宽,然后复制名称、组件、SVG,或直接下载。')}</p>

        {/* search + category */}
        <div className="sticky top-0 z-[2] bg-app/92 backdrop-blur -mx-2 px-2 pt-3 mt-6 flex items-center gap-2 flex-wrap">
          <div className="relative w-[300px] max-w-full">
            <Icon name="search" size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink3" />
            <input value={q} onChange={e => setQ(e.target.value)} placeholder={tr('Search icons…', '搜索图标…')}
              className="w-full h-10 bg-panel border border-line rounded-[12px] pl-9 pr-3 text-[14px] text-ink focus-ring focus:border-line2" />
          </div>
          <div className="flex items-center gap-1 flex-wrap">
            {['all'].concat(cats).map(c => (
              <button key={c} onClick={() => setCat(c)}
                className={cx('h-8 px-3 rounded-[8px] text-[13px] font-medium transition', cat === c ? 'bg-accentWeak text-accent' : 'text-ink2 hover:text-ink hover:bg-hover')}>
                {c === 'all' ? tr('All', '全部') : c}</button>
            ))}
          </div>
          <span className="ml-auto text-[13px] text-ink3 tabular-nums">{shown.length}</span>
        </div>
        {/* render settings */}
        <div className="sticky top-[52px] z-[2] bg-app/92 backdrop-blur -mx-2 px-2 pb-3 pt-2 mb-1 flex items-center gap-5 flex-wrap text-[12.5px] text-ink2 border-b border-line">
          <label className="inline-flex items-center gap-2">{tr('Size', '尺寸')}
            <input type="range" min="16" max="40" value={size} onChange={e => setSize(+e.target.value)} className="w-28" style={{ accentColor: 'var(--accent)' }} />
            <span className="font-mono text-ink3 w-6 text-right">{size}</span></label>
          <label className="inline-flex items-center gap-2">{tr('Stroke', '线宽')}
            <input type="range" min="1" max="2.4" step="0.1" value={stroke} onChange={e => setStroke(+e.target.value)} className="w-24" style={{ accentColor: 'var(--accent)' }} />
            <span className="font-mono text-ink3 w-7 text-right">{stroke.toFixed(1)}</span></label>
          <div className="inline-flex items-center gap-1.5">{tr('Color', '颜色')}
            {ICON_SWATCHES.map(s => (
              <button key={s} onClick={() => setColor(s)} title={s}
                className={cx('w-5 h-5 rounded-full border transition', color === s ? 'ring-2 ring-offset-1 ring-[color:var(--accent)] border-transparent' : 'border-line hover:scale-110')} style={{ background: s }} />
            ))}
            <input type="color" value={color} onChange={e => setColor(e.target.value)} title={tr('Custom', '自定义')}
              className="w-5 h-5 rounded-full border border-line bg-transparent cursor-pointer p-0" />
          </div>
          <Segmented size="sm" value={bg} onChange={setBg} options={[{ value: 'light', label: tr('Light', '浅') }, { value: 'checker', label: tr('Grid', '格') }, { value: 'dark', label: tr('Dark', '深') }]} />
        </div>

        {shown.length === 0 ? (
          <div className="py-24 text-center text-ink3 text-[14px]">{tr('No icons match.', '没有匹配的图标。')}</div>
        ) : (
          <div className="grid gap-3 mt-4" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(132px, 1fr))' }}>
            {shown.map(ic => (
              <button key={ic.id} onClick={() => setSel(ic)} title={ic.id + (ic.desc ? ' — ' + ic.desc : '')}
                className={cx('group relative flex flex-col items-center gap-2.5 rounded-[12px] border bg-panel p-4 transition', sel && sel.id === ic.id ? 'border-accent' : 'border-line hover:border-accent hover:shadow-[0_4px_16px_rgba(0,0,0,0.06)]')}>
                <span className={cx('w-14 h-14 rounded-[12px] border flex items-center justify-center transition', tileBg)} style={{ color }}>
                  {ic.uploaded && ic.url ? <img src={ic.url} alt={ic.id} className="max-w-[80%] max-h-[80%] object-contain" /> : <Icon name={ic.icon} size={Math.min(size, 40)} stroke={stroke} />}
                </span>
                <span className="font-mono text-[11px] text-ink2 truncate max-w-full">{ic.id.split('.').slice(1).join('.')}</span>
                {ic.status !== 'published' && <span className="absolute top-2 right-2"><StatusTag status={ic.status} /></span>}
              </button>
            ))}
          </div>
        )}
        <footer className="border-t border-line mt-12 pt-8 text-center text-[12.5px] text-ink3">{SESSION.product} · {tr('Icon library', '图标库')} · {icons.length} {tr('icons', '个图标')}</footer>
      </section>
      </div>

      {/* docked inspector — an inline panel (no scrim) so you can click through icons rapidly */}
      {sel && (
        <aside className="w-[380px] shrink-0 border-l border-line bg-panel flex flex-col" style={{ animation:'fadeIn 120ms ease' }}>
          <div className="flex items-start justify-between px-5 pt-4 pb-3 border-b border-line">
            <div className="min-w-0">
              <div className="text-[11px] uppercase tracking-wide text-ink3 mb-1">{sel.category} · {sel.format} · {sel.dims}</div>
              <h2 className="font-mono text-[15px] text-ink font-medium truncate">{sel.id}</h2>
            </div>
            <IconButton name="close" title="Close" onClick={() => setSel(null)} />
          </div>
          <div className="flex-1 overflow-y-auto ds-scroll p-5 flex flex-col gap-5">
            <div className={cx('rounded-[12px] border flex items-center justify-center h-44', tileBg)} style={{ color }}>
              <span ref={previewRef}>{sel.uploaded && sel.url ? <img src={sel.url} alt={sel.id} className="max-h-32 object-contain" /> : <Icon name={sel.icon} size={Math.max(size + 16, 44)} stroke={stroke} />}</span>
            </div>
            {(() => {
              const lbl = (typeof copyForIcon !== 'undefined') ? copyForIcon(sel.id) : null;
              if (!lbl) return null;
              return (
                <div className="rounded-[12px] border border-line bg-sunken p-3.5">
                  <div className="flex items-center justify-between mb-1">
                    <div className="text-[10.5px] uppercase tracking-wide text-ink3">{tr('Standard label', '标准文字')}</div>
                    <span className="inline-flex items-center gap-1 text-[10.5px] text-ink3"><Icon name="edit" size={11} />{tr('Managed in Content', '内容规范维护')}</span>
                  </div>
                  <div className="text-[15px] font-medium text-ink">{lbl.en}<span className="text-ink3 font-normal"> · {lbl.zh}</span></div>
                  {(getAppLang()==='zh' ? lbl.contextZh : lbl.context) && <p className="text-[12px] text-ink2 mt-1.5 leading-relaxed">{getAppLang()==='zh' ? (lbl.contextZh||lbl.context) : lbl.context}</p>}
                </div>
              );
            })()}
            {sel.desc && <p className="text-[13px] text-ink2 leading-relaxed">{sel.desc}</p>}
            <div className="grid grid-cols-2 gap-3">
              <div className="rounded-[12px] border border-line bg-sunken p-3"><div className="text-[10.5px] uppercase tracking-wide text-ink3">{tr('Glyph', '字形')}</div><div className="font-mono text-[13px] text-ink mt-0.5 truncate">{sel.icon}</div></div>
              <div className="rounded-[12px] border border-line bg-sunken p-3"><div className="text-[10.5px] uppercase tracking-wide text-ink3">{tr('References', '引用')}</div><div className="text-[18px] font-semibold text-ink tabular-nums leading-none mt-1">{sel.used}</div></div>
            </div>
            {sel.keywords.length > 0 && (
              <div><div className="text-[11px] uppercase tracking-wide text-ink3 mb-1.5">{tr('Keywords', '关键词')}</div>
                <div className="flex flex-wrap gap-1.5">{sel.keywords.map(k => <span key={k} className="h-6 px-2 rounded-[4px] bg-sunken border border-line text-[11.5px] text-ink2 inline-flex items-center">{k}</span>)}</div></div>
            )}
            {sel.usedBy.length > 0 && (
              <div><div className="text-[11px] uppercase tracking-wide text-ink3 mb-1.5">{tr('Used in', '使用场景')}</div>
                <div className="flex flex-wrap gap-1.5">{sel.usedBy.map(u => <span key={u} className="h-6 px-2 rounded-[4px] bg-sunken border border-line text-[11.5px] text-ink2 inline-flex items-center">{u}</span>)}</div></div>
            )}
            <div className="grid grid-cols-2 gap-2 pt-1">
              <Button variant="secondary" icon="copy" onClick={() => copyText(sel.id, tr('Copied name', '已复制名称'))}>{tr('Copy name', '复制名称')}</Button>
              <Button variant="secondary" icon="copy" onClick={() => copyText('<Icon name="' + sel.icon + '" size={' + size + '} />', tr('Copied component', '已复制组件'))}>{tr('Copy component', '复制组件')}</Button>
              <Button variant="secondary" icon="hash" onClick={() => copyText(iconSvgString(previewRef.current && previewRef.current.querySelector('svg'), color), tr('Copied SVG', '已复制 SVG'))}>{tr('Copy SVG', '复制 SVG')}</Button>
              <Button variant="primary" icon="download" onClick={() => siteDownload(sel.id + '.svg', iconSvgString(previewRef.current && previewRef.current.querySelector('svg'), color), 'image/svg+xml')}>{tr('Download', '下载')}</Button>
            </div>
          </div>
        </aside>
      )}

      {toast && (
        <div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[80] inline-flex items-center gap-2 h-10 px-4 rounded-[12px] bg-[#1D1D1F] text-white text-[13px] shadow-[0_8px_28px_rgba(0,0,0,0.25)]" style={{ animation: 'fadeIn 140ms ease' }}>
          <Icon name="check" size={15} />{toast}
        </div>
      )}
    </div>
  );
}

/* front-end shell */
/* theme-scope chips for a copy/term — "All themes" or the named themes it applies to */
function CopyThemeScope({ themes }) {
  const list = (themes && themes.length) ? themes : ['all'];
  if (list.includes('all')) return <span className="inline-flex items-center h-[20px] px-2 rounded-[4px] text-[11px] font-medium bg-sunken border border-line text-ink3 shrink-0">{tr('All themes','全部主题')}</span>;
  const map = (typeof THEMES !== 'undefined') ? Object.fromEntries(THEMES.map(t => [t.id, t])) : {};
  return <span className="inline-flex items-center gap-1 shrink-0">{list.map(id => { const t = map[id]; return <span key={id} className="inline-flex items-center gap-1 h-[20px] pl-1.5 pr-2 rounded-[4px] text-[11px] font-medium bg-sunken border border-line text-ink2"><span className="w-1.5 h-1.5 rounded-full" style={{ background: t ? t.accent[500] : 'var(--text-3)' }} />{t ? t.name : id}</span>; })}</span>;
}
/* CopySpec — atomic teaching block: surface chip + EN/中文 cards (copy-on-hover) + context + good/bad */
function CopySpec({ item: c }) {
  const zh = getAppLang() === 'zh';
  const [copied, setCopied] = useStateST(null);
  const copy = (which, text) => { try { navigator.clipboard.writeText(text); } catch (e) {} setCopied(which); setTimeout(() => setCopied(x => x === which ? null : x), 1200); };
  return (
    <div className="rounded-[12px] border border-line bg-panel p-5">
      <div className="flex items-center gap-2 mb-3">
        <span className="inline-flex items-center h-[20px] px-2 rounded-[4px] text-[11px] font-medium bg-sunken border border-line text-ink2">{surfaceLabel(c.surface)}</span>
        <span className="font-mono text-[11.5px] text-ink3 truncate flex-1">{c.key}</span>
        <CopyThemeScope themes={c.themes} />
      </div>
      <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
        {[['EN', c.en, 'en'], ['中文', c.zh, 'zh']].map(([lab, val, k]) => (
          <div key={k} className="group relative rounded-[12px] border border-line bg-sunken px-3.5 py-3">
            <div className="text-[10.5px] uppercase tracking-wide text-ink3 mb-1">{lab}</div>
            <div className="text-[14px] text-ink leading-snug pr-5 break-words">{val}</div>
            <button onClick={() => copy(k, val)} title={tr('Copy', '复制')} className="absolute top-2.5 right-2.5 text-ink3 hover:text-accent transition">
              <Icon name={copied === k ? 'check' : 'copy'} size={13} className={copied === k ? 'text-success' : ''} />
            </button>
          </div>
        ))}
      </div>
      {(c.context || c.contextZh) && <p className="text-[12.5px] text-ink2 mt-3 leading-relaxed">{zh ? (c.contextZh || c.context) : c.context}</p>}
      {(c.good || c.bad) && (
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-7 gap-y-1.5 mt-3 pt-3 border-t border-line">
          {c.good && <div className="flex items-start gap-2 text-[12.5px]"><Icon name="check" size={14} className="text-success shrink-0 mt-0.5" /><span className="text-ink2">{zh ? (c.goodZh || c.good) : c.good}</span></div>}
          {c.bad && <div className="flex items-start gap-2 text-[12.5px]"><Icon name="close" size={14} className="text-danger shrink-0 mt-0.5" /><span className="text-ink3 line-through">{zh ? (c.badZh || c.bad) : c.bad}</span></div>}
        </div>
      )}
    </div>
  );
}

/* public Content / 内容规范 — voice&tone + word list + messages catalog */
function SiteContent({ ctx }) {
  const zh = getAppLang() === 'zh';
  const guides = (typeof GUIDES !== 'undefined' ? GUIDES : []).slice().sort((a, b) => a.order - b.order);
  const [sel, setSel] = useStateST(guides[0] ? 'g:' + guides[0].id : 'glossary');
  const [q, setQ] = useStateST('');
  const [cq, setCq] = useStateST('');          // UI-strings search
  const [csurf, setCsurf] = useStateST('all');  // UI-strings type filter
  const guideCats = Array.from(new Set(guides.map(g => g.category)));
  const railBtn = (on) => cx('w-full text-left px-4 h-8 text-[13px] transition truncate', on ? 'text-accent bg-accentWeak font-medium' : 'text-ink2 hover:text-ink hover:bg-hover');
  const themeId = (ctx && ctx.theme && ctx.theme.id) || 'all';
  const inTheme = (x) => { const ts = x.themes || ['all']; return ts.includes('all') || ts.includes(themeId); };
  const terms = (typeof GLOSSARY !== 'undefined' ? GLOSSARY : []).filter(inTheme).filter(g => !q || (g.term + ' ' + g.termZh + ' ' + g.def + ' ' + g.defZh).toLowerCase().includes(q.toLowerCase()));
  // full string registry (theme-filtered + searched/filtered), grouped by type — mirrors the admin Content → Copy strings list
  const allCopy = (typeof COPY !== 'undefined' ? COPY : []).filter(inTheme)
    .filter(c => csurf === 'all' || c.surface === csurf)
    .filter(c => !cq || (c.key + ' ' + c.en + ' ' + c.zh + ' ' + (c.context || '')).toLowerCase().includes(cq.toLowerCase()));
  const copySurfacesPresent = (typeof COPY_SURFACES !== 'undefined' ? COPY_SURFACES : []).filter(s => (typeof COPY !== 'undefined' ? COPY : []).filter(inTheme).some(c => c.surface === s));
  const copyBySurface = (typeof COPY_SURFACES !== 'undefined' ? COPY_SURFACES : []).map(s => ({ s, items: allCopy.filter(c => c.surface === s) })).filter(grp => grp.items.length);
  return (
    <div className="flex-1 min-h-0 flex">
      <div className="w-[240px] shrink-0 border-r border-line overflow-y-auto ds-scroll-hover py-3 bg-[color:var(--bg-rail)]">
        {guideCats.map(cat => (
          <div key={cat} className="mb-2">
            <div className="px-4 py-1 text-[11px] uppercase tracking-wide text-ink3">{cat}</div>
            {guides.filter(g => g.category === cat).map(g => (
              <button key={g.id} onClick={() => setSel('g:' + g.id)} className={railBtn(sel === 'g:' + g.id)}>{tr(g.title, g.titleZh)}</button>
            ))}
          </div>
        ))}
        <div className="mb-2">
          <div className="px-4 py-1 text-[11px] uppercase tracking-wide text-ink3">{tr('Reference', '参考')}</div>
          <button onClick={() => setSel('glossary')} className={railBtn(sel === 'glossary')}>{tr('Word list', '术语表')}</button>
          <button onClick={() => setSel('messages')} className={railBtn(sel === 'messages')}>{tr('UI strings', '界面文案')}</button>
        </div>
      </div>
      <div className="flex-1 overflow-y-auto ds-scroll">
        <div className="max-w-[860px] mx-auto px-10 py-8">
          {sel.indexOf('g:') === 0 && (() => { const g = GUIDES.find(x => x.id === sel.slice(2)); return g ? <MarkdownDoc md={zh ? (g.bodyZh || g.body) : g.body} /> : null; })()}

          {sel === 'glossary' && (
            <div>
              <h1 className="text-[28px] font-semibold text-ink tracking-tight mb-1">{tr('Word list', '术语表')}</h1>
              <p className="text-[14px] text-ink2 mb-5">{tr('Preferred terms with meanings, in both languages. Use the preferred form; avoid the struck-through synonyms.', '中英对照的首选术语与含义。请使用首选写法,避免划掉的近义词。')}</p>
              <div className="relative w-[300px] max-w-full mb-5">
                <Icon name="search" size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink3" />
                <input value={q} onChange={e => setQ(e.target.value)} placeholder={tr('Search terms…', '搜索术语…')} className="w-full h-10 bg-panel border border-line rounded-[12px] pl-9 pr-3 text-[14px] text-ink focus-ring focus:border-line2" />
              </div>
              <div className="rounded-[12px] border border-line overflow-hidden">
                <table className="w-full table-fixed border-collapse text-[13px]">
                  <colgroup><col className="w-[15%]" /><col className="w-[15%]" /><col className="w-[34%]" /><col className="w-[16%]" /><col className="w-[20%]" /></colgroup>
                  <thead><tr className="bg-sunken border-b border-line text-left">{[tr('Term', '术语'), '中文', tr('Meaning', '释义'), tr('Avoid', '避免'), tr('Theme scope', '适用主题')].map(h => <th key={h} className="px-4 h-9 font-medium text-[11px] uppercase tracking-wide text-ink3">{h}</th>)}</tr></thead>
                  <tbody>
                    {terms.map(g => (
                      <tr key={g.id} className="border-b border-[color:var(--border)] last:border-0 align-top">
                        <td className="px-4 py-2.5"><span className="inline-flex items-center gap-1.5"><span className="font-medium text-ink break-words">{g.term}</span>{g.preferred && <span className="text-[9px] font-semibold px-1 rounded text-success shrink-0" style={{ background: 'rgba(30,135,75,0.12)' }}>{tr('USE', '推荐')}</span>}</span></td>
                        <td className="px-4 py-2.5 text-ink break-words">{g.termZh}</td>
                        <td className="px-4 py-2.5 text-ink2">{zh ? g.defZh : g.def}</td>
                        <td className="px-4 py-2.5">{g.avoid.map((a, i) => <span key={i} className="text-ink3 line-through mr-1.5 text-[12px]">{a}</span>)}</td>
                        <td className="px-4 py-2.5 whitespace-nowrap"><CopyThemeScope themes={g.themes} /></td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          )}

          {sel === 'messages' && (
            <div>
              <h1 className="text-[28px] font-semibold text-ink tracking-tight mb-1">{tr('UI strings', '界面文案')}</h1>
              <p className="text-[14px] text-ink2 mb-5">{tr('Every standard UI string in both languages, grouped by type — with when-to-use context and good/avoid examples. Mirrors the Content registry.', '全部标准界面文案,中英对照,按类型分组 —— 附使用场景与推荐/避免示例。与内容规范库一致。')}</p>
              <div className="flex items-center gap-2.5 mb-6 flex-wrap">
                <div className="relative w-[280px] max-w-full">
                  <Icon name="search" size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink3" />
                  <input value={cq} onChange={e => setCq(e.target.value)} placeholder={tr('Search key, text, context…', '搜索 key、文案、说明…')} className="w-full h-9 bg-panel border border-line rounded-[10px] pl-9 pr-3 text-[13.5px] text-ink focus-ring focus:border-line2" />
                </div>
                <select value={csurf} onChange={e => setCsurf(e.target.value)} className="h-9 bg-panel border border-line rounded-[10px] px-2.5 text-[13px] text-ink focus-ring">
                  <option value="all">{tr('All types', '全部类型')}</option>
                  {copySurfacesPresent.map(s => <option key={s} value={s}>{surfaceLabel(s)}</option>)}
                </select>
              </div>
              {copyBySurface.length === 0 ? <p className="text-[14px] text-ink3">{(cq || csurf !== 'all') ? tr('No strings match your search.', '没有匹配的文案。') : tr('No strings for this theme yet.', '该主题暂无文案。')}</p> :
                <div className="flex flex-col gap-9">
                  {copyBySurface.map(grp => (
                    <div key={grp.s}>
                      <div className="flex items-center gap-2 mb-3">
                        <h2 className="text-[16px] font-semibold text-ink">{surfaceLabel(grp.s)}</h2>
                        <span className="text-[12.5px] text-ink3 tabular-nums">{grp.items.length}</span>
                      </div>
                      <div className="flex flex-col gap-4">{grp.items.map(c => <CopySpec key={c.key} item={c} />)}</div>
                    </div>
                  ))}
                </div>}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* public AI integration / AI 接入 — the developer-facing AI integration portal.
   Marketing-calm (no admin PageToolbar); reuses the ai-export.jsx window fns. */
function SiteDevCode({ code }) {
  const [copied, setCopied] = useStateST(false);
  const doCopy = () => { try { navigator.clipboard.writeText(code); } catch (e) {} setCopied(true); setTimeout(() => setCopied(false), 1400); };
  return (
    <div className="relative rounded-[12px] border border-line bg-sunken">
      <pre className="m-0 px-4 py-3.5 pr-14 overflow-x-auto ds-scroll text-[12.5px] leading-relaxed font-mono text-ink whitespace-pre">{code}</pre>
      <button onClick={doCopy} title={tr('Copy', '复制')}
        className="absolute top-2.5 right-2.5 inline-flex items-center gap-1 h-7 px-2 rounded-[8px] bg-panel border border-line text-ink2 hover:text-accent hover:border-accent transition text-[11.5px]">
        <Icon name={copied ? 'check' : 'copy'} size={13} className={copied ? 'text-success' : ''} />{copied ? tr('Copied', '已复制') : tr('Copy', '复制')}
      </button>
    </div>
  );
}

function SiteDevelop({ ctx }) {
  const hasAI = typeof aiBundle !== 'undefined';
  const opts = { publishedOnly: true, includeDrafts: false, themes: (typeof THEMES !== 'undefined' ? THEMES : []).map(t => t.id) };
  const counts = hasAI ? aiCounts(opts) : { tokens: 0, components: 0, copy: 0, glossary: 0, icons: 0 };
  const version = hasAI ? aiVersion() : { cycle: '—', date: null };
  const agentsMd = hasAI ? aiAgentsMd(opts) : '';
  const [toast, setToast] = useStateST(null);
  const flash = (m) => { setToast(m); setTimeout(() => setToast(null), 1700); };

  const FILES = [
    ['tokens.json', tr('Tokens (DTCG)', 'Token（DTCG）'), counts.tokens],
    ['components.json', tr('Components', '组件'), counts.components],
    ['copy.json', tr('UI strings', '界面文案'), counts.copy],
    ['glossary.json', tr('Glossary', '术语表'), counts.glossary],
    ['icons.json', tr('Icons', '图标'), counts.icons],
    ['AGENTS.md', tr('Agent rules', '接入规范'), null],
    ['llms.txt', tr('Index', '索引'), null],
  ];
  const mcpSnippet = 'claude mcp add sicarrier \\\n  --env SICARRIER_DIR=/abs/path/to/design-system \\\n  -- node /abs/path/to/sicarrier-mcp.js';

  const dl = (name) => { if (hasAI) { downloadBundleFile(name, opts); flash(tr('Downloaded', '已下载') + ' ' + name); } };

  return (
    <div className="flex-1 overflow-y-auto ds-scroll">
      {/* hero */}
      <section className="max-w-[860px] mx-auto px-8 pt-16 pb-8 text-center">
        <span className="inline-flex items-center gap-1.5 h-7 px-3 rounded-full bg-accentWeak text-accent text-[12.5px] font-medium mb-5"><Icon name="link" size={13} />{tr('AI Platform', 'AI 平台')}</span>
        <h1 className="text-[38px] font-semibold text-ink tracking-tight leading-[1.12]">{tr('Build with AI, on-system', '让 AI 按规范开发')}</h1>
        <p className="text-[16px] text-ink2 mt-4 max-w-[620px] mx-auto leading-relaxed">
          {tr('Give your coding agent the whole design system as a machine-readable bundle — tokens, components, copy, vocabulary and icons — so it builds with the right values instead of guessing.',
            '把整套设计系统作为机器可读的资源包交给你的编码 Agent —— token、组件、文案、术语与图标 —— 让它用正确的值开发，而不是凭空猜测。')}
        </p>
        <div className="flex items-center justify-center gap-3 mt-7">
          <Button variant="primary" size="lg" icon="download" onClick={() => { if (hasAI) { downloadAIBundle(opts); flash(tr('Downloading bundle…', '正在下载…')); } }}>{tr('Download the bundle', '下载资源包')}</Button>
        </div>
        <div className="text-[12.5px] text-ink3 mt-4">{counts.tokens} {tr('tokens', '个 token')} · {counts.components} {tr('components', '个组件')} · {counts.copy} {tr('strings', '条文案')} · {counts.glossary} {tr('terms', '个术语')} · {counts.icons} {tr('icons', '个图标')}</div>
      </section>

      {/* two routes */}
      <section className="max-w-[860px] mx-auto px-8 py-6">
        <h2 className="text-[13px] uppercase tracking-wide text-ink3 mb-4 text-center">{tr('Two ways to connect', '两种接入方式')}</h2>
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div className="rounded-[16px] border border-line bg-panel p-6">
            <span className="w-10 h-10 rounded-[12px] bg-accentWeak text-accent flex items-center justify-center mb-3"><Icon name="download" size={20} /></span>
            <h3 className="text-[16px] font-semibold text-ink">{tr('1 · Drop files into your repo', '1 · 放入你的仓库')}</h3>
            <p className="text-[13px] text-ink2 mt-1.5 leading-relaxed">{tr('Download the bundle, commit the folder, and put AGENTS.md at the repo root. Your agent reads the JSON directly.', '下载资源包，提交该文件夹，并把 AGENTS.md 放在仓库根目录。Agent 会直接读取这些 JSON。')}</p>
            <div className="mt-4"><SiteDevCode code={'design-system/\n  AGENTS.md      # rules — start here\n  tokens.json    # DTCG tokens + themes\n  components.json\n  copy.json  glossary.json  icons.json'} /></div>
          </div>
          <div className="rounded-[16px] border border-line bg-panel p-6">
            <span className="w-10 h-10 rounded-[12px] bg-accentWeak text-accent flex items-center justify-center mb-3"><Icon name="network" size={20} /></span>
            <h3 className="text-[16px] font-semibold text-ink">{tr('2 · Connect via MCP', '2 · 通过 MCP 接入')}</h3>
            <p className="text-[13px] text-ink2 mt-1.5 leading-relaxed">{tr('Run the bundled server so the agent can query the system live — resolve tokens, look up components, and lint code against the system.', '运行随附的服务，让 Agent 实时查询系统 —— 解析 token、查找组件，并按规范校验代码。')}</p>
            <div className="mt-4"><SiteDevCode code={'npm i @modelcontextprotocol/sdk zod'} /></div>
            <div className="mt-2.5"><SiteDevCode code={mcpSnippet} /></div>
            <div className="flex flex-wrap gap-1.5 mt-3">
              {['resolve_token', 'get_component', 'search_components', 'get_copy', 'search_glossary', 'find_icon', 'lint_against_system'].map(t => (
                <span key={t} className="inline-flex items-center h-[22px] px-2 rounded-[6px] bg-sunken border border-line font-mono text-[11px] text-ink2">{t}</span>
              ))}
            </div>
          </div>
        </div>
      </section>

      {/* bundle download grid */}
      <section className="max-w-[860px] mx-auto px-8 py-6">
        <h2 className="text-[18px] font-semibold text-ink mb-1">{tr('The bundle', '资源包内容')}</h2>
        <p className="text-[13.5px] text-ink2 mb-4 leading-relaxed">{tr('Each file is generated from the live system. Download the whole bundle or grab one file.', '每个文件都从在线系统实时生成。可下载整包，也可单独获取某个文件。')}</p>
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-2.5">
          {FILES.map(([name, label, count]) => (
            <button key={name} onClick={() => dl(name)}
              className="group flex items-center gap-3 rounded-[12px] border border-line bg-panel px-4 py-3 hover:border-accent hover:shadow-[0_4px_16px_rgba(0,0,0,0.05)] transition text-left">
              <span className="w-9 h-9 rounded-[10px] bg-sunken border border-line flex items-center justify-center text-ink3 group-hover:text-accent shrink-0"><Icon name={/\.json$/.test(name) ? 'hash' : 'edit'} size={16} /></span>
              <span className="flex-1 min-w-0">
                <span className="block font-mono text-[13px] text-ink">{name}</span>
                <span className="block text-[12px] text-ink3 mt-0.5">{label}{count != null ? ' · ' + count : ''}</span>
              </span>
              <Icon name="download" size={16} className="text-ink3 group-hover:text-accent shrink-0" />
            </button>
          ))}
          <button onClick={() => dl('sicarrier-mcp.js')}
            className="group flex items-center gap-3 rounded-[12px] border border-line bg-panel px-4 py-3 hover:border-accent hover:shadow-[0_4px_16px_rgba(0,0,0,0.05)] transition text-left">
            <span className="w-9 h-9 rounded-[10px] bg-sunken border border-line flex items-center justify-center text-ink3 group-hover:text-accent shrink-0"><Icon name="network" size={16} /></span>
            <span className="flex-1 min-w-0">
              <span className="block font-mono text-[13px] text-ink">sicarrier-mcp.js</span>
              <span className="block text-[12px] text-ink3 mt-0.5">{tr('MCP server', 'MCP 服务')}</span>
            </span>
            <Icon name="download" size={16} className="text-ink3 group-hover:text-accent shrink-0" />
          </button>
        </div>
      </section>

      {/* what AI sees */}
      <section className="max-w-[860px] mx-auto px-8 py-6">
        <h2 className="text-[18px] font-semibold text-ink mb-1">{tr('What the agent reads', 'Agent 读到的内容')}</h2>
        <p className="text-[13.5px] text-ink2 mb-4 leading-relaxed">{tr('The exact AGENTS.md the bundle ships with — the rules your agent follows.', '资源包内附的 AGENTS.md 原文 —— Agent 将遵循的规则。')}</p>
        <div className="rounded-[14px] border border-line bg-panel px-6 py-5 max-h-[460px] overflow-y-auto ds-scroll">
          <MarkdownDoc md={agentsMd} />
        </div>
      </section>

      <footer className="border-t border-line mt-6 py-8 text-center text-[12.5px] text-ink3">
        {SESSION.product} · {tr('AI Platform', 'AI 平台')} · {tr('Bundle', '版本')} {version.cycle}{version.date ? ' · ' + version.date : ''}
      </footer>

      {toast && (
        <div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[80] inline-flex items-center gap-2 h-10 px-4 rounded-[12px] bg-[#1D1D1F] text-white text-[13px] shadow-[0_8px_28px_rgba(0,0,0,0.25)]" style={{ animation: 'fadeIn 140ms ease' }}>
          <Icon name="check" size={15} />{toast}
        </div>
      )}
    </div>
  );
}

function SiteShell({ ctx, role, onEnterAdmin, lang, onSetLang }) {
  // deep-link: a valid ?theme=<id|name> (not the default 'site') opens Guidelines previewing that brand.
  // The site chrome itself ALWAYS stays the red 'site' theme — the preview is scoped to Guidelines.
  const deepTheme = useMemoST(() => {
    try {
      const all = (typeof THEMES !== 'undefined') ? THEMES : [];
      const p = new URLSearchParams(window.location.search).get('theme');
      if (!p) return null;
      const f = all.find(t => t.id === p) || all.find(t => (t.name || '').toLowerCase() === p.toLowerCase());
      return (f && f.id !== 'site') ? f : null;
    } catch (e) { return null; }
  }, []);
  const [page, setPage] = useStateST(deepTheme ? 'spec' : 'home');
  const [loggedIn, setLoggedIn] = useStateST(true);
  return (
    <SiteThemeVars>
      <div className="site-surface h-full flex flex-col bg-app text-ink">
        <SiteNav page={page} setPage={setPage} role={role} onEnterAdmin={onEnterAdmin}
          lang={lang} onSetLang={onSetLang}
          loggedIn={loggedIn} onLogin={() => setLoggedIn(true)} onLogout={() => setLoggedIn(false)} />
        {page === 'home' ? <SiteHome setPage={setPage} /> : page === 'icons' ? <SiteIcons /> : page === 'content' ? <SiteContent ctx={ctx} /> : page === 'develop' ? <SiteDevelop ctx={ctx} /> : <SiteSpec ctx={ctx} initialTheme={deepTheme} />}
      </div>
    </SiteThemeVars>
  );
}

Object.assign(window, { SiteShell, SiteTokenDoc });
