// ─────────────────────────────────────────────────────────────────────
// LOCALIZATION · multi-script catalog metadata management
// ─────────────────────────────────────────────────────────────────────
// Why this exists in ASTRO:
//
//   When you register a work with a foreign society — say JASRAC for a
//   Japanese release, or KOMCA for Korea — they want the work title in
//   the local script, plus a romanization for system interchange.
//   CWR v3 has explicit slots for Original Title, Original Title
//   Translated, and Original Title Romanized. Most publishers leave
//   them blank, which silently caps mechanical collections in those
//   territories: societies can't match a work whose title doesn't
//   appear in their script.
//
//   This screen is the operational surface for that:
//
//   01 COVERAGE      — which works have which translations, gap matrix
//                      across our top earning markets
//   02 GAPS          — prioritized queue: works with revenue in a market
//                      but no localized title yet
//   03 SCRIPTS       — non-Roman names per work, romanization quality
//                      check, alt-titles per language
//   04 LYRIC ADAPTS  — modified / restricted / translated lyric versions
//                      (CWR LYR codes), per language
//   05 ACTIVITY      — translation jobs queue + status
//
// Data sources:
//   astro.work_alt_titles      title_type (CWR), language_id, title
//   astro.work_non_roman_names script (Latn/Hani/Hang/Cyrl/Arab/...)
//   ref.languages              iso_639_1, iso_639_2, native_name
//   ref.lyric_adaptations      MOD / RES / NON ...
// ─────────────────────────────────────────────────────────────────────

const { useState: useLocS, useMemo: useLocM } = React;

// ─────────── Markets we track for localization coverage ────────────
//
// These are the catalog's top mechanical+performance earning territories
// where script/translation matters. ISO 639-1 + ISO 15924 script.
const LOC_MARKETS = [
  { iso: 'JA', flag: '🇯🇵', name: 'Japan',          script: 'Jpan', native: '日本語',      society: 'JASRAC',  earnPct: 14.2 },
  { iso: 'KO', flag: '🇰🇷', name: 'South Korea',    script: 'Hang', native: '한국어',       society: 'KOMCA',   earnPct: 6.8  },
  { iso: 'ZH', flag: '🇨🇳', name: 'China · Greater', script: 'Hans', native: '中文',         society: 'MCSC',    earnPct: 4.1  },
  { iso: 'RU', flag: '🇷🇺', name: 'Russia · CIS',   script: 'Cyrl', native: 'Русский',     society: 'RAO',     earnPct: 1.9  },
  { iso: 'AR', flag: '🇸🇦', name: 'MENA',           script: 'Arab', native: 'العربية',      society: 'SACERAU', earnPct: 2.4  },
  { iso: 'EL', flag: '🇬🇷', name: 'Greece · CY',    script: 'Grek', native: 'Ελληνικά',    society: 'AEPI',    earnPct: 0.6  },
  { iso: 'HE', flag: '🇮🇱', name: 'Israel',         script: 'Hebr', native: 'עברית',        society: 'ACUM',    earnPct: 0.7  },
  { iso: 'TH', flag: '🇹🇭', name: 'Thailand',       script: 'Thai', native: 'ไทย',          society: 'MCT',     earnPct: 0.9  },
  { iso: 'HI', flag: '🇮🇳', name: 'India',          script: 'Deva', native: 'हिन्दी',       society: 'IPRS',    earnPct: 1.1  },
  { iso: 'ES', flag: '🇪🇸', name: 'LATAM · IB',     script: 'Latn', native: 'Español',     society: 'SGAE+',   earnPct: 18.4 },
  { iso: 'PT', flag: '🇧🇷', name: 'Brazil · PT',    script: 'Latn', native: 'Português',   society: 'UBC',     earnPct: 7.2  },
  { iso: 'FR', flag: '🇫🇷', name: 'France · FR',    script: 'Latn', native: 'Français',    society: 'SACEM',   earnPct: 4.6  },
  { iso: 'DE', flag: '🇩🇪', name: 'DACH',           script: 'Latn', native: 'Deutsch',     society: 'GEMA',    earnPct: 5.3  },
];

// Markets that *require* non-Roman script for society registration
const NON_ROMAN_MARKETS = LOC_MARKETS.filter(m => m.script !== 'Latn');

// CWR Title Type codes — astro.work_alt_titles.title_type_cwr
const CWR_TITLE_TYPES = {
  AT:  { code:'AT',  label:'Alternative Title' },
  TE:  { code:'TE',  label:'First Line of Text' },
  FT:  { code:'FT',  label:'Formal Title' },
  IT:  { code:'IT',  label:'Incorrect Title' },
  OT:  { code:'OT',  label:'Original Title' },
  TT:  { code:'TT',  label:'Original Title Translated' },
  PT:  { code:'PT',  label:'Part Title' },
  RT:  { code:'RT',  label:'Restricted Title' },
  ET:  { code:'ET',  label:'Extra Search Title' },
  OL:  { code:'OL',  label:'Original Language' },
};

// CWR Lyric Adaptation codes — ref.lyric_adaptations
const CWR_LYRIC_ADAPTS = [
  { code:'MOD', label:'Modified',        note:'Slight edit · same language',       severity:'low'  },
  { code:'NON', label:'None',            note:'No adaptation — same as original',  severity:'low'  },
  { code:'ORI', label:'Original',        note:'The reference recording lyrics',     severity:'low'  },
  { code:'RES', label:'Restricted',      note:'Restricted to specific territory',   severity:'med'  },
  { code:'TRA', label:'Translation',     note:'Lyrics in a different language',     severity:'med'  },
  { code:'ADL', label:'Adaptation',      note:'Significant lyrical adaptation',     severity:'high' },
  { code:'UNS', label:'Unspecified',     note:'Adaptation type unknown',            severity:'med'  },
];

// ─────────── Deterministic seed per work ──────────────────────────
function locSeed(s) {
  let h = 5381;
  for (let i = 0; i < s.length; i++) h = ((h<<5)+h+s.charCodeAt(i))>>>0;
  return () => { h = (h * 1103515245 + 12345) >>> 0; return h / 4294967296; };
}

