/* ContentPage.jsx — admin "Content / 文案" module. Three sub-tabs:
   Guidelines (prose, MarkdownDoc + upload), Copy strings (the registry, list+drawer),
   Glossary (bilingual word-list, table+drawer). Edits route through the Changes flow
   via onSaveContent(change). No CMS, no rich editor — reuses every existing primitive. */
const { useState: useStateCN } = React;

const GUIDE_CATS = ['Foundations', 'English', 'Grammar', 'Inclusive', 'Localization'];
const GLOSS_CATS = ['Actions', 'Equipment', 'Status', 'Navigation', 'Domain'];
function subTabs(tab, setTab) {
  return <Segmented size="sm" value={tab} onChange={setTab} options={[
    { value:'guides',   label:tr('Guidelines','规范') },
    { value:'copy',     label:tr('Copy strings','文案字符串') },
    { value:'glossary', label:tr('Glossary','术语表') },
  ]} />;
}
function SurfaceChip({ surface }) {
  return <span className="inline-flex items-center h-[18px] px-1.5 rounded-[4px] text-[10px] font-medium bg-sunken border border-line text-ink2 shrink-0">{surfaceLabel(surface)}</span>;
}
const THEME_MAP_LOCAL = () => (typeof THEMES !== 'undefined') ? Object.fromEntries(THEMES.map(t => [t.id, t])) : {};
/* row/card display of a copy/term's applicable theme scope */
function ThemeScope({ themes }) {
  const list = (themes && themes.length) ? themes : ['all'];
  if (list.includes('all')) return <span className="inline-flex items-center h-[18px] px-1.5 rounded-[4px] text-[10px] font-medium bg-sunken border border-line text-ink3 shrink-0">{tr('All themes','全部主题')}</span>;
  const map = THEME_MAP_LOCAL();
  return <span className="inline-flex items-center gap-1 shrink-0 flex-wrap justify-end">{list.map(id => { const t = map[id]; return <span key={id} className="inline-flex items-center gap-1 h-[18px] pl-1 pr-1.5 rounded-[4px] text-[10px] 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>;
}
/* multi-select theme scope picker used in the copy / term drawers */
function ThemeMultiSelect({ value, onChange }) {
  const themes = (typeof THEMES !== 'undefined') ? THEMES : [];
  const v = (value && value.length) ? value : ['all'];
  const isAll = v.includes('all');
  const chip = (on) => cx('inline-flex items-center h-7 px-2.5 rounded-[7px] text-[12px] font-medium transition border', on ? 'bg-accentWeak text-accent border-[color:var(--accent)]/30' : 'bg-panel text-ink2 border-line hover:text-ink');
  const toggle = (id) => { let next = isAll ? [] : v.slice(); next = next.includes(id) ? next.filter(x => x !== id) : next.concat(id); if (!next.length) next = ['all']; onChange(next); };
  return (
    <div className="flex items-center gap-1.5 flex-wrap">
      <button type="button" onClick={() => onChange(['all'])} className={chip(isAll)}>{tr('All themes','全部主题')}</button>
      {themes.map(t => <button type="button" key={t.id} onClick={() => toggle(t.id)} className={chip(!isAll && v.includes(t.id))}><span className="w-2 h-2 rounded-full mr-1.5" style={{ background: t.accent[500] }} />{t.name}</button>)}
    </div>
  );
}

/* one-line explanation strip, shown directly under the toolbar (below the filters) */
function ViewIntro({ children }) {
  return <div className="shrink-0 px-6 py-2 bg-sunken border-b border-line text-[12.5px] text-ink2 leading-relaxed">{children}</div>;
}

/* ============ COPY STRINGS (the registry) ============ */
function CopyView({ tab, setTab, onSave, focusKey, ctx }) {
  const defTheme = (ctx && ctx.theme && ctx.theme.id) || 'any';
  const [q, setQ] = useStateCN('');
  const [filters, setFilters] = useStateCN({ surface:'all', theme: defTheme, status:'all' });
  const [sel, setSel] = useStateCN(null);
  const [rev, setRev] = useStateCN(0);
  React.useEffect(() => { if (focusKey && focusKey.tab === 'copy' && focusKey.key) { const c = COPY_MAP[focusKey.key]; if (c) setSel(c); } }, [focusKey]);

  const inTheme = (c) => { const ts = c.themes || ['all']; return filters.theme === 'any' || ts.includes('all') || ts.includes(filters.theme); };
  const rows = COPY.filter(c =>
    (filters.surface === 'all' || c.surface === filters.surface) &&
    inTheme(c) &&
    (filters.status === 'all' || c.status === filters.status) &&
    (!q || (c.key + ' ' + c.en + ' ' + c.zh + ' ' + c.context).toLowerCase().includes(q.toLowerCase())))
    .sort((a, b) => (a.status === 'new' ? 0 : 1) - (b.status === 'new' ? 0 : 1)); // newly-created float to the top

  const themeOpts = [['any', tr('All themes','全部主题')]].concat((typeof THEMES!=='undefined'?THEMES:[]).map(t => [t.id, t.name]));
  const filterGroups = [
    { key:'surface', label:tr('Type','类型'),       opts: [['all', tr('All types','全部类型')]].concat(COPY_SURFACES.map(s => [s, surfaceLabel(s)])) },
    { key:'theme',   label:tr('Theme scope','适用主题'), opts: themeOpts },
    { key:'status',  label:tr('Status','状态'),       opts: [['all',tr('All','全部')],['published',tr('Published','已发布')],['new',tr('New','新增')],['modified',tr('Modified','修改')],['deprecated',tr('Deprecated','废弃')]] },
  ];
  const newItem = () => setSel({ key:'', surface:'button', en:'', zh:'', context:'', contextZh:'', componentId:null, themes:['all'], good:'', bad:'', status:'new', isNew:true });

  return (
    <div className="h-full flex flex-col">
      <PageToolbar title={tr('Content','文案')} count={rows.length}
        leadingActions={<>{subTabs(tab, setTab)}<Button variant="primary" size="sm" icon="plus" disabled={!canEdit()} onClick={newItem}>{tr('New string','新建文案')}</Button></>}
        search={{ value:q, onChange:setQ, placeholder:tr('Search key, text, context…','搜索 key、文案、说明…') }}
        filters={{ groups:filterGroups, value:filters, onChange:setFilters }} />
      <ViewIntro>{tr('The literal UI text shipped in products — edit each string’s wording.','产品里真实使用的 UI 文本 —— 逐条编辑文案措辞。')}</ViewIntro>
      <div className="flex-1 overflow-y-auto ds-scroll bg-panel">
        {rows.length === 0 ? <EmptyState icon="edit" title={tr('No strings match','没有匹配的文案')} body={tr('Try a different filter or search.','换个筛选或搜索词试试。')} />
          : rows.map(c => {
            const rail = { new:'border-[color:var(--success)]', modified:'border-[color:var(--accent)]', renamed:'border-[color:var(--accent)]', deprecated:'border-[color:var(--border-strong)]' }[c.status] || 'border-transparent';
            const showZh = c.zh && c.zh !== c.en;
            const link = c.componentId || c.iconId;
            return (
            <button key={c.key} onClick={()=>setSel(c)}
              className={cx('group w-full text-left flex flex-col gap-1 pl-5 pr-4 py-3 min-h-[64px] border-b border-[color:var(--border)] border-l-2 transition hover:bg-hover', rail, sel && sel.key === c.key && 'bg-[color:var(--selected)]')}>
              {/* EN headline — always the stable lead line; wraps fully so long strings are readable without hovering */}
              <div className="text-[14px] font-medium text-ink leading-snug break-words">{c.en}</div>
              {/* 中文 companion — skipped when identical (e.g. "99+") */}
              {showZh && <div className="text-[12.5px] text-ink2 leading-snug break-words">{c.zh}</div>}
              {/* quiet meta footer: key · type · scope · [link] · status */}
              <div className="flex items-center gap-2 mt-0.5">
                <span className="inline-flex items-center gap-1 min-w-0 text-ink3"><Icon name="hash" size={11} className="shrink-0" /><span className="font-mono text-[11.5px] truncate">{c.key}</span></span>
                <SurfaceChip surface={c.surface} />
                <ThemeScope themes={c.themes} />
                {link && <span className="inline-flex items-center gap-1 h-[18px] px-1.5 rounded-[4px] text-[10px] font-mono bg-sunken border border-line text-ink3 shrink-0"><Icon name={c.iconId ? 'image' : 'component'} size={11} />{link}</span>}
                <span className="ml-auto shrink-0">{c.status !== 'published' && <StatusTag status={c.status} />}</span>
              </div>
            </button>
          );})}
      </div>
      {sel && <CopyDrawer item={sel} onClose={()=>setSel(null)} onSave={onSave} bump={()=>setRev(r=>r+1)} />}
    </div>
  );
}

function CopyDrawer({ item, onClose, onSave, bump }) {
  const [d, setD] = useStateCN(() => ({ ...item }));
  const set = (k, v) => setD(x => ({ ...x, [k]:v }));
  const isNew = !!item.isNew;
  const valid = d.key.trim() && d.en.trim() && d.zh.trim();
  const compOpts = (typeof COMPONENTS !== 'undefined') ? COMPONENTS.map(c => c.id) : [];
  function save() {
    const key = d.key.trim();
    const row = { key, surface:d.surface, en:d.en, zh:d.zh, context:d.context, contextZh:d.contextZh,
      componentId:d.componentId || null, iconId:d.iconId || null, themes:(d.themes&&d.themes.length)?d.themes:['all'], good:d.good, goodZh:d.goodZh, bad:d.bad, badZh:d.badZh,
      vars:d.vars||[], tags:d.tags||[d.surface], status: isNew ? 'new' : (d.status==='published'?'modified':d.status) };
    const prev = COPY_MAP[key];
    if (prev) { Object.assign(prev, row); } else { COPY.push(row); COPY_MAP[key] = row; }
    onSave({ action: isNew?'added':'modified', target:'copy:'+key, diffType: isNew?'copyNew':'copyEdit',
      from: isNew?undefined:(prev?prev.en:''), to: row.en });
    bump(); onClose();
  }
  return (
    <Drawer open={true} onClose={onClose} width={460}>
      <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">{tr('Copy string','文案字符串')}</div>
          <h2 className="font-mono text-[14px] text-ink truncate">{isNew ? tr('New string','新建文案') : d.key}</h2></div>
        <IconButton name="close" title="Close" onClick={onClose} />
      </div>
      <div className="flex-1 overflow-y-auto ds-scroll p-5 flex flex-col gap-4">
        <Field label={tr('Key','键')} hint={tr('Stable dotted id, e.g. table.empty.title','稳定的点号 id,如 table.empty.title')}>
          <TextInput mono value={d.key} onChange={e=>set('key', e.target.value)} disabled={!isNew} placeholder="surface.context.part" />
        </Field>
        <Field label={tr('Type','类型')}>
          <select value={d.surface} onChange={e=>set('surface', e.target.value)} className="w-full h-8 bg-sunken border border-line rounded-[8px] px-2 text-[13px] text-ink focus-ring">
            {COPY_SURFACES.map(s => <option key={s} value={s}>{surfaceLabel(s)}</option>)}
          </select>
        </Field>
        <div className="grid grid-cols-2 gap-3">
          <Field label="English"><TextArea rows={2} value={d.en} onChange={e=>set('en', e.target.value)} placeholder="Save" /></Field>
          <Field label="中文"><TextArea rows={2} value={d.zh} onChange={e=>set('zh', e.target.value)} placeholder="保存" /></Field>
        </div>
        <Field label={tr('Context — when/where it appears','上下文 —— 何时何处出现')}>
          <TextArea rows={2} value={d.context} onChange={e=>set('context', e.target.value)} />
        </Field>
        <TextArea rows={2} value={d.contextZh} onChange={e=>set('contextZh', e.target.value)} placeholder={tr('Context (中文)','上下文(中文)')} />
        <Field label={tr('Component','组件')}>
          <select value={d.componentId||''} onChange={e=>set('componentId', e.target.value||null)} className="w-full h-8 bg-sunken border border-line rounded-[8px] px-2 text-[13px] text-ink focus-ring">
            <option value="">{tr('— none —','— 无 —')}</option>
            {compOpts.map(id => <option key={id} value={id}>{id}</option>)}
          </select>
        </Field>
        <Field label={tr('Theme scope','适用主题')} hint={tr('Which themes this string applies to. Default = all.','此文案适用的主题范围,默认为全部。')}>
          <ThemeMultiSelect value={d.themes} onChange={v=>set('themes', v)} />
        </Field>
        <div className="grid grid-cols-2 gap-3">
          <Field label={tr('Preferred (good)','推荐写法')}><TextInput value={d.good} onChange={e=>set('good', e.target.value)} /></Field>
          <Field label={tr('Avoid (bad)','避免写法')}><TextInput value={d.bad} onChange={e=>set('bad', e.target.value)} /></Field>
        </div>
      </div>
      <div className="px-5 py-3 border-t border-line flex justify-end gap-2">
        <Button variant="ghost" onClick={onClose}>{tr('Cancel','取消')}</Button>
        <Button variant="primary" icon="check" disabled={!valid || !canEdit()} onClick={save}>{isNew?tr('Add','新增'):tr('Save draft','保存草稿')}</Button>
      </div>
    </Drawer>
  );
}

/* ============ GUIDELINES (prose) ============ */
function GuidesView({ tab, setTab, onSave, focusKey }) {
  const zh = getAppLang() === 'zh';
  const [sel, setSel] = useStateCN(GUIDES[0] ? GUIDES[0].id : null);
  const [drawer, setDrawer] = useStateCN(null); // null | { mode:'create' } | { mode:'edit', guide }
  const [rev, setRev] = useStateCN(0);
  React.useEffect(() => { if (focusKey && focusKey.tab === 'guides' && focusKey.key) setSel(focusKey.key); }, [focusKey]);
  const g = GUIDES.find(x => x.id === sel);
  const lang = zh ? 'bodyZh' : 'body';
  async function onMd(e) { const md = await processMdFiles(e.target.files); e.target.value=''; if (md != null && g) { g[lang] = md; g.status = g.status==='published'?'modified':g.status; onSave({ action:'modified', target:'guide:'+g.id, diffType:'contentDoc', summary:'Edited '+(g.title)+' ('+(zh?'中文':'EN')+')' }); setRev(r=>r+1); } }
  function persistGuide(d, existing) {
    const cat = d.category.trim();
    if (cat && !GUIDE_CATS.includes(cat)) GUIDE_CATS.push(cat);
    if (existing) {
      existing.title = d.title.trim(); existing.titleZh = d.titleZh.trim() || d.title.trim(); existing.category = cat;
      if (existing.status === 'published') existing.status = 'modified';
      onSave({ action:'modified', target:'guide:'+existing.id, diffType:'contentDoc', summary:'Edited guide “'+existing.title+'”' });
      setSel(existing.id);
    } else {
      let id = (d.title.trim().toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/(^-|-$)/g,'')) || ('guide-'+(GUIDES.length+1));
      while (GUIDES.some(x=>x.id===id)) id += '-1';
      const maxOrder = Math.max(0, ...GUIDES.filter(x=>x.category===cat).map(x=>x.order||0));
      const ng = { id, title:d.title.trim(), titleZh:d.titleZh.trim()||d.title.trim(), category:cat, order:maxOrder+1,
        body:'# '+d.title.trim()+'\n\n'+tr('_Upload a .md file to populate this guide._','_上传 .md 文件以填充本规范。_'),
        bodyZh:'# '+(d.titleZh.trim()||d.title.trim())+'\n\n'+tr('_Upload a .md file to populate this guide._','_上传 .md 文件以填充本规范。_'), status:'new', updated:'2026-06-08' };
      GUIDES.push(ng);
      onSave({ action:'added', target:'guide:'+id, diffType:'contentDoc', summary:'Added guide “'+ng.title+'” ('+cat+')' });
      setSel(id);
    }
    setDrawer(null); setRev(r=>r+1);
  }
  function deleteGuide(gg) {
    const i = GUIDES.findIndex(x=>x.id===gg.id); if (i>=0) GUIDES.splice(i,1);
    onSave({ action:'removed', target:'guide:'+gg.id, diffType:'contentDoc', summary:'Removed guide “'+gg.title+'”' });
    if (sel===gg.id) setSel(GUIDES[0]?GUIDES[0].id:null);
    setDrawer(null); setRev(r=>r+1);
  }
  function renameCategory(c) {
    const n = (window.prompt(tr('Rename category','重命名分类'), c) || '').trim();
    if (!n || n===c) return;
    GUIDES.forEach(x=>{ if (x.category===c) x.category=n; });
    const i=GUIDE_CATS.indexOf(c); if (i>=0) GUIDE_CATS[i]=n; else GUIDE_CATS.push(n);
    onSave({ action:'modified', target:'guide-cat:'+n, diffType:'contentDoc', summary:'Renamed category “'+c+'” → “'+n+'”' });
    setRev(r=>r+1);
  }
  function deleteCategory(c) {
    const inCat = GUIDES.filter(x=>x.category===c);
    if (!window.confirm(tr('Delete category “'+c+'” and its '+inCat.length+' document(s)?','删除分类「'+c+'」及其 '+inCat.length+' 篇文档?'))) return;
    for (let i=GUIDES.length-1;i>=0;i--){ if (GUIDES[i].category===c) GUIDES.splice(i,1); }
    const ci=GUIDE_CATS.indexOf(c); if (ci>=0) GUIDE_CATS.splice(ci,1);
    onSave({ action:'removed', target:'guide-cat:'+c, diffType:'contentDoc', summary:'Removed category “'+c+'” ('+inCat.length+' docs)' });
    if (g && g.category===c) setSel(GUIDES[0]?GUIDES[0].id:null);
    setRev(r=>r+1);
  }
  return (
    <div className="h-full flex flex-col">
      <PageToolbar title={tr('Content','文案')} count={GUIDES.length}
        leadingActions={<>{subTabs(tab, setTab)}
          {canEdit() && <Button variant="primary" size="sm" icon="plus" onClick={()=>setDrawer({ mode:'create' })}>{tr('New guide','新建规范')}</Button>}
          {canEdit() && g && <Button variant="secondary" size="sm" icon="edit" onClick={()=>setDrawer({ mode:'edit', guide:g })}>{tr('Edit','编辑')}</Button>}
          {canEdit() && g && (
          <label className="inline-flex items-center gap-1.5 h-7 px-2.5 rounded-[7px] text-[12px] font-medium border border-line text-ink hover:bg-hover cursor-pointer transition shrink-0">
            <Icon name="upload" size={13} />{tr('Replace .md','替换 .md')}<input type="file" accept=".md,.markdown,image/*,video/*,.pdf,.doc,.docx,.ppt,.pptx" multiple className="hidden" onChange={onMd} />
          </label>)}</>} />
      <ViewIntro>{tr('Voice, tone & writing principles that sit behind every string.','贯穿所有文案的语气、风格与写作原则。')}</ViewIntro>
      <div className="flex-1 min-h-0 flex">
        <div className="w-[230px] shrink-0 border-r border-line overflow-y-auto ds-scroll py-3 bg-panel">
          {GUIDE_CATS.filter(c => GUIDES.some(g => g.category === c)).map(c => (
            <div key={c} className="mb-2 group/cat">
              <div className="flex items-center gap-0.5 px-4 py-1">
                <span className="text-[11px] uppercase tracking-wide text-ink3 flex-1 truncate">{c}</span>
                {canEdit() && <>
                  <button onClick={()=>renameCategory(c)} title={tr('Rename category','重命名分类')} className="opacity-0 group-hover/cat:opacity-100 text-ink3 hover:text-ink p-0.5 rounded transition"><Icon name="edit" size={12} /></button>
                  <button onClick={()=>deleteCategory(c)} title={tr('Delete category','删除分类')} className="opacity-0 group-hover/cat:opacity-100 text-ink3 hover:text-danger p-0.5 rounded transition"><Icon name="trash" size={12} /></button>
                </>}
              </div>
              {GUIDES.filter(g => g.category === c).sort((a,b)=>a.order-b.order).map(gg => (
                <div key={gg.id} className={cx('group/g w-full flex items-center pr-2 transition', sel===gg.id?'bg-accentWeak':'hover:bg-hover')}>
                  <button onClick={()=>setSel(gg.id)} className={cx('flex-1 min-w-0 text-left pl-4 h-8 text-[13px] flex items-center gap-2', sel===gg.id?'text-accent font-medium':'text-ink2 group-hover/g:text-ink')}>
                    <span className="truncate flex-1">{tr(gg.title, gg.titleZh)}</span>
                    {gg.status!=='published' && <StatusTag status={gg.status} />}
                  </button>
                  {canEdit() && <button onClick={()=>setDrawer({ mode:'edit', guide:gg })} title={tr('Edit','编辑')} className="opacity-0 group-hover/g:opacity-100 text-ink3 hover:text-ink p-0.5 shrink-0 transition"><Icon name="edit" size={12} /></button>}
                </div>
              ))}
            </div>
          ))}
        </div>
        <div className="flex-1 overflow-y-auto ds-scroll">
          {!g ? <EmptyState icon="edit" title={tr('Select a guide','选择一篇规范')} /> :
            <div className="max-w-[760px] mx-auto px-10 py-8"><MarkdownDoc md={g[lang] || g.body} /></div>}
        </div>
      </div>
      {drawer && <GuideDrawer drawer={drawer} onClose={()=>setDrawer(null)} onPersist={persistGuide} onDelete={deleteGuide} />}
    </div>
  );
}

/* create OR edit a guide doc (+ optionally a new category); edit mode adds delete. Content via Replace .md */
function GuideDrawer({ drawer, onClose, onPersist, onDelete }) {
  const editing = drawer.mode === 'edit' ? drawer.guide : null;
  const [d, setD] = useStateCN({ title: editing ? editing.title : '', titleZh: editing ? (editing.titleZh||'') : '', category: editing ? editing.category : (GUIDE_CATS[0] || 'Foundations'), newCat:'' });
  const [confirmDel, setConfirmDel] = useStateCN(false);
  const set = (k, v) => setD(x => ({ ...x, [k]:v }));
  const usingNew = d.category === '__new__';
  const finalCat = usingNew ? d.newCat.trim() : d.category;
  const valid = d.title.trim() && finalCat;
  return (
    <Drawer open={true} onClose={onClose} width={420}>
      <div className="flex items-start justify-between px-5 pt-4 pb-3 border-b border-line">
        <div><div className="text-[11px] uppercase tracking-wide text-ink3 mb-1">{tr('Guideline','规范')}</div>
          <h2 className="text-[15px] font-semibold text-ink">{editing ? tr('Edit guide','编辑规范') : tr('New guide','新建规范')}</h2></div>
        <IconButton name="close" title="Close" onClick={onClose} />
      </div>
      <div className="flex-1 overflow-y-auto ds-scroll p-5 flex flex-col gap-4">
        <div className="grid grid-cols-2 gap-3">
          <Field label={tr('Title','标题')}><TextInput value={d.title} onChange={e=>set('title', e.target.value)} placeholder="Capitalization" /></Field>
          <Field label="中文"><TextInput value={d.titleZh} onChange={e=>set('titleZh', e.target.value)} placeholder="大小写规范" /></Field>
        </div>
        <Field label={tr('Category','分类')} hint={tr('Pick an existing section or create a new one.','选择已有分类或新建一个。')}>
          <select value={d.category} onChange={e=>set('category', e.target.value)} className="w-full h-8 bg-sunken border border-line rounded-[8px] px-2 text-[13px] text-ink focus-ring">
            {GUIDE_CATS.map(c => <option key={c} value={c}>{c}</option>)}
            <option value="__new__">+ {tr('New category…','新建分类…')}</option>
          </select>
        </Field>
        {usingNew && <Field label={tr('New category name','新分类名称')}><TextInput value={d.newCat} onChange={e=>set('newCat', e.target.value)} placeholder="Accessibility" /></Field>}
        {!editing && <p className="text-[12px] text-ink3 leading-relaxed">{tr('After creating, use “Replace .md” to upload the document content (Markdown + images / video / pdf).','创建后,用「替换 .md」上传文档内容(Markdown + 图片 / 视频 / pdf)。')}</p>}
        {editing && <p className="text-[12px] text-ink3 leading-relaxed">{tr('Editing title/category here. Use “Replace .md” to change the document content.','此处修改标题/分类。文档内容请用「替换 .md」更新。')}</p>}
      </div>
      <div className="px-5 py-3 border-t border-line flex items-center gap-2">
        {editing && (confirmDel
          ? <ConfirmInline open={true} label={tr('Delete this guide?','删除该规范?')} onConfirm={()=>onDelete(editing)} onCancel={()=>setConfirmDel(false)} />
          : <Button variant="danger" icon="trash" disabled={!canEdit()} onClick={()=>setConfirmDel(true)}>{tr('Delete','删除')}</Button>)}
        <div className="ml-auto flex items-center gap-2">
          <Button variant="ghost" onClick={onClose}>{tr('Cancel','取消')}</Button>
          <Button variant="primary" icon="check" disabled={!valid || !canEdit()} onClick={()=>onPersist({ title:d.title, titleZh:d.titleZh, category:finalCat }, editing)}>{editing ? tr('Save','保存') : tr('Create','创建')}</Button>
        </div>
      </div>
    </Drawer>
  );
}

/* ============ GLOSSARY (word-list) ============ */
function GlossaryView({ tab, setTab, onSave, focusKey, ctx }) {
  const zh = getAppLang() === 'zh';
  const defTheme = (ctx && ctx.theme && ctx.theme.id) || 'any';
  const [q, setQ] = useStateCN('');
  const [filters, setFilters] = useStateCN({ category:'all', theme: defTheme });
  const [sel, setSel] = useStateCN(null);
  const [rev, setRev] = useStateCN(0);
  React.useEffect(() => { if (focusKey && focusKey.tab === 'glossary' && focusKey.key) { const t = GLOSSARY_MAP[focusKey.key]; if (t) setSel(t); } }, [focusKey]);
  const inTheme = (g) => { const ts = g.themes || ['all']; return filters.theme === 'any' || ts.includes('all') || ts.includes(filters.theme); };
  const rows = GLOSSARY.filter(g =>
    (filters.category === 'all' || g.category === filters.category) &&
    inTheme(g) &&
    (!q || (g.term + ' ' + g.termZh + ' ' + g.def + ' ' + g.defZh + ' ' + g.avoid.join(' ')).toLowerCase().includes(q.toLowerCase())));
  const themeOpts = [['any', tr('All themes','全部主题')]].concat((typeof THEMES!=='undefined'?THEMES:[]).map(t => [t.id, t.name]));
  const filterGroups = [
    { key:'category', label:tr('Category','分类'),    opts: [['all', tr('All','全部')]].concat(GLOSS_CATS.map(c => [c, c])) },
    { key:'theme',    label:tr('Theme scope','适用主题'), opts: themeOpts },
  ];
  const newTerm = () => setSel({ term:'', termZh:'', def:'', defZh:'', category:'Actions', preferred:true, avoid:[], related:[], themes:['all'], status:'new', isNew:true });
  return (
    <div className="h-full flex flex-col">
      <PageToolbar title={tr('Content','文案')} count={rows.length}
        leadingActions={<>{subTabs(tab, setTab)}<Button variant="primary" size="sm" icon="plus" disabled={!canEdit()} onClick={newTerm}>{tr('New term','新建术语')}</Button></>}
        search={{ value:q, onChange:setQ, placeholder:tr('Search term or meaning…','搜索术语或释义…') }}
        filters={{ groups:filterGroups, value:filters, onChange:setFilters }} />
      <ViewIntro>{tr('Preferred vocabulary & meanings — the right word for each concept.','首选用词与含义 —— 每个概念对应的标准说法。')}</ViewIntro>
      <div className="flex-1 overflow-y-auto ds-scroll bg-panel">
        <table className="w-full border-collapse text-[12.5px]">
          <thead className="sticky top-0 z-[1]"><tr className="bg-sunken border-b border-line text-left">
            {[tr('Term','术语'),'中文',tr('Meaning','释义'),tr('Avoid','避免'),tr('Theme scope','适用主题'),''].map((h,i)=><th key={i} className="px-5 h-9 font-medium text-[11px] uppercase tracking-wide text-ink3">{h}</th>)}
          </tr></thead>
          <tbody>
            {rows.map(g => (
              <tr key={g.id} onClick={()=>setSel(g)} className="border-b border-[color:var(--border)] hover:bg-hover transition cursor-pointer">
                <td className="px-5 py-2.5"><span className="inline-flex items-center gap-1.5"><span className="font-medium text-ink">{g.term}</span>{g.preferred && <span className="text-[9px] font-semibold px-1 rounded text-success" style={{background:'rgba(30,135,75,0.12)'}}>{tr('USE','推荐')}</span>}</span></td>
                <td className="px-5 py-2.5 text-ink">{g.termZh}</td>
                <td className="px-5 py-2.5 text-ink2">{zh ? g.defZh : g.def}</td>
                <td className="px-5 py-2.5">{g.avoid.map((a,i)=><span key={i} className="text-ink3 line-through mr-1.5 text-[11.5px]">{a}</span>)}</td>
                <td className="px-5 py-2.5"><ThemeScope themes={g.themes} /></td>
                <td className="px-5 py-2.5 text-right">{g.status!=='published' && <StatusTag status={g.status} />}</td>
              </tr>
            ))}
          </tbody>
        </table>
        {rows.length===0 && <EmptyState icon="search" title={tr('No terms match','没有匹配的术语')} />}
      </div>
      {sel && <TermDrawer item={sel} onClose={()=>setSel(null)} onSave={onSave} bump={()=>setRev(r=>r+1)} />}
    </div>
  );
}

function TermDrawer({ item, onClose, onSave, bump }) {
  const [d, setD] = useStateCN(() => ({ ...item, avoid:[...(item.avoid||[])] }));
  const set = (k, v) => setD(x => ({ ...x, [k]:v }));
  const isNew = !!item.isNew;
  const valid = d.term.trim() && d.termZh.trim();
  function save() {
    const id = item.id || d.term.toLowerCase().replace(/[^a-z0-9]+/g,'-');
    const row = { id, term:d.term, termZh:d.termZh, def:d.def, defZh:d.defZh, category:d.category, preferred:d.preferred, avoid:d.avoid, related:d.related||[], themes:(d.themes&&d.themes.length)?d.themes:['all'], status: isNew?'new':(d.status==='published'?'modified':d.status) };
    const prev = GLOSSARY_MAP[id];
    if (prev) Object.assign(prev, row); else { GLOSSARY.push(row); GLOSSARY_MAP[id] = row; }
    onSave({ action:isNew?'added':'modified', target:'term:'+id, diffType:'contentDoc', summary:'Edited glossary term “'+d.term+'”' });
    bump(); onClose();
  }
  return (
    <Drawer open={true} onClose={onClose} width={420}>
      <div className="flex items-start justify-between px-5 pt-4 pb-3 border-b border-line">
        <div className="text-[14px] font-semibold text-ink">{isNew?tr('New term','新建术语'):d.term}</div>
        <IconButton name="close" title="Close" onClick={onClose} />
      </div>
      <div className="flex-1 overflow-y-auto ds-scroll p-5 flex flex-col gap-4">
        <div className="grid grid-cols-2 gap-3">
          <Field label={tr('Term (preferred)','术语(首选)')}><TextInput value={d.term} onChange={e=>set('term', e.target.value)} /></Field>
          <Field label="中文"><TextInput value={d.termZh} onChange={e=>set('termZh', e.target.value)} /></Field>
        </div>
        <Field label={tr('Meaning','释义')}><TextArea rows={2} value={d.def} onChange={e=>set('def', e.target.value)} /></Field>
        <TextArea rows={2} value={d.defZh} onChange={e=>set('defZh', e.target.value)} placeholder={tr('Meaning (中文)','释义(中文)')} />
        <Field label={tr('Category','分类')}>
          <Segmented size="sm" value={d.category} onChange={v=>set('category', v)} options={GLOSS_CATS.map(c=>({value:c,label:c}))} />
        </Field>
        <Field label={tr('Theme scope','适用主题')} hint={tr('Which themes this term applies to. Default = all.','此术语适用的主题范围,默认为全部。')}>
          <ThemeMultiSelect value={d.themes} onChange={v=>set('themes', v)} />
        </Field>
        <Field label={tr('Avoid these synonyms','避免使用的近义词')}><TagInput value={d.avoid} onChange={v=>set('avoid', v)} disabled={!canEdit()} placeholder={tr('Add synonym to avoid…','添加要避免的近义词…')} /></Field>
      </div>
      <div className="px-5 py-3 border-t border-line flex justify-end gap-2">
        <Button variant="ghost" onClick={onClose}>{tr('Cancel','取消')}</Button>
        <Button variant="primary" icon="check" disabled={!valid || !canEdit()} onClick={save}>{isNew?tr('Add','新增'):tr('Save draft','保存草稿')}</Button>
      </div>
    </Drawer>
  );
}

/* ============ SHELL ============ */
function ContentPage({ ctx, onSaveContent, focusKey, clearFocus }) {
  const [tab, setTab] = useStateCN((focusKey && focusKey.tab) || 'guides');
  React.useEffect(() => { if (focusKey && focusKey.tab) setTab(focusKey.tab); }, [focusKey]);
  const shared = { tab, setTab, onSave:onSaveContent, focusKey, ctx };
  if (tab === 'copy') return <CopyView {...shared} />;
  if (tab === 'glossary') return <GlossaryView {...shared} />;
  return <GuidesView {...shared} />;
}

Object.assign(window, { ContentPage });