// ─────────── Sample local-script titles (deterministic + curated) ─
//
// Real publishing systems hold a few hundred manually-curated
// translations + thousands of machine-romanized ones; we fake this
// distribution with a small curated set + procedural fill.
const CURATED_TITLES = {
  // workIdHash%50 → fake "real" Japanese / Korean / Chinese titles
  // The hash is deterministic, so the same English title always maps
  // to the same local-script "translation" within this session.
  ja: ['夕暮れの空','薄明の街','水面に映る月','遠い記憶','風の便り','静寂のうた','夜の鼓動','金色の朝','溶ける時間','灯火の道',
       '雨上がりの庭','螺旋の光','色のない夢','春の終わり','深海の声'],
  ko: ['저녁 하늘','새벽 도시','달의 그림자','먼 추억','바람의 소식','조용한 노래','밤의 박동','황금빛 아침','녹는 시간','등불의 길',
       '비 온 뒤 정원','나선의 빛','색없는 꿈','봄의 끝','심해의 소리'],
  zh: ['黄昏之空','黎明都市','水中之月','遥远记忆','风之音讯','寂静之歌','夜的脉动','金色清晨','融化的时间','灯火之路',
       '雨后庭院','螺旋之光','无色之梦','春之终焉','深海之声'],
  ru: ['Сумерки неба','Город на рассвете','Луна в воде','Далёкое воспоминание','Голос ветра','Тихая песня','Биение ночи','Золотое утро','Тающее время','Путь огня',
       'Сад после дождя','Свет спирали','Бесцветный сон','Конец весны','Голос глубин'],
  ar: ['سماء الغسق','مدينة الفجر','القمر في الماء','ذكرى بعيدة','رسالة الريح','أغنية صامتة','نبض الليل','صباح ذهبي','الوقت الذائب','طريق الضوء',
       'حديقة بعد المطر','ضوء حلزوني','حلم بلا لون','نهاية الربيع','صوت الأعماق'],
  el: ['Ουρανός του δειλινού','Αυγή της πόλης','Φεγγάρι στο νερό','Μακρινή μνήμη','Φωνή του ανέμου','Σιωπηλό τραγούδι','Παλμός νύχτας','Χρυσό πρωί','Λιωμένος χρόνος','Δρόμος φωτιάς',
       'Κήπος μετά τη βροχή','Φως σπείρας','Άχρωμο όνειρο','Τέλος της άνοιξης','Φωνή των βαθών'],
  he: ['שמי בין ערביים','עיר בשחר','ירח במים','זיכרון רחוק','קול הרוח','שיר שקט','דופק הלילה','בוקר זהב','זמן נמס','דרך האור',
       'גן לאחר הגשם','אור הסליל','חלום חסר צבע','סוף האביב','קול המעמקים'],
  th: ['ท้องฟ้ายามเย็น','เมืองรุ่งอรุณ','พระจันทร์ในน้ำ','ความทรงจำแสนไกล','เสียงสายลม','เพลงเงียบ','จังหวะแห่งราตรี','เช้าสีทอง','เวลาที่ละลาย','ทางแห่งแสง',
       'สวนหลังฝน','แสงเกลียว','ฝันไร้สี','ปลายฤดูใบไม้ผลิ','เสียงจากก้นทะเล'],
  hi: ['सांझ का आसमान','भोर का शहर','पानी में चांद','दूर की याद','हवा का संदेश','खामोश गीत','रात की धड़कन','सुनहरी सुबह','पिघलता समय','रोशनी का रास्ता',
       'बारिश के बाद बगीचा','सर्पिल प्रकाश','रंगहीन सपना','वसंत का अंत','गहराई की आवाज़'],
};

// Romanization quality flags
const ROMAN_QUALITY = ['curated','machine','rough'];

// Build a per-work localization profile (cached)
function buildLocProfile(work, _seed) {
  const r = locSeed('loc·' + work.id);
  const isClassic = !!work.iswc;
  const profile = {
    id: work.id,
    title: work.title,
    iswc: work.iswc,
    plays: work.plays || 0,
    earnUsd: Math.round((work.plays || 0) / 800),
    coverage: {},  // iso → { native, romanized, type, quality, source }
    needs: [],     // [{ iso, why, blockers }]
    hasNonRoman: false,
    altTitles: [],     // CWR alt titles (non-translation)
    lyricAdapts: [],
  };
  // Always at least an OT entry for English / Latin original
  profile.coverage['EN'] = {
    native: work.title,
    romanized: work.title,
    type: 'OT',
    quality: 'curated',
    script: 'Latn',
    source: 'master',
  };
  // For each market, decide coverage based on a per-work random + revenue weight
  for (const m of LOC_MARKETS) {
    if (m.iso === 'EN') continue;
    if (m.iso === 'ES' || m.iso === 'PT' || m.iso === 'FR' || m.iso === 'DE' || m.iso === 'EL') {
      // Latin / Romance / DACH: usually only TT (Original Title Translated) on hits
      const has = isClassic && r() > 0.45;
      if (has) {
        const transl = m.iso === 'ES' ? 'El ' + work.title :
                       m.iso === 'PT' ? 'O ' + work.title :
                       m.iso === 'FR' ? 'Le ' + work.title :
                       m.iso === 'DE' ? 'Der ' + work.title :
                       m.iso === 'EL' ? 'Το ' + work.title :
                       work.title;
        profile.coverage[m.iso] = { native: transl, romanized: transl, type: 'TT', quality: 'curated', script: m.script, source: 'editor' };
      }
      continue;
    }
    // Non-Roman markets: probabilistic coverage with quality tiers
    const haveNative = isClassic && r() > 0.55;
    if (haveNative) {
      const idx = Math.floor(r() * 15);
      const lc = m.iso.toLowerCase();
      const native = (CURATED_TITLES[lc] || [])[idx % 15] || work.title;
      const quality = r() < 0.35 ? 'curated' : r() < 0.85 ? 'machine' : 'rough';
      profile.coverage[m.iso] = {
        native,
        romanized: work.title.replace(/[aeiou]/gi, x => x), // placeholder romanization — would be transliteration engine output
        type: 'TT',
        quality,
        script: m.script,
        source: quality === 'curated' ? 'editor' : quality === 'machine' ? 'auto·deepL' : 'auto·romanize',
      };
      profile.hasNonRoman = true;
    } else {
      // Mark as gap if revenue exists in that market
      if (m.earnPct > 0.5 && (work.plays || 0) > 200000) {
        profile.needs.push({
          iso: m.iso,
          name: m.name,
          script: m.script,
          society: m.society,
          why: 'no localized title',
          estLossUsd: Math.round((work.plays || 0) * (m.earnPct / 100) * 0.0006),
          blockers: ['society-registration-blocked'],
        });
      }
    }
  }
  // CWR alt titles (non-translation) — formal title, first line of text
  if (r() > 0.7 && isClassic) {
    profile.altTitles.push({ type:'FT', label:'Formal Title', value: work.title.toUpperCase(), language:'EN' });
  }
  if (r() > 0.85 && isClassic) {
    profile.altTitles.push({ type:'TE', label:'First Line of Text', value: 'I remember when ' + work.title.toLowerCase(), language:'EN' });
  }
  // Lyric adaptations
  if (r() > 0.7 && isClassic) {
    const adapts = ['TRA','MOD','RES'];
    const code = adapts[Math.floor(r()*adapts.length)];
    const lang = ['ES','JA','PT','FR','KO'][Math.floor(r()*5)];
    profile.lyricAdapts.push({ code, language: lang });
  }
  return profile;
}

// Build the full catalog × markets coverage matrix
function buildLocMatrix() {
  if (window.__LOC_MATRIX_CACHE) return window.__LOC_MATRIX_CACHE;
  const works = (window.WORKS || []).slice(0, 60); // cap for screen scale
  const profiles = works.map(w => buildLocProfile(w));
  // Aggregate per market
  const perMarket = {};
  for (const m of LOC_MARKETS) {
    const cov = profiles.filter(p => !!p.coverage[m.iso]).length;
    const need = profiles.filter(p => p.needs.find(n => n.iso === m.iso)).length;
    const lossUsd = profiles.reduce((s, p) => {
      const n = p.needs.find(n => n.iso === m.iso);
      return s + (n ? n.estLossUsd : 0);
    }, 0);
    const curated = profiles.filter(p => p.coverage[m.iso]?.quality === 'curated').length;
    const machine = profiles.filter(p => p.coverage[m.iso]?.quality === 'machine').length;
    const rough   = profiles.filter(p => p.coverage[m.iso]?.quality === 'rough').length;
    perMarket[m.iso] = { cov, need, lossUsd, curated, machine, rough, total: profiles.length };
  }
  // Total gaps
  const allGaps = [];
  for (const p of profiles) {
    for (const n of p.needs) {
      allGaps.push({ work: p, ...n });
    }
  }
  allGaps.sort((a,b) => b.estLossUsd - a.estLossUsd);
  const out = { profiles, perMarket, allGaps };
  window.__LOC_MATRIX_CACHE = out;
  return out;
}

// ─────────── Translation queue (jobs panel) ───────────────────────
function buildTranslationJobs() {
  if (window.__LOC_JOBS_CACHE) return window.__LOC_JOBS_CACHE;
  const r = locSeed('loc·jobs·v1');
  const matrix = buildLocMatrix();
  const jobs = [];
  // Recent: "machine drafted, awaiting review"
  for (let i = 0; i < 12; i++) {
    if (i >= matrix.allGaps.length) break;
    const g = matrix.allGaps[i];
    const isMachine = r() > 0.4;
    const status = isMachine ? (r() > 0.5 ? 'review' : 'queued') : (r() > 0.6 ? 'in-progress' : 'queued');
    const submitted = new Date(2026, 3, 28 - Math.floor(r() * 12));
    jobs.push({
      id: 'JOB-' + String(40871 + i).padStart(5,'0'),
      work: g.work,
      iso: g.iso,
      script: g.script,
      society: g.society,
      assignee: status === 'review' ? 'auto·DeepL' : status === 'in-progress' ? ['Hina M.','Min-Jun K.','Liu W.','Daria K.'][Math.floor(r()*4)] : '—',
      submittedAt: submitted,
      status,
      cost: isMachine ? 0.04 : (4.50 + r() * 8),
      kind: isMachine ? 'machine' : 'human',
    });
  }
  // Done jobs
  for (let i = 0; i < 8; i++) {
    const g = matrix.allGaps[20 + i] || matrix.allGaps[i];
    if (!g) break;
    const submitted = new Date(2026, 3, 22 - i);
    jobs.push({
      id: 'JOB-' + String(40860 - i).padStart(5,'0'),
      work: g.work,
      iso: g.iso,
      script: g.script,
      society: g.society,
      assignee: ['Hina M.','Min-Jun K.','auto·DeepL','Liu W.','auto·DeepL'][i % 5],
      submittedAt: submitted,
      status: 'done',
      cost: i % 3 === 0 ? 0.04 : 6.80,
      kind: i % 3 === 0 ? 'machine' : 'human',
    });
  }
  window.__LOC_JOBS_CACHE = jobs;
  return jobs;
}

// ───────────────────────────────────────────────────────────────────
// SCREEN
// ───────────────────────────────────────────────────────────────────
function ScreenLocalization({ go, payload }) {
  const Btn = window.Btn, Ic = window.Ic, PageHeader = window.PageHeader;
  const [tab, setTab] = useLocS(payload?.tab || 'coverage');
  const matrix = useLocM(() => buildLocMatrix(), []);
  const jobs   = useLocM(() => buildTranslationJobs(), []);

  // Header-level KPIs
  const kpi = useLocM(() => {
    const totalWorks = matrix.profiles.length;
    const fullyCovered = matrix.profiles.filter(p => p.needs.length === 0).length;
    const partial = matrix.profiles.filter(p => p.needs.length > 0 && Object.keys(p.coverage).length > 1).length;
    const noLocal = matrix.profiles.filter(p => Object.keys(p.coverage).length <= 1).length;
    const totalLossUsd = matrix.allGaps.reduce((s, g) => s + g.estLossUsd, 0);
    return { totalWorks, fullyCovered, partial, noLocal, totalLossUsd, gaps: matrix.allGaps.length };
  }, [matrix]);

  return (
    <div className="container-prose" style={{ position:'relative' }}>
      <PageHeader
        eyebrow={`§04 · CATALOG · BULK LOCALIZATION · ${LOC_MARKETS.length} MARKETS · ${kpi.totalWorks} WORKS`}
        title="Localization (bulk)"
        sub={
          <>
            Power-user matrix for editing alt-titles, scripts, and lyric adaptations across many works at once.
            Per-work entry lives on the Work page; gaps and returned translations now appear in your Inbox.
            <strong>{kpi.gaps}</strong> coverage gaps · <span className="ff-mono num" style={{color:'var(--danger)'}}>${kpi.totalLossUsd.toLocaleString()}</span> est. annual leakage.
          </>
        }
        right={
          <>
            <Btn variant="secondary" icon={<Ic.Send />} size="sm" onClick={() => go && go('inbox', { tab:'tasks' })}>Open in Inbox</Btn>
          </>
        }
      />

      {/* Tab strip */}
      <LocTabBar tab={tab} setTab={setTab} />

      {/* Tab content */}
      {tab === 'coverage'   && <LocCoverage matrix={matrix} kpi={kpi} go={go}/>}
      {tab === 'scripts'    && <LocScripts matrix={matrix} go={go}/>}
      {tab === 'lyrics'     && <LocLyrics matrix={matrix} go={go}/>}
    </div>
  );
}

// ─────────── Tab bar ──────────────────────────────────────────────
function LocTabBar({ tab, setTab }) {
  const tabs = [
    { id:'coverage', label:'01 · Coverage matrix' },
    { id:'scripts',  label:'02 · Scripts & alt titles' },
    { id:'lyrics',   label:'03 · Lyric adaptations' },
  ];
  return (
    <div style={{display:'flex',gap:0,borderBottom:'2px solid var(--ink)',margin:'24px 0 28px',overflowX:'auto'}}>
      {tabs.map(t => (
        <button key={t.id} onClick={()=>setTab(t.id)}
          className="ff-mono upper"
          style={{
            background: tab === t.id ? 'var(--ink)' : 'transparent',
            color:      tab === t.id ? 'var(--bg)'  : 'var(--ink-2)',
            border:0, padding:'10px 18px', fontSize:11, letterSpacing:'.08em',
            cursor:'pointer', whiteSpace:'nowrap', fontWeight: tab===t.id?600:500,
          }}>
          {t.label}
        </button>
      ))}
    </div>
  );
}

// ─────────── 01 · COVERAGE MATRIX ─────────────────────────────────
function LocCoverage({ matrix, kpi, go }) {
  const [hoverCell, setHoverCell] = useLocS(null);
  const visibleWorks = matrix.profiles.slice(0, 24);

  return (
    <div>
      {/* KPI strip */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',
        borderTop:'1px solid var(--rule)',borderBottom:'1px solid var(--rule)',marginBottom:32}}>
        <KpiCell label="WORKS · ALL SCRIPTS"   value={kpi.fullyCovered} sub={`of ${kpi.totalWorks} fully covered`} tone="ok"/>
        <KpiCell label="PARTIAL COVERAGE"      value={kpi.partial}      sub="some markets only"/>
        <KpiCell label="NO LOCAL TITLES"       value={kpi.noLocal}      sub="EN only" tone="warn"/>
        <KpiCell label="ANNUAL LEAKAGE EST."   value={'$'+(kpi.totalLossUsd/1000).toFixed(1)+'K'} sub={`${kpi.gaps} fixable gaps`} tone="danger"/>
      </div>

      {/* Per-market coverage row */}
      <div style={{marginBottom:32}}>
        <div className="ff-mono upper" style={{fontSize:10,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:14}}>
          BY MARKET · % OF CATALOG WITH LOCAL-SCRIPT TITLE
        </div>
        <div style={{border:'1px solid var(--rule)'}}>
          {LOC_MARKETS.map((m,i) => {
            const stats = matrix.perMarket[m.iso];
            const pct = Math.round((stats.cov / Math.max(stats.total,1)) * 100);
            const tone = pct >= 80 ? 'var(--ok)' : pct >= 50 ? 'var(--warn)' : 'var(--danger)';
            return (
              <div key={m.iso} style={{
                display:'grid',gridTemplateColumns:'40px 220px 1fr 110px 90px 80px',
                alignItems:'center',gap:0,padding:'10px 14px',
                borderTop: i===0 ? 0 : '1px solid var(--rule-soft)',
                background: i%2 ? 'var(--bg)' : 'var(--bg-2)',
              }}>
                <span style={{fontSize:18,lineHeight:1}}>{m.flag}</span>
                <div>
                  <div style={{fontSize:13,fontWeight:500}}>{m.name}</div>
                  <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.08em',marginTop:2}}>
                    {m.iso} · {m.script} · {m.society} · {m.earnPct}% earn
                  </div>
                </div>
                {/* Coverage bar */}
                <div style={{display:'flex',alignItems:'center',gap:10,paddingRight:18}}>
                  <div style={{flex:1,height:8,background:'var(--bg-3)',position:'relative'}}>
                    <div style={{position:'absolute',inset:0,width:pct+'%',background:tone}}/>
                    {/* curated portion overlay */}
                    <div style={{position:'absolute',top:0,bottom:0,left:0,
                      width: Math.round((stats.curated / Math.max(stats.total,1))*100)+'%',
                      background:'var(--ink)',mixBlendMode:'multiply',opacity:.45}}/>
                  </div>
                  <span className="ff-mono num" style={{fontSize:11,color:'var(--ink-2)',minWidth:34,textAlign:'right'}}>{pct}%</span>
                </div>
                <span className="ff-mono num" style={{fontSize:11,textAlign:'right',color:'var(--ink-2)'}}>{stats.cov}/{stats.total}</span>
                <span className="ff-mono num" style={{fontSize:11,textAlign:'right',color:stats.need ? 'var(--danger)' : 'var(--ink-3)'}}>
                  {stats.need ? '-' + stats.need + ' gap' : '— clean'}
                </span>
                <span className="ff-mono num" style={{fontSize:11,textAlign:'right',color:'var(--ink)',fontWeight:500}}>
                  {stats.lossUsd ? '$'+stats.lossUsd.toLocaleString() : '—'}
                </span>
              </div>
            );
          })}
        </div>
        <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:8,letterSpacing:'.04em'}}>
          ▮ curated translation · ▮ machine-only · empty = gap. Leakage = est. annual mech share blocked at society.
        </div>
      </div>

      {/* Heatmap matrix · works × markets */}
      <div>
        <div className="ff-mono upper" style={{fontSize:10,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:14,
          display:'flex',alignItems:'baseline',justifyContent:'space-between'}}>
          <span>WORKS × MARKETS · TOP {visibleWorks.length} BY EARN</span>
          <span style={{color:'var(--ink-4)',letterSpacing:'.06em'}}>hover for detail · click to open work</span>
        </div>
        <div style={{border:'1px solid var(--rule)',overflowX:'auto',position:'relative'}}>
          {/* Header row */}
          <div style={{display:'grid',gridTemplateColumns:`260px repeat(${LOC_MARKETS.length}, 56px) 80px`,
            background:'var(--bg-2)',borderBottom:'1px solid var(--ink)'}}>
            <div className="ff-mono upper" style={{padding:'10px 14px',fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>WORK</div>
            {LOC_MARKETS.map(m => (
              <div key={m.iso} style={{padding:'10px 4px',textAlign:'center',borderLeft:'1px solid var(--rule-soft)'}}>
                <div style={{fontSize:14,lineHeight:1}}>{m.flag}</div>
                <div className="ff-mono num" style={{fontSize:8,color:'var(--ink-3)',marginTop:3,letterSpacing:'.06em'}}>{m.iso}</div>
              </div>
            ))}
            <div className="ff-mono upper" style={{padding:'10px 8px',fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',
              textAlign:'right',borderLeft:'1px solid var(--rule-soft)'}}>EARN</div>
          </div>
          {/* Rows */}
          {visibleWorks.map((p, ri) => (
            <div key={p.id} style={{display:'grid',gridTemplateColumns:`260px repeat(${LOC_MARKETS.length}, 56px) 80px`,
              borderTop: ri===0?0:'1px solid var(--rule-soft)', alignItems:'stretch'}}
              onClick={() => go && go('work', { id: p.id })}>
              <div style={{padding:'8px 14px',fontSize:12,fontWeight:500,
                whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis',
                cursor:'pointer',display:'flex',flexDirection:'column',justifyContent:'center'}}>
                {p.title}
                <span className="ff-mono num" style={{fontSize:9,color:'var(--ink-3)',marginTop:2}}>
                  {p.iswc || '— no ISWC —'}
                </span>
              </div>
              {LOC_MARKETS.map(m => {
                const cell = p.coverage[m.iso];
                const isGap = !cell;
                const isHover = hoverCell?.workId === p.id && hoverCell?.iso === m.iso;
                let bg = 'var(--bg)', glyph = '·', color = 'var(--ink-4)';
                if (cell) {
                  if (cell.quality === 'curated') { bg = 'var(--ink)';     glyph = '●'; color = 'var(--bg)'; }
                  else if (cell.quality === 'machine') { bg = 'var(--bg-3)'; glyph = '◐'; color = 'var(--ink-2)'; }
                  else if (cell.quality === 'rough')   { bg = 'var(--bg-2)'; glyph = '◌'; color = 'var(--ink-3)'; }
                }
                if (isGap && p.needs.find(n => n.iso === m.iso)) { bg = 'rgba(160,68,50,.08)'; glyph = '·'; color = 'var(--danger)'; }
                return (
                  <div key={m.iso} style={{
                      borderLeft:'1px solid var(--rule-soft)',
                      background: bg,
                      display:'flex',alignItems:'center',justifyContent:'center',
                      cursor: cell ? 'pointer' : 'default',position:'relative',
                      outline: isHover ? '2px solid var(--accent)' : '0',outlineOffset:-2,
                    }}
                    onMouseEnter={() => setHoverCell({workId: p.id, iso: m.iso})}
                    onMouseLeave={() => setHoverCell(null)}
                  >
                    <span style={{fontSize:14,color,lineHeight:1}}>{glyph}</span>
                    {isHover && cell && (
                      <div style={{position:'absolute',top:'100%',left:'50%',transform:'translateX(-50%)',
                        background:'var(--ink)',color:'var(--bg)',padding:'8px 10px',whiteSpace:'nowrap',zIndex:10,
                        boxShadow:'0 4px 12px rgba(0,0,0,.18)',fontSize:11,marginTop:4}}>
                        <div style={{fontWeight:600,marginBottom:3}}>{cell.native}</div>
                        <div className="ff-mono" style={{fontSize:9,opacity:.7,letterSpacing:'.04em'}}>
                          {CWR_TITLE_TYPES[cell.type]?.label} · {cell.quality} · {cell.source}
                        </div>
                      </div>
                    )}
                    {isHover && isGap && (
                      <div style={{position:'absolute',top:'100%',left:'50%',transform:'translateX(-50%)',
                        background:'var(--danger)',color:'#fff',padding:'8px 10px',whiteSpace:'nowrap',zIndex:10,
                        boxShadow:'0 4px 12px rgba(0,0,0,.18)',fontSize:11,marginTop:4}}>
                        <div style={{fontWeight:600,marginBottom:3}}>Gap · {m.name}</div>
                        <div className="ff-mono" style={{fontSize:9,opacity:.85,letterSpacing:'.04em'}}>{m.society} cannot match this work</div>
                      </div>
                    )}
                  </div>
                );
              })}
              <div className="ff-mono num" style={{padding:'8px 8px',fontSize:11,textAlign:'right',color:'var(--ink-2)',
                borderLeft:'1px solid var(--rule-soft)',alignSelf:'center'}}>
                ${(p.earnUsd/1000).toFixed(1)}K
              </div>
            </div>
          ))}
        </div>
        <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:8,letterSpacing:'.04em',display:'flex',gap:18}}>
          <span>● curated</span>
          <span>◐ machine</span>
          <span>◌ rough</span>
          <span style={{color:'var(--danger)'}}>· gap (revenue at risk)</span>
        </div>
      </div>
    </div>
  );
}

// ─────────── 02 · GAPS ────────────────────────────────────────────
function LocGaps({ matrix, go, setTab }) {
  const Btn = window.Btn, Ic = window.Ic;
  const [marketFilter, setMarketFilter] = useLocS('all');
  const [selected, setSelected] = useLocS(new Set());
  const filteredGaps = useLocM(() =>
    matrix.allGaps.filter(g => marketFilter === 'all' || g.iso === marketFilter),
    [matrix, marketFilter]
  );
  const totalLoss = filteredGaps.reduce((s,g)=>s+g.estLossUsd,0);
  const selectedLoss = filteredGaps.filter(g => selected.has(g.work.id+'·'+g.iso)).reduce((s,g)=>s+g.estLossUsd,0);

  const toggle = (key) => {
    const n = new Set(selected);
    if (n.has(key)) n.delete(key); else n.add(key);
    setSelected(n);
  };
  const selectAll = () => setSelected(new Set(filteredGaps.map(g => g.work.id+'·'+g.iso)));
  const clearAll = () => setSelected(new Set());

  return (
    <div>
      {/* Filter bar */}
      <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:18,flexWrap:'wrap'}}>
        <span className="ff-mono upper" style={{fontSize:10,letterSpacing:'.1em',color:'var(--ink-3)',marginRight:6}}>FILTER MARKET ·</span>
        <button onClick={()=>setMarketFilter('all')} className="ff-mono upper"
          style={{padding:'4px 10px',fontSize:10,letterSpacing:'.06em',
            background:marketFilter==='all'?'var(--ink)':'transparent',
            color:marketFilter==='all'?'var(--bg)':'var(--ink-2)',
            border:'1px solid var(--rule)',cursor:'pointer'}}>ALL · {matrix.allGaps.length}</button>
        {NON_ROMAN_MARKETS.map(m => {
          const c = matrix.allGaps.filter(g=>g.iso===m.iso).length;
          if (!c) return null;
          return (
            <button key={m.iso} onClick={()=>setMarketFilter(m.iso)} className="ff-mono upper"
              style={{padding:'4px 10px',fontSize:10,letterSpacing:'.06em',
                background:marketFilter===m.iso?'var(--ink)':'transparent',
                color:marketFilter===m.iso?'var(--bg)':'var(--ink-2)',
                border:'1px solid var(--rule)',cursor:'pointer',display:'inline-flex',alignItems:'center',gap:6}}>
              <span style={{fontSize:13}}>{m.flag}</span>{m.iso} · {c}
            </button>
          );
        })}
      </div>

      {/* Bulk action bar */}
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',
        padding:'12px 16px',background: selected.size ? 'var(--ink)' : 'var(--bg-2)',
        color: selected.size ? 'var(--bg)' : 'var(--ink-2)',
        border:'1px solid var(--ink)',marginBottom:0}}>
        <div className="ff-mono upper" style={{fontSize:11,letterSpacing:'.08em'}}>
          {selected.size ? (
            <>
              {selected.size} GAP{selected.size>1?'S':''} SELECTED · ${selectedLoss.toLocaleString()} LOSS · {' '}
              <button onClick={clearAll} style={{background:'transparent',border:0,color:'var(--bg)',textDecoration:'underline',cursor:'pointer',padding:0,fontSize:11,letterSpacing:'.08em'}}>clear</button>
            </>
          ) : (
            <>
              {filteredGaps.length} TOTAL GAPS · ${totalLoss.toLocaleString()} ANNUAL LEAKAGE · {' '}
              <button onClick={selectAll} style={{background:'transparent',border:0,color:'var(--ink-2)',textDecoration:'underline',cursor:'pointer',padding:0,fontSize:11,letterSpacing:'.08em'}}>select all</button>
            </>
          )}
        </div>
        <div style={{display:'flex',gap:8}}>
          {selected.size > 0 && (
            <>
              <Btn variant={selected.size?'accent':'secondary'} icon={<Ic.Build />} size="sm">
                Auto-translate ({selected.size})
              </Btn>
              <Btn variant="secondary" size="sm" style={{borderColor:'var(--bg)',color:'var(--bg)'}}>
                Assign to translator
              </Btn>
            </>
          )}
        </div>
      </div>

      {/* Gaps table */}
      <div style={{border:'1px solid var(--ink)',borderTop:0}}>
        <div style={{display:'grid',gridTemplateColumns:'40px 1.6fr 90px 100px 1fr 110px 130px',
          padding:'8px 14px',background:'var(--bg-2)',borderBottom:'1px solid var(--ink)'}}>
          <span/>
          <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>WORK</span>
          <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>MARKET</span>
          <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>SOCIETY</span>
          <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>BLOCKER</span>
          <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',textAlign:'right'}}>EST. LOSS · 12M</span>
          <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',textAlign:'right'}}>ACTION</span>
        </div>
        {filteredGaps.slice(0, 30).map((g, i) => {
          const m = LOC_MARKETS.find(mm => mm.iso === g.iso);
          const key = g.work.id + '·' + g.iso;
          const isSel = selected.has(key);
          return (
            <div key={key} style={{display:'grid',gridTemplateColumns:'40px 1.6fr 90px 100px 1fr 110px 130px',
              padding:'10px 14px',borderTop: i===0?0:'1px solid var(--rule-soft)',
              alignItems:'center',
              background: isSel ? 'var(--accent-soft, rgba(255,230,90,.18))' : (i%2 ? 'var(--bg)' : 'var(--bg-2)'),
              cursor:'pointer'}}
              onClick={()=>toggle(key)}>
              <span><input type="checkbox" checked={isSel} onChange={()=>toggle(key)} onClick={e=>e.stopPropagation()}/></span>
              <div>
                <div style={{fontSize:13,fontWeight:500}}>{g.work.title}</div>
                <div className="ff-mono num" style={{fontSize:10,color:'var(--ink-3)',marginTop:2}}>
                  {g.work.iswc || '—'} · {g.work.plays.toLocaleString()} plays
                </div>
              </div>
              <div style={{display:'flex',alignItems:'center',gap:6}}>
                <span style={{fontSize:14}}>{m?.flag}</span>
                <span className="ff-mono upper" style={{fontSize:11,letterSpacing:'.06em'}}>{g.iso}</span>
              </div>
              <span className="ff-mono upper" style={{fontSize:11,letterSpacing:'.06em',color:'var(--ink-2)'}}>{g.society}</span>
              <span className="ff-mono" style={{fontSize:11,color:'var(--ink-2)'}}>
                <span style={{color:'var(--danger)',marginRight:6}}>●</span>
                {g.script} script title missing · CWR TT slot empty
              </span>
              <span className="ff-mono num" style={{fontSize:12,textAlign:'right',color:'var(--ink)',fontWeight:500}}>
                ${g.estLossUsd.toLocaleString()}
              </span>
              <div style={{display:'flex',gap:4,justifyContent:'flex-end'}} onClick={e=>e.stopPropagation()}>
                <button className="ff-mono upper" style={{fontSize:9,letterSpacing:'.06em',
                  padding:'4px 8px',background:'var(--ink)',color:'var(--bg)',border:0,cursor:'pointer'}}>
                  TRANSLATE
                </button>
                <button onClick={()=>go && go('work', g.work)} className="ff-mono upper" style={{fontSize:9,letterSpacing:'.06em',
                  padding:'4px 8px',background:'transparent',color:'var(--ink-2)',border:'1px solid var(--rule)',cursor:'pointer'}}>
                  OPEN
                </button>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─────────── 03 · SCRIPTS ─────────────────────────────────────────
function LocScripts({ matrix, go }) {
  const Btn = window.Btn, Ic = window.Ic;
  const [search, setSearch] = useLocS('');
  const filtered = useLocM(() => {
    const q = search.trim().toLowerCase();
    return matrix.profiles
      .filter(p => p.hasNonRoman || p.altTitles.length > 0)
      .filter(p => !q || p.title.toLowerCase().includes(q))
      .slice(0, 20);
  }, [matrix, search]);

  return (
    <div>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:18}}>
        <div className="ff-mono upper" style={{fontSize:10,letterSpacing:'.12em',color:'var(--ink-3)'}}>
          NON-ROMAN NAMES + CWR ALT TITLES · PER WORK
        </div>
        <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="search work title…"
          className="ff-mono" style={{padding:'6px 10px',fontSize:11,border:'1px solid var(--rule)',
            background:'var(--bg)',color:'var(--ink)',width:240}}/>
      </div>

      <div style={{display:'flex',flexDirection:'column',gap:14}}>
        {filtered.map(p => (
          <div key={p.id} style={{border:'1px solid var(--rule)',background:'var(--bg)'}}>
            {/* Work header */}
            <div onClick={()=>go && go('work', p)}
              style={{padding:'14px 18px',display:'flex',alignItems:'baseline',justifyContent:'space-between',
                borderBottom:'1px solid var(--rule-soft)',cursor:'pointer'}}>
              <div>
                <div style={{fontSize:16,fontWeight:600,letterSpacing:'-0.01em'}}>{p.title}</div>
                <div className="ff-mono num" style={{fontSize:10,color:'var(--ink-3)',marginTop:2,letterSpacing:'.04em'}}>
                  {p.iswc || '— no ISWC —'} · {p.plays.toLocaleString()} plays · ${p.earnUsd.toLocaleString()}/12M
                </div>
              </div>
              <span className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.08em'}}>
                {Object.keys(p.coverage).length} TITLES · {p.altTitles.length} ALT
              </span>
            </div>
            {/* Translation rows */}
            <div style={{padding:'10px 18px'}}>
              {Object.entries(p.coverage).filter(([iso]) => iso !== 'EN').map(([iso, cell]) => {
                const m = LOC_MARKETS.find(mm => mm.iso === iso);
                if (!m) return null;
                return (
                  <div key={iso} style={{display:'grid',gridTemplateColumns:'80px 1fr 1fr 110px 90px',
                    alignItems:'center',gap:12,padding:'8px 0',borderBottom:'1px solid var(--rule-soft)'}}>
                    <div style={{display:'flex',alignItems:'center',gap:6}}>
                      <span style={{fontSize:14}}>{m.flag}</span>
                      <span className="ff-mono upper" style={{fontSize:10,letterSpacing:'.08em'}}>{iso}</span>
                    </div>
                    <div style={{fontSize:15,fontWeight:500,fontFeatureSettings:'"palt" 1'}}
                         lang={iso.toLowerCase()} dir={(iso==='AR'||iso==='HE') ? 'rtl' : 'ltr'}>
                      {cell.native}
                    </div>
                    <div className="ff-mono" style={{fontSize:11,color:'var(--ink-3)',fontStyle:'italic'}}>
                      {cell.romanized}
                    </div>
                    <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.06em',
                      color: cell.quality==='curated'?'var(--ok)' : cell.quality==='machine'?'var(--ink-2)' : 'var(--warn)'}}>
                      ● {cell.quality}
                    </span>
                    <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.06em',color:'var(--ink-3)',textAlign:'right'}}>
                      CWR · {cell.type}
                    </span>
                  </div>
                );
              })}
              {p.altTitles.map((a,i) => (
                <div key={'alt'+i} style={{display:'grid',gridTemplateColumns:'80px 1fr 1fr 110px 90px',
                  alignItems:'center',gap:12,padding:'8px 0',
                  borderBottom: i===p.altTitles.length-1 ? 0 : '1px solid var(--rule-soft)'}}>
                  <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.08em',color:'var(--ink-3)'}}>ALT</span>
                  <div style={{fontSize:13,fontWeight:500}}>{a.value}</div>
                  <span/>
                  <span/>
                  <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.06em',color:'var(--ink-3)',textAlign:'right'}}>
                    CWR · {a.type} · {a.label}
                  </span>
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ─────────── 04 · LYRICS ──────────────────────────────────────────
function LocLyrics({ matrix, go }) {
  const adapts = useLocM(() => {
    const out = [];
    for (const p of matrix.profiles) {
      for (const a of p.lyricAdapts) out.push({ work: p, ...a });
    }
    return out;
  }, [matrix]);

  const codeStats = useLocM(() => {
    const s = {};
    for (const a of adapts) s[a.code] = (s[a.code] || 0) + 1;
    return s;
  }, [adapts]);

  return (
    <div>
      <div className="ff-mono upper" style={{fontSize:10,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:14}}>
        LYRIC ADAPTATIONS · CWR ref.lyric_adaptations · {adapts.length} ENTRIES
      </div>

      {/* Code legend */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(180px,1fr))',
        gap:0,border:'1px solid var(--rule)',marginBottom:24}}>
        {CWR_LYRIC_ADAPTS.map((a,i) => {
          const tone = a.severity==='high'?'var(--danger)':a.severity==='med'?'var(--warn)':'var(--ink-3)';
          return (
            <div key={a.code} style={{padding:'12px 14px',
              borderRight: i<CWR_LYRIC_ADAPTS.length-1?'1px solid var(--rule-soft)':0,
              borderBottom:'1px solid var(--rule-soft)'}}>
              <div style={{display:'flex',alignItems:'baseline',justifyContent:'space-between',marginBottom:4}}>
                <span className="ff-mono upper" style={{fontSize:11,fontWeight:600,letterSpacing:'.08em',color: tone}}>
                  {a.code}
                </span>
                <span className="ff-mono num" style={{fontSize:13,color:'var(--ink)',fontWeight:600}}>{codeStats[a.code] || 0}</span>
              </div>
              <div style={{fontSize:13,fontWeight:500,marginBottom:2}}>{a.label}</div>
              <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',letterSpacing:'.02em',lineHeight:1.4}}>{a.note}</div>
            </div>
          );
        })}
      </div>

      {/* List */}
      {adapts.length === 0 ? (
        <div style={{padding:36,textAlign:'center',border:'1px dashed var(--rule)',color:'var(--ink-3)'}}>
          No lyric adaptations recorded across the catalog.
        </div>
      ) : (
        <div style={{border:'1px solid var(--rule)'}}>
          <div style={{display:'grid',gridTemplateColumns:'1.6fr 100px 90px 1fr 100px',
            padding:'8px 14px',background:'var(--bg-2)',borderBottom:'1px solid var(--ink)'}}>
            <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>WORK</span>
            <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>CODE</span>
            <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>LANGUAGE</span>
            <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)'}}>NOTE</span>
            <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.1em',color:'var(--ink-3)',textAlign:'right'}}>SEVERITY</span>
          </div>
          {adapts.map((a, i) => {
            const def = CWR_LYRIC_ADAPTS.find(x => x.code === a.code);
            const m = LOC_MARKETS.find(mm => mm.iso === a.language);
            const tone = def?.severity==='high'?'var(--danger)':def?.severity==='med'?'var(--warn)':'var(--ink-3)';
            return (
              <div key={i} style={{display:'grid',gridTemplateColumns:'1.6fr 100px 90px 1fr 100px',
                padding:'10px 14px',borderTop: i===0?0:'1px solid var(--rule-soft)',alignItems:'center',
                background: i%2 ? 'var(--bg)' : 'var(--bg-2)',cursor:'pointer'}}
                onClick={()=>go && go('work', a.work)}>
                <span style={{fontSize:13,fontWeight:500}}>{a.work.title}</span>
                <span className="ff-mono upper" style={{fontSize:11,letterSpacing:'.08em',color:tone,fontWeight:600}}>{a.code}</span>
                <span style={{display:'flex',alignItems:'center',gap:6}}>
                  <span style={{fontSize:13}}>{m?.flag || '🏳'}</span>
                  <span className="ff-mono upper" style={{fontSize:10,letterSpacing:'.06em'}}>{a.language}</span>
                </span>
                <span className="ff-mono" style={{fontSize:11,color:'var(--ink-2)'}}>{def?.note || '—'}</span>
                <span className="ff-mono upper" style={{fontSize:9,letterSpacing:'.06em',color:tone,textAlign:'right'}}>
                  ● {def?.severity || '—'}
                </span>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// ─────────── 05 · JOBS ────────────────────────────────────────────
function LocJobs({ jobs, go }) {
  const Btn = window.Btn, Ic = window.Ic;
  const grouped = useLocM(() => ({
    queued:    jobs.filter(j => j.status === 'queued'),
    'in-progress': jobs.filter(j => j.status === 'in-progress'),
    review:    jobs.filter(j => j.status === 'review'),
    done:      jobs.filter(j => j.status === 'done'),
  }), [jobs]);

  const totalSpend = jobs.reduce((s, j) => s + j.cost, 0);
  const machineCount = jobs.filter(j => j.kind === 'machine').length;
  const humanCount = jobs.filter(j => j.kind === 'human').length;

  return (
    <div>
      {/* KPI */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',
        borderTop:'1px solid var(--rule)',borderBottom:'1px solid var(--rule)',marginBottom:24}}>
        <KpiCell label="QUEUED"          value={grouped.queued.length}      sub="ready to translate"/>
        <KpiCell label="IN PROGRESS"     value={grouped['in-progress'].length} sub="with translator"/>
        <KpiCell label="AWAITING REVIEW" value={grouped.review.length}      sub="machine drafted" tone="warn"/>
        <KpiCell label="SPEND · 30D"     value={'$'+totalSpend.toFixed(2)}
                 sub={`${machineCount} machine · ${humanCount} human`}/>
      </div>

      {/* Lanes */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',gap:14}}>
        {[
          { key:'queued',      title:'QUEUED',          tone:'var(--ink-3)' },
          { key:'in-progress', title:'IN PROGRESS',     tone:'var(--warn)' },
          { key:'review',      title:'AWAITING REVIEW', tone:'var(--accent)' },
          { key:'done',        title:'DONE',            tone:'var(--ok)' },
        ].map(lane => (
          <div key={lane.key} style={{border:'1px solid var(--rule)',background:'var(--bg-2)',display:'flex',flexDirection:'column',minHeight:200}}>
            <div style={{padding:'10px 12px',borderBottom:'1px solid var(--rule)',
              display:'flex',alignItems:'center',justifyContent:'space-between',background:'var(--bg)'}}>
              <span className="ff-mono upper" style={{fontSize:10,letterSpacing:'.1em',color:'var(--ink-2)'}}>
                <span style={{display:'inline-block',width:8,height:8,background:lane.tone,marginRight:8}}/>
                {lane.title}
              </span>
              <span className="ff-mono num" style={{fontSize:11,color:'var(--ink-3)'}}>{grouped[lane.key].length}</span>
            </div>
            <div style={{padding:10,display:'flex',flexDirection:'column',gap:8,flex:1}}>
              {grouped[lane.key].length === 0 ? (
                <div className="ff-mono" style={{fontSize:11,color:'var(--ink-4)',fontStyle:'italic',padding:'18px 4px',textAlign:'center'}}>—</div>
              ) : grouped[lane.key].slice(0,8).map(j => {
                const m = LOC_MARKETS.find(mm => mm.iso === j.iso);
                return (
                  <div key={j.id} onClick={()=>go && go('work', j.work)}
                    style={{padding:'10px 12px',background:'var(--bg)',border:'1px solid var(--rule-soft)',cursor:'pointer'}}>
                    <div style={{display:'flex',alignItems:'baseline',justifyContent:'space-between',marginBottom:4,gap:6}}>
                      <span className="ff-mono num" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.04em'}}>{j.id}</span>
                      <span style={{fontSize:13}}>{m?.flag}</span>
                    </div>
                    <div style={{fontSize:13,fontWeight:500,marginBottom:3,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>
                      {j.work.title}
                    </div>
                    <div className="ff-mono upper" style={{fontSize:9,color:'var(--ink-3)',letterSpacing:'.06em',display:'flex',justifyContent:'space-between',gap:6}}>
                      <span>{j.iso} · {j.script}</span>
                      <span style={{color: j.kind==='machine'?'var(--ink-3)':'var(--ink-2)'}}>{j.kind === 'machine' ? '⚙ ' : '✎ '}{j.assignee}</span>
                    </div>
                    {j.cost > 0 && (
                      <div className="ff-mono num" style={{fontSize:9,color:'var(--ink-3)',marginTop:3,textAlign:'right'}}>
                        ${j.cost.toFixed(2)}
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ─────────── KPI cell helper ──────────────────────────────────────
function KpiCell({ label, value, sub, tone }) {
  const colorMap = {
    ok:'var(--ok)', warn:'var(--warn)', danger:'var(--danger)',
  };
  return (
    <div style={{padding:'18px 20px',borderRight:'1px solid var(--rule)'}}>
      <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8}}>{label}</div>
      <div className="ff-display num heading-swap" style={{fontSize:32,fontWeight:600,letterSpacing:'-0.03em',lineHeight:1,
        color: tone ? colorMap[tone] : 'var(--ink)'}}>
        {value}
      </div>
      {sub && <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:8,letterSpacing:'.04em'}}>{sub}</div>}
    </div>
  );
}

Object.assign(window, { ScreenLocalization });
