// ============================================================================
// CAF SCREEN · CISAC Common Agreement Format · full lifecycle
// ----------------------------------------------------------------------------
// Mounted both as a route ('caf') and as a tab inside CWR-Acks.
//
// Tabs (sub-navigation):
//   01 GENERATE   — agreement picker → preview → validate → distribute
//   02 OUTBOX     — sent files, transmission status, retry
//   03 ACKS       — incoming AGR-ACK files, status codes, match to outbox
//   04 CONFLICTS  — agreement conflicts (CO status), resolution workflow
//
// Depends on: window.CafBuild, window.CafSynth, window.CafDecode, window.CafValidate
// EXPORT: window.ScreenCaf, window.CafGenTab
// ============================================================================

(function () {
  'use strict';
  const { useState, useMemo, useEffect } = React;

  // ─── Helpers
  function fmtDate(d) {
    if (!d) return '—';
    if (d.length === 10) return d;
    try { return new Date(d).toISOString().slice(0, 10); } catch { return d; }
  }
  function classNames(...xs) { return xs.filter(Boolean).join(' '); }

  // Pull agreements
  function getAgreements() {
    return Array.isArray(window.AGREEMENTS) ? window.AGREEMENTS : [];
  }

  // ─── Recipient societies
  const RECIPIENTS = [
    { code: 'ASCAP', soc: 10,  name: 'ASCAP',           tz: 'US',     gateway: 'sftp.ascap-cisac.net' },
    { code: 'BMI',   soc: 21,  name: 'BMI',             tz: 'US',     gateway: 'caf.bmi.com' },
    { code: 'PRS',   soc: 52,  name: 'PRS for Music',   tz: 'GB',     gateway: 'caf.prsformusic.com' },
    { code: 'GEMA',  soc: 35,  name: 'GEMA',            tz: 'DE',     gateway: 'edi.gema.de' },
    { code: 'SACEM', soc: 58,  name: 'SACEM',           tz: 'FR',     gateway: 'edi.sacem.fr' },
    { code: 'SIAE',  soc: 40,  name: 'SIAE',            tz: 'IT',     gateway: 'caf.siae.it' },
    { code: 'JASRAC',soc: 11,  name: 'JASRAC',          tz: 'JP',     gateway: 'caf.jasrac.or.jp' },
    { code: 'SOCAN', soc: 101, name: 'SOCAN',           tz: 'CA',     gateway: 'caf.socan.com' },
    { code: 'APRA',  soc: 40,  name: 'APRA AMCOS',      tz: 'AU',     gateway: 'edi.apra-amcos.com.au' },
    { code: 'STIM',  soc: 79,  name: 'STIM',            tz: 'SE',     gateway: 'caf.stim.se' },
    { code: 'CISAC', soc: 0,   name: 'CIS-Net Hub',     tz: 'EU',     gateway: 'cisnet.cisac.org' },
  ];

  // ═══════════════════════════════════════════════════════════════════ MAIN
  function ScreenCaf({ go, payload }) {
    const [tab, setTab] = useState(payload?.tab || 'gen');
    return (
      <div>
        <div className="ff-mono upper" style={{ fontSize:10, color:'var(--ink-3)', letterSpacing:'.12em', marginBottom:8, display:'flex', gap:10 }}>
          <button onClick={() => go && go('cwr')} style={{ background:'transparent', border:0, padding:0, color:'inherit', cursor:'pointer', font:'inherit', letterSpacing:'inherit', textTransform:'inherit' }}>TRANSMISSIONS</button>
          <span style={{ color:'var(--ink-4)' }}>/</span>
          <span style={{ color:'var(--ink)' }}>CAF</span>
        </div>

        <div style={{ display:'grid', gridTemplateColumns:'1fr auto', gap:24, alignItems:'flex-end', marginBottom:16 }}>
          <div>
            <h1 className="ff-display" style={{ fontSize:'clamp(36px,4.5vw,56px)', fontWeight:700, letterSpacing:'-0.04em', lineHeight:.95, margin:0 }}>
              Common Agreement Format
            </h1>
            <p style={{ color:'var(--ink-3)', maxWidth:780, marginTop:10, lineHeight:1.5 }}>
              CISAC's society-to-society wire for agreement registration. Generate, distribute, track acks, and resolve conflicts —
              the full bilateral lifecycle. CAF v1.2 fixed-width records: AGR · TER · IPA · NPA · USA · AGM.
            </p>
          </div>
        </div>

        <div style={{ display:'flex', borderBottom:'1px solid var(--rule)', marginBottom:0 }}>
          {[
            { k:'gen',       l:'Generate',  hint:'pick agreements → build → distribute' },
            { k:'outbox',    l:'Outbox',    hint:'sent files & transmission status' },
            { k:'acks',      l:'Acks',      hint:'incoming agreement ack files' },
            { k:'conflicts', l:'Conflicts', hint:'CO-status agreements awaiting resolution' },
            { k:'formats',   l:'Formats',   hint:'JSON / XML conversion' },
            { k:'compliance',l:'Compliance',hint:'spec coverage · fixture suite · readiness' },
          ].map(t => (
            <button key={t.k} onClick={() => setTab(t.k)} className="ff-mono upper" style={{
              padding:'14px 18px', fontSize:11, fontWeight:600, letterSpacing:'.08em',
              borderBottom: tab === t.k ? '3px solid var(--ink)' : '3px solid transparent', marginBottom:-1,
              color: tab === t.k ? 'var(--ink)' : 'var(--ink-3)', background:'transparent', border:0, cursor:'pointer',
              display:'flex', flexDirection:'column', alignItems:'flex-start', gap:2,
            }}>
              <span>{t.l}</span>
              <span style={{ fontSize:9, fontWeight:500, color:'var(--ink-4)', letterSpacing:'.04em', textTransform:'none' }}>{t.hint}</span>
            </button>
          ))}
        </div>

        <div style={{ marginTop: tab === 'gen' ? 0 : 24 }}>
          {tab === 'gen' && <CafGenTab go={go} payload={payload} />}
          {tab === 'outbox' && <OutboxTab />}
          {tab === 'acks' && <AcksTab />}
          {tab === 'conflicts' && <ConflictsTab go={go} />}
          {tab === 'formats' && (window.FormatsTab ? <window.FormatsTab kind="caf"/> : null)}
          {tab === 'compliance' && <ComplianceTab />}
        </div>
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════ GENERATE TAB
  function CafGenTab({ go, payload }) {
    const all = useMemo(getAgreements, []);
    const initialIds = (payload && payload.agreementIds) || (payload && payload.agreementId ? [payload.agreementId] : []);
    const [selected, setSelected] = useState(() => new Set(initialIds.length ? initialIds : (all[0] ? [all[0].id] : [])));
    const [search, setSearch] = useState('');
    const [filter, setFilter] = useState('all'); // all | active | expiring | pending
    const [recipient, setRecipient] = useState('SACEM');
    const [senderId, setSenderId] = useState(199900001);
    const [senderName, setSenderName] = useState('PLURALIS MUSIC');
    const [activeLine, setActiveLine] = useState(0);
    const [validationOpen, setValidationOpen] = useState(false);
    const [distOpen, setDistOpen] = useState(false);

    const filtered = useMemo(() => {
      const q = search.trim().toLowerCase();
      let xs = all;
      if (filter === 'active')   xs = xs.filter(a => a.status === 'active');
      if (filter === 'expiring') xs = xs.filter(a => a.status === 'expiring');
      if (filter === 'pending')  xs = xs.filter(a => a.status === 'pending');
      if (!q) return xs;
      return xs.filter(a => `${a.id||''} ${a.a||''} ${a.b||''} ${a.kind||''} ${a.territory||''}`.toLowerCase().includes(q));
    }, [all, search, filter]);

    const hydratedAgreements = useMemo(() => {
      return [...selected]
        .map(id => all.find(a => a.id === id))
        .filter(Boolean)
        .map(a => window.CafSynth.hydrateAgreement(a));
    }, [selected, all]);

    const transmission = useMemo(() => {
      if (!hydratedAgreements.length) return [];
      return window.CafBuild.buildTransmission({
        senderType: 'SP', senderId, senderName,
        agreements: hydratedAgreements,
        created: new Date(2026, 4, 12, 14, 22, 33),
      });
    }, [hydratedAgreements, senderId, senderName]);

    const filename = window.CafBuild.buildFilename({
      senderCode: 'PLU', recipientCode: recipient, sequence: 8421,
      created: new Date(2026, 4, 12), version: '1.2',
    });

    const decoded = useMemo(() => {
      const line = transmission[activeLine];
      if (!line || !window.CafDecode) return null;
      return window.CafDecode.decodeLine(line, '1.2');
    }, [transmission, activeLine]);

    const validation = useMemo(() => {
      if (!window.CafValidate) return { issues: [], summary: { errors: 0, warnings: 0, total: 0, ok: true } };
      return window.CafValidate.validate({ version: '1.2', lines: transmission, agreements: hydratedAgreements });
    }, [transmission, hydratedAgreements]);

    const toggle = (id) => setSelected(s => {
      const n = new Set(s); if (n.has(id)) n.delete(id); else n.add(id); return n;
    });
    const download = () => {
      const blob = new Blob([transmission.join('\r\n') + '\r\n'], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url; a.download = filename;
      document.body.appendChild(a); a.click(); a.remove();
      URL.revokeObjectURL(url);
      window.toast && window.toast(`Wrote ${filename} (${transmission.length} records)`);
    };
    const copy = () => {
      navigator.clipboard.writeText(transmission.join('\r\n'));
      window.toast && window.toast('CAF transmission copied to clipboard');
    };

    return (
      <div style={{ borderTop:'1px solid var(--rule)', display:'grid', gridTemplateColumns:'340px 1fr', minHeight:'calc(100vh - 280px)' }}>
        {/* LEFT: pickers */}
        <aside style={{ borderRight:'1px solid var(--rule)', background:'var(--bg-2)', display:'flex', flexDirection:'column' }}>
          <div style={{ padding:'14px 14px 12px', borderBottom:'1px solid var(--rule)' }}>
            <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:8 }}>RECIPIENT SOCIETY</div>
            <select value={recipient} onChange={(e) => setRecipient(e.target.value)} className="ff-mono"
              style={{ width:'100%', padding:'7px 8px', fontSize:11, background:'var(--paper)', border:'1px solid var(--rule)', marginBottom:12, boxSizing:'border-box' }}>
              {RECIPIENTS.map(r => <option key={r.code} value={r.code}>{r.code} — {r.name}</option>)}
            </select>

            <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:8 }}>SENDER</div>
            <input value={senderName} onChange={e => setSenderName(e.target.value)} className="ff-mono"
              style={{ width:'100%', padding:'7px 8px', fontSize:11, background:'var(--paper)', border:'1px solid var(--rule)', marginBottom:6, boxSizing:'border-box' }} />
            <input value={senderId} onChange={e => setSenderId(e.target.value)} className="ff-mono" placeholder="CAE / IPI"
              style={{ width:'100%', padding:'7px 8px', fontSize:11, background:'var(--paper)', border:'1px solid var(--rule)', boxSizing:'border-box' }} />
          </div>

          <div style={{ padding:'12px 14px 8px' }}>
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:8 }}>
              <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)' }}>AGREEMENTS · {selected.size} of {all.length}</div>
              <button onClick={() => setSelected(new Set(filtered.map(a => a.id)))} className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.08em', background:'transparent', border:0, color:'var(--ink-3)', cursor:'pointer' }}>SELECT ALL</button>
            </div>
            <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search ID, party, territory…" className="ff-mono"
              style={{ width:'100%', padding:'7px 8px', fontSize:11, background:'var(--paper)', border:'1px solid var(--rule)', marginBottom:8, boxSizing:'border-box' }} />
            <div style={{ display:'flex', gap:0, marginBottom:0, border:'1px solid var(--rule)' }}>
              {['all','active','expiring','pending'].map((f, i) => (
                <button key={f} onClick={() => setFilter(f)} className="ff-mono upper" style={{
                  flex:1, padding:'6px 0', fontSize:9, letterSpacing:'.08em',
                  background: filter === f ? 'var(--ink)' : 'transparent',
                  color: filter === f ? 'var(--paper)' : 'var(--ink-3)',
                  border:0, borderLeft: i ? '1px solid var(--rule)' : 0, cursor:'pointer',
                }}>{f}</button>
              ))}
            </div>
          </div>

          <div style={{ flex:1, overflowY:'auto', borderTop:'1px solid var(--rule)' }}>
            {filtered.map(a => (
              <button key={a.id} onClick={() => toggle(a.id)} style={{
                display:'flex', alignItems:'flex-start', gap:8, width:'100%', textAlign:'left',
                padding:'10px 14px', cursor:'pointer',
                background: selected.has(a.id) ? 'var(--paper)' : 'transparent',
                border:0, borderBottom:'1px solid var(--rule)',
              }}>
                <span style={{
                  width:14, height:14, flex:'0 0 14px', marginTop:2,
                  border:'1px solid var(--ink-2)',
                  background: selected.has(a.id) ? 'var(--ink)' : 'transparent',
                  display:'inline-flex', alignItems:'center', justifyContent:'center',
                  color:'var(--paper)', fontSize:10, fontWeight:700,
                }}>{selected.has(a.id) ? '✓' : ''}</span>
                <span style={{ flex:1, minWidth:0 }}>
                  <span className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', display:'block' }}>{a.id} · {a.kind}</span>
                  <span style={{ fontSize:12, fontWeight:500, display:'block', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
                    {a.a} <span style={{color:'var(--ink-3)'}}>×</span> {a.b}
                  </span>
                  <span className="ff-mono" style={{ fontSize:9, color:'var(--ink-3)', display:'block', marginTop:2 }}>{a.territory} · {a.share} · {fmtDate(a.start)} → {fmtDate(a.end)}</span>
                </span>
              </button>
            ))}
            {filtered.length === 0 && (
              <div className="ff-mono" style={{ padding:24, fontSize:11, color:'var(--ink-3)', textAlign:'center' }}>no agreements match</div>
            )}
          </div>
        </aside>

        {/* RIGHT: preview + inspector */}
        <main style={{ display:'flex', flexDirection:'column', minWidth:0 }}>
          <div style={{ borderBottom:'1px solid var(--rule)', padding:'10px 16px', display:'flex', alignItems:'center', gap:14, background:'var(--paper)', flexWrap:'wrap' }}>
            <div style={{ flex:'1 1 240px', minWidth:0 }}>
              <div className="ff-mono" style={{ fontSize:13, fontWeight:600, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{filename}</div>
              <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:1, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>
                {transmission.length} records · {transmission.reduce((s,l) => s+l.length, 0).toLocaleString()} chars · CAF v1.2 · → {recipient}
              </div>
            </div>
            <div style={{ display:'flex', gap:8, flexWrap:'wrap', flex:'0 0 auto' }}>
            <button onClick={copy} className="ff-mono upper" style={btnSecondary}>copy</button>
            <button onClick={() => setValidationOpen(v => !v)} className="ff-mono upper" title={`${validation.summary.errors} errors · ${validation.summary.warnings} warnings`}
              style={{
                ...btnSecondary,
                background: validationOpen ? 'var(--ink)' : 'var(--paper)',
                color: validationOpen ? 'var(--paper)' : 'var(--ink)',
                display:'inline-flex', alignItems:'center', gap:6,
              }}>
              <span style={{ width:7, height:7, borderRadius:99,
                background: validation.summary.errors ? '#c0392b' : (validation.summary.warnings ? '#d68910' : '#2e7d4f') }} />
              validate
              {validation.summary.total > 0 && <span style={{ fontWeight:500, color: validationOpen ? 'var(--paper)' : 'var(--ink-3)' }}>· {validation.summary.errors}E / {validation.summary.warnings}W</span>}
            </button>
            <button onClick={download} className="ff-mono upper" style={btnSecondary}>download</button>
            <button onClick={() => setDistOpen(true)} className="ff-mono upper" style={btnPrimary}>distribute →</button>
            </div>
          </div>

          {validationOpen && <ValidationPanel report={validation} onJump={(line) => setActiveLine(line)} />}

          <div style={{ flex:1, display:'grid', gridTemplateColumns:'1fr 380px', minHeight:0 }}>
            <LinesView lines={transmission} active={activeLine} onPick={setActiveLine} validation={validation} />
            <Inspector decoded={decoded} line={transmission[activeLine]} />
          </div>
        </main>

        {distOpen && <DistributeModal
          onClose={() => setDistOpen(false)}
          agreements={hydratedAgreements}
          recipient={recipient}
          filename={filename}
          transmission={transmission}
        />}
      </div>
    );
  }

  // ─── Lines view (preview)
  function LinesView({ lines, active, onPick, validation }) {
    const issuesByLine = useMemo(() => {
      const m = new Map();
      (validation?.issues || []).forEach(i => {
        if (!m.has(i.line)) m.set(i.line, []);
        m.get(i.line).push(i);
      });
      return m;
    }, [validation]);

    return (
      <div className="ff-mono" style={{ background:'var(--paper)', overflow:'auto', minHeight:0, fontSize:11, lineHeight:1.55 }}>
        <table style={{ width:'100%', borderCollapse:'collapse' }}>
          <tbody>
            {lines.map((line, i) => {
              const t = line.slice(0,3);
              const isActive = i === active;
              const issues = issuesByLine.get(i) || [];
              const hasErr = issues.some(x => x.severity === 'error');
              const hasWarn = issues.some(x => x.severity === 'warning');
              return (
                <tr key={i} onClick={() => onPick(i)} style={{
                  cursor:'pointer',
                  background: isActive ? 'var(--bg-2)' : 'transparent',
                  borderLeft: isActive ? '2px solid var(--ink)' : '2px solid transparent',
                }}>
                  <td style={{ padding:'1px 8px 1px 12px', color:'var(--ink-4)', fontSize:9, width:36, userSelect:'none', textAlign:'right', verticalAlign:'top' }}>{i+1}</td>
                  <td style={{ padding:'1px 6px', verticalAlign:'top', width:14 }}>
                    {hasErr && <span style={{ display:'inline-block', width:6, height:6, borderRadius:99, background:'#c0392b' }} />}
                    {!hasErr && hasWarn && <span style={{ display:'inline-block', width:6, height:6, borderRadius:99, background:'#d68910' }} />}
                  </td>
                  <td style={{ padding:'1px 8px', verticalAlign:'top' }}>
                    <span style={{ color: TYPE_COLOR[t] || 'var(--ink-3)', fontWeight:600 }}>{t}</span>
                    <span style={{ color:'var(--ink)', whiteSpace:'pre' }}>{line.slice(3)}</span>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    );
  }

  const TYPE_COLOR = {
    HDR:'#3056C8', GRH:'#3056C8', GRT:'#3056C8', TRL:'#3056C8',
    AGR:'#a04432', TER:'#3F8F6E', IPA:'#5c2a8a', NPA:'#5c2a8a',
    USA:'#c47b1c', AGM:'#6e6a60',
  };

  // ─── Inspector (decoded line)
  function Inspector({ decoded, line }) {
    if (!decoded) return <div className="ff-mono" style={{ padding:24, color:'var(--ink-3)', borderLeft:'1px solid var(--rule)', fontSize:11 }}>Pick a line.</div>;
    return (
      <div style={{ borderLeft:'1px solid var(--rule)', overflowY:'auto', minHeight:0, background:'var(--bg-2)' }}>
        <div style={{ padding:'14px 16px', borderBottom:'1px solid var(--rule)' }}>
          <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:6 }}>RECORD TYPE</div>
          <div className="ff-display" style={{ fontSize:22, fontWeight:600, letterSpacing:'-.02em', color: TYPE_COLOR[decoded.type] || 'var(--ink)' }}>{decoded.type}</div>
          <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:4 }}>{(line||'').length} chars</div>
        </div>
        <div style={{ padding:'4px 0' }}>
          {decoded.fields.map((f, i) => {
            const trimmed = (f.raw || '').trim();
            const show = trimmed === '' ? '·'.repeat(Math.min(f.len, 8)) : f.raw;
            return (
              <div key={i} style={{ padding:'10px 16px', borderBottom:'1px solid var(--rule-soft)' }}>
                <div className="ff-mono" style={{ fontSize:9, color:'var(--ink-4)', marginBottom:3, letterSpacing:'.04em' }}>
                  @{f.offset} · {f.len}c
                </div>
                <div style={{ fontSize:11, fontWeight:600, marginBottom:4 }}>{f.name}</div>
                <div className="ff-mono" style={{ fontSize:11, color:'var(--ink)', wordBreak:'break-all', whiteSpace:'pre-wrap', background:'var(--paper)', padding:'4px 6px', border:'1px solid var(--rule-soft)' }}>{show}</div>
                {f.decoded && <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:4 }}>→ {f.decoded}</div>}
                {f.hint && !f.decoded && <div className="ff-mono" style={{ fontSize:9, color:'var(--ink-4)', marginTop:4, fontStyle:'italic' }}>{f.hint}</div>}
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  // ─── Validation panel
  function ValidationPanel({ report, onJump }) {
    const { issues, summary } = report;
    const grouped = useMemo(() => {
      const m = { error: [], warning: [], info: [] };
      issues.forEach(i => m[i.severity]?.push(i));
      return m;
    }, [issues]);
    return (
      <div style={{ borderBottom:'1px solid var(--rule)', background:'var(--bg-2)', maxHeight:240, overflowY:'auto' }}>
        <div style={{ display:'flex', gap:24, padding:'10px 16px', borderBottom:'1px solid var(--rule)' }}>
          <Counter n={summary.errors} label="errors" tone="#c0392b" />
          <Counter n={summary.warnings} label="warnings" tone="#d68910" />
          <Counter n={summary.infos} label="info" tone="#3056C8" />
          <div style={{flex:1}} />
          <span className="ff-mono upper" style={{ fontSize:10, color: summary.ok ? '#2e7d4f' : 'var(--ink-3)', letterSpacing:'.1em' }}>
            {summary.ok ? '✓ TRANSMISSION VALID' : 'NOT READY TO SEND'}
          </span>
        </div>
        {issues.length === 0 && (
          <div className="ff-mono" style={{ padding:'18px', fontSize:11, color:'var(--ink-3)' }}>No issues detected. Schema, business rules, and society quirks all pass.</div>
        )}
        {issues.map((iss, i) => (
          <button key={i} onClick={() => onJump(iss.line)} style={{
            display:'grid', gridTemplateColumns:'auto auto 1fr auto', gap:14, alignItems:'center',
            width:'100%', textAlign:'left', padding:'8px 16px', cursor:'pointer',
            background:'transparent', border:0, borderBottom:'1px solid var(--rule-soft)',
          }}>
            <span style={{ width:6, height:6, borderRadius:99,
              background: iss.severity === 'error' ? '#c0392b' : iss.severity === 'warning' ? '#d68910' : '#3056C8' }} />
            <span className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', minWidth:80 }}>L{iss.line+1} · {iss.recordType}</span>
            <span style={{ fontSize:11 }}>
              <span style={{ color:'var(--ink)' }}>{iss.message}</span>
              {iss.fix && <span style={{ color:'var(--ink-3)', marginLeft:8 }}>· {iss.fix}</span>}
            </span>
            <span className="ff-mono" style={{ fontSize:9, color:'var(--ink-4)' }}>{iss.code}</span>
          </button>
        ))}
      </div>
    );
  }
  function Counter({ n, label, tone }) {
    return (
      <div style={{ display:'flex', alignItems:'baseline', gap:6 }}>
        <span className="ff-display" style={{ fontSize:18, fontWeight:600, color: n ? tone : 'var(--ink-3)' }}>{n}</span>
        <span className="ff-mono upper" style={{ fontSize:9, color:'var(--ink-3)', letterSpacing:'.1em' }}>{label}</span>
      </div>
    );
  }

  // ─── Distribute modal
  function DistributeModal({ onClose, agreements, recipient, filename, transmission }) {
    const [transport, setTransport] = useState('sftp');
    const [delivery, setDelivery] = useState('immediate');
    const [scheduleAt, setScheduleAt] = useState('2026-05-13T09:00');
    const [stage, setStage] = useState('config');
    const r = RECIPIENTS.find(x => x.code === recipient) || RECIPIENTS[0];

    const send = () => {
      setStage('sending');
      setTimeout(() => {
        setStage('sent');
        window.toast && window.toast(`CAF queued: ${filename} → ${r.name}`, 'ok');
      }, 700);
    };

    return (
      <div role="dialog" aria-modal="true" style={{
        position:'fixed', inset:0, background:'rgba(14,14,12,.45)', display:'flex',
        alignItems:'center', justifyContent:'center', zIndex:80,
      }} onClick={onClose}>
        <div onClick={e => e.stopPropagation()} style={{
          width:680, maxWidth:'92vw', background:'var(--paper)',
          border:'1px solid var(--rule)', maxHeight:'90vh', overflow:'auto',
        }}>
          <div style={{ padding:'18px 22px', borderBottom:'1px solid var(--rule)', display:'flex', alignItems:'baseline', justifyContent:'space-between' }}>
            <div>
              <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)' }}>DISTRIBUTE CAF</div>
              <div className="ff-display" style={{ fontSize:22, fontWeight:600, letterSpacing:'-.02em', marginTop:4 }}>{filename}</div>
              <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:4 }}>{agreements.length} agreement{agreements.length!==1?'s':''} · {transmission.length} records · → {r.name}</div>
            </div>
            <button onClick={onClose} style={{ background:'transparent', border:0, fontSize:20, cursor:'pointer', color:'var(--ink-3)', lineHeight:1 }}>×</button>
          </div>

          {stage === 'config' && (
            <div style={{ padding:'18px 22px' }}>
              <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:10 }}>TRANSPORT</div>
              <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8, marginBottom:18 }}>
                {[
                  { v:'sftp',   l:'Direct SFTP',     hint: r.gateway },
                  { v:'cisnet', l:'CIS-Net Hub',     hint:'cisnet.cisac.org' },
                  { v:'pgp',    l:'Email + PGP',     hint:'caf-in@'+r.code.toLowerCase()+'.org' },
                  { v:'manual', l:'Download only',   hint:'upload to portal manually' },
                ].map(opt => (
                  <button key={opt.v} onClick={() => setTransport(opt.v)} style={{
                    textAlign:'left', padding:'12px 14px', cursor:'pointer',
                    border: transport === opt.v ? '2px solid var(--ink)' : '1px solid var(--rule)',
                    background: transport === opt.v ? 'var(--bg-2)' : 'transparent',
                  }}>
                    <div style={{ fontSize:12, fontWeight:600 }}>{opt.l}</div>
                    <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:3 }}>{opt.hint}</div>
                  </button>
                ))}
              </div>

              <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:10 }}>SCHEDULE</div>
              <div style={{ display:'flex', gap:8, marginBottom:18 }}>
                {[
                  { v:'immediate', l:'Send now' },
                  { v:'scheduled', l:'Schedule' },
                  { v:'overnight', l:'Off-hours batch' },
                ].map(opt => (
                  <button key={opt.v} onClick={() => setDelivery(opt.v)} className="ff-mono upper" style={{
                    flex:1, padding:'10px 12px', fontSize:10, letterSpacing:'.08em', cursor:'pointer',
                    border: delivery === opt.v ? '2px solid var(--ink)' : '1px solid var(--rule)',
                    background: delivery === opt.v ? 'var(--ink)' : 'transparent',
                    color: delivery === opt.v ? 'var(--paper)' : 'var(--ink)',
                  }}>{opt.l}</button>
                ))}
              </div>
              {delivery === 'scheduled' && (
                <input type="datetime-local" value={scheduleAt} onChange={e => setScheduleAt(e.target.value)} className="ff-mono"
                  style={{ width:'100%', padding:'8px 10px', fontSize:11, background:'var(--paper)', border:'1px solid var(--rule)', marginBottom:18, boxSizing:'border-box' }} />
              )}

              <div style={{ padding:'14px 16px', background:'var(--bg-2)', border:'1px solid var(--rule-soft)', marginBottom:18 }}>
                <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:6 }}>TRANSMISSION SUMMARY</div>
                <div style={{ display:'grid', gridTemplateColumns:'auto 1fr', gap:'4px 16px', fontSize:11 }}>
                  <span className="ff-mono" style={{color:'var(--ink-3)'}}>From</span><span>PLURALIS MUSIC · IPI 199900001</span>
                  <span className="ff-mono" style={{color:'var(--ink-3)'}}>To</span><span>{r.name} · soc {String(r.soc).padStart(3,'0')} · {r.tz}</span>
                  <span className="ff-mono" style={{color:'var(--ink-3)'}}>Format</span><span>CAF v1.2 fixed-width</span>
                  <span className="ff-mono" style={{color:'var(--ink-3)'}}>Agreements</span><span>{agreements.length}</span>
                  <span className="ff-mono" style={{color:'var(--ink-3)'}}>Records</span><span>{transmission.length} ({transmission.reduce((s,l)=>s+l.length,0).toLocaleString()} chars)</span>
                </div>
              </div>

              <div style={{ display:'flex', gap:8, justifyContent:'flex-end' }}>
                <button onClick={onClose} className="ff-mono upper" style={btnSecondary}>cancel</button>
                <button onClick={send} className="ff-mono upper" style={btnPrimary}>send</button>
              </div>
            </div>
          )}

          {stage === 'sending' && (
            <div style={{ padding:'40px 22px', textAlign:'center' }}>
              <div className="ff-mono upper" style={{ fontSize:11, letterSpacing:'.12em', color:'var(--ink-3)' }}>HANDSHAKING WITH {r.gateway}…</div>
            </div>
          )}

          {stage === 'sent' && (
            <div style={{ padding:'30px 22px' }}>
              <div className="ff-display" style={{ fontSize:22, fontWeight:600, letterSpacing:'-.02em', marginBottom:6 }}>Queued for delivery</div>
              <div className="ff-mono" style={{ fontSize:11, color:'var(--ink-3)', marginBottom:18 }}>
                Tracking ID <strong style={{color:'var(--ink)'}}>CAF-{Date.now().toString(36).toUpperCase().slice(-8)}</strong> · 
                {delivery === 'immediate' ? ' transmitting now' : delivery === 'scheduled' ? ` scheduled ${scheduleAt}` : ' queued for next off-hours window'}
              </div>
              <div style={{ display:'flex', gap:8, justifyContent:'flex-end' }}>
                <button onClick={onClose} className="ff-mono upper" style={btnPrimary}>done</button>
              </div>
            </div>
          )}
        </div>
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════ OUTBOX TAB
  function OutboxTab() {
    const rows = useMemo(buildOutbox, []);
    const [pickedId, setPickedId] = useState(rows[0]?.id);
    const picked = rows.find(r => r.id === pickedId) || rows[0];
    return (
      <div style={{ display:'grid', gridTemplateColumns:'1.2fr 1fr', gap:0, border:'1px solid var(--rule)' }}>
        <div style={{ borderRight:'1px solid var(--rule)' }}>
          <table className="ff-mono" style={{ width:'100%', borderCollapse:'collapse', fontSize:11 }}>
            <thead>
              <tr style={{ background:'var(--bg-2)', borderBottom:'1px solid var(--rule)' }}>
                <Th>FILE</Th><Th>RECIPIENT</Th><Th>SENT</Th><Th>AGR</Th><Th>STATUS</Th>
              </tr>
            </thead>
            <tbody>
              {rows.map(r => (
                <tr key={r.id} onClick={() => setPickedId(r.id)} style={{
                  cursor:'pointer', borderBottom:'1px solid var(--rule-soft)',
                  background: picked?.id === r.id ? 'var(--bg-2)' : 'transparent',
                }}>
                  <td style={{ padding:'10px 12px' }}>{r.filename}</td>
                  <td style={{ padding:'10px 12px' }}>{r.recipient}</td>
                  <td style={{ padding:'10px 12px', color:'var(--ink-3)' }}>{r.sent}</td>
                  <td style={{ padding:'10px 12px', color:'var(--ink-3)' }}>{r.agreementCount}</td>
                  <td style={{ padding:'10px 12px' }}><StatusPill s={r.status} /></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div style={{ padding:'18px 22px' }}>
          {picked && <OutboxDetail row={picked} />}
        </div>
      </div>
    );
  }
  function Th({ children }) { return <th style={{ textAlign:'left', padding:'9px 12px', fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', fontWeight:600, textTransform:'uppercase' }}>{children}</th>; }
  function StatusPill({ s }) {
    const map = {
      sent:    { tone:'#3056C8', label:'SENT' },
      acked:   { tone:'#2e7d4f', label:'ACKED' },
      partial: { tone:'#d68910', label:'PARTIAL' },
      failed:  { tone:'#c0392b', label:'FAILED' },
      pending: { tone:'#6e6a60', label:'PENDING' },
      conflict:{ tone:'#a04432', label:'CONFLICT' },
    };
    const m = map[s] || map.pending;
    return (
      <span className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.08em', padding:'3px 7px', background:m.tone, color:'#fff' }}>{m.label}</span>
    );
  }
  function OutboxDetail({ row }) {
    return (
      <div>
        <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:6 }}>TRANSMISSION</div>
        <div className="ff-display" style={{ fontSize:20, fontWeight:600, letterSpacing:'-.02em', marginBottom:4 }}>{row.filename}</div>
        <div className="ff-mono" style={{ fontSize:11, color:'var(--ink-3)', marginBottom:18 }}>{row.transport} · {row.gateway}</div>
        <div style={{ display:'grid', gridTemplateColumns:'auto 1fr', gap:'8px 18px', fontSize:11, marginBottom:20 }}>
          <span className="ff-mono" style={{color:'var(--ink-3)'}}>Sent</span><span>{row.sent}</span>
          <span className="ff-mono" style={{color:'var(--ink-3)'}}>Recipient</span><span>{row.recipient}</span>
          <span className="ff-mono" style={{color:'var(--ink-3)'}}>Agreements</span><span>{row.agreementCount}</span>
          <span className="ff-mono" style={{color:'var(--ink-3)'}}>Records</span><span>{row.recordCount}</span>
          <span className="ff-mono" style={{color:'var(--ink-3)'}}>Status</span><StatusPill s={row.status} />
          {row.ackedAt && (<><span className="ff-mono" style={{color:'var(--ink-3)'}}>Acked</span><span>{row.ackedAt}</span></>)}
          {row.trackingId && (<><span className="ff-mono" style={{color:'var(--ink-3)'}}>Tracking</span><span className="ff-mono">{row.trackingId}</span></>)}
        </div>

        <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:8 }}>LIFECYCLE</div>
        <Timeline events={row.events} />

        <div style={{ display:'flex', gap:8, marginTop:20 }}>
          <button className="ff-mono upper" style={btnSecondary}>resend</button>
          <button className="ff-mono upper" style={btnSecondary}>download .V12</button>
          {row.status === 'failed' && <button className="ff-mono upper" style={btnPrimary}>retry</button>}
        </div>
      </div>
    );
  }
  function Timeline({ events }) {
    return (
      <ol style={{ listStyle:'none', padding:0, margin:0 }}>
        {events.map((e, i) => (
          <li key={i} style={{ display:'grid', gridTemplateColumns:'14px 1fr', gap:10, padding:'8px 0', position:'relative' }}>
            <span style={{ width:8, height:8, borderRadius:99, background: e.tone || 'var(--ink)', marginTop:5 }} />
            <div>
              <div style={{ fontSize:11, fontWeight:600 }}>{e.label}</div>
              <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:2 }}>{e.at}{e.detail ? ' · ' + e.detail : ''}</div>
            </div>
          </li>
        ))}
      </ol>
    );
  }
  function buildOutbox() {
    return [
      { id:'tx1', filename:'CA260821PLU_SAC.V12', recipient:'SACEM', transport:'Direct SFTP', gateway:'edi.sacem.fr', sent:'2026-04-30 14:22', agreementCount:14, recordCount:124, status:'acked', ackedAt:'2026-04-30 16:08', trackingId:'CAF-Q8AX2L1', events:[
        { at:'2026-04-30 14:22', label:'Queued for transmission', tone:'#3056C8' },
        { at:'2026-04-30 14:22', label:'Connected to edi.sacem.fr (SFTP)', tone:'#3056C8' },
        { at:'2026-04-30 14:23', label:'File transferred (124 records)', tone:'#3056C8' },
        { at:'2026-04-30 16:08', label:'AGR-ACK received · 14 accepted', tone:'#2e7d4f', detail:'all transactions accepted' },
      ]},
      { id:'tx2', filename:'CA260820PLU_GEM.V12', recipient:'GEMA', transport:'Direct SFTP', gateway:'edi.gema.de', sent:'2026-04-29 23:00', agreementCount:8, recordCount:71, status:'partial', ackedAt:'2026-04-30 04:14', trackingId:'CAF-Q88WP3F', events:[
        { at:'2026-04-29 23:00', label:'Off-hours batch picked up', tone:'#3056C8' },
        { at:'2026-04-29 23:01', label:'File transferred', tone:'#3056C8' },
        { at:'2026-04-30 04:14', label:'AGR-ACK · 6 accepted, 2 conflict', tone:'#d68910', detail:'2 conflicts flagged for review' },
      ]},
      { id:'tx3', filename:'CA260819PLU_PRS.V12', recipient:'PRS', transport:'CIS-Net Hub', gateway:'cisnet.cisac.org', sent:'2026-04-28 11:45', agreementCount:21, recordCount:178, status:'acked', ackedAt:'2026-04-28 13:02', trackingId:'CAF-Q8581ZQ', events:[
        { at:'2026-04-28 11:45', label:'Submitted to CIS-Net', tone:'#3056C8' },
        { at:'2026-04-28 12:01', label:'Forwarded to PRS', tone:'#3056C8' },
        { at:'2026-04-28 13:02', label:'AGR-ACK received · all 21 accepted', tone:'#2e7d4f' },
      ]},
      { id:'tx4', filename:'CA260818PLU_BMI.V12', recipient:'BMI', transport:'Direct SFTP', gateway:'caf.bmi.com', sent:'2026-04-26 09:15', agreementCount:33, recordCount:284, status:'failed', trackingId:'CAF-Q83K6XB', events:[
        { at:'2026-04-26 09:15', label:'Connection attempt', tone:'#3056C8' },
        { at:'2026-04-26 09:16', label:'Auth failed · key rotated', tone:'#c0392b', detail:'BMI rotated SFTP keys 04/24' },
      ]},
      { id:'tx5', filename:'CA260817PLU_JAS.V12', recipient:'JASRAC', transport:'Email + PGP', gateway:'caf-in@jasrac.or.jp', sent:'2026-04-25 22:30', agreementCount:6, recordCount:54, status:'sent', trackingId:'CAF-Q827YNT', events:[
        { at:'2026-04-25 22:30', label:'PGP-signed email sent', tone:'#3056C8' },
        { at:'2026-04-25 22:30', label:'Awaiting AGR-ACK · ETA 5–7 days', tone:'#6e6a60' },
      ]},
      { id:'tx6', filename:'CA260815PLU_SCN.V12', recipient:'SOCAN', transport:'Direct SFTP', gateway:'caf.socan.com', sent:'2026-04-22 16:00', agreementCount:4, recordCount:33, status:'conflict', ackedAt:'2026-04-23 11:50', trackingId:'CAF-Q7Y2HR5', events:[
        { at:'2026-04-22 16:00', label:'Submitted', tone:'#3056C8' },
        { at:'2026-04-23 11:50', label:'AGR-ACK · 1 accepted, 3 conflict', tone:'#a04432', detail:'overlap with prior assignor claims' },
      ]},
    ];
  }

  // ═══════════════════════════════════════════════════════ ACKS TAB
  function AcksTab() {
    const rows = useMemo(buildAcks, []);
    return (
      <div style={{ border:'1px solid var(--rule)' }}>
        <table className="ff-mono" style={{ width:'100%', borderCollapse:'collapse', fontSize:11 }}>
          <thead>
            <tr style={{ background:'var(--bg-2)', borderBottom:'1px solid var(--rule)' }}>
              <Th>FILE</Th><Th>SOCIETY</Th><Th>RECEIVED</Th><Th>TXN</Th><Th>AC</Th><Th>CO</Th><Th>RJ</Th><Th>OTHER</Th><Th></Th>
            </tr>
          </thead>
          <tbody>
            {rows.map(r => (
              <tr key={r.id} style={{ borderBottom:'1px solid var(--rule-soft)' }}>
                <td style={{ padding:'10px 12px' }}>{r.filename}</td>
                <td style={{ padding:'10px 12px' }}>{r.society}</td>
                <td style={{ padding:'10px 12px', color:'var(--ink-3)' }}>{r.received}</td>
                <td style={{ padding:'10px 12px' }}>{r.txn}</td>
                <td style={{ padding:'10px 12px', color:'#2e7d4f', fontWeight:600 }}>{r.accepted}</td>
                <td style={{ padding:'10px 12px', color:'#a04432', fontWeight: r.conflict ? 600 : 400 }}>{r.conflict || '·'}</td>
                <td style={{ padding:'10px 12px', color:'#c0392b', fontWeight: r.rejected ? 600 : 400 }}>{r.rejected || '·'}</td>
                <td style={{ padding:'10px 12px', color:'var(--ink-3)' }}>{r.other || '·'}</td>
                <td style={{ padding:'10px 12px', textAlign:'right' }}>
                  <button className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.08em', padding:'4px 8px', border:'1px solid var(--rule)', background:'transparent', cursor:'pointer' }}>open</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    );
  }
  function buildAcks() {
    return [
      { id:'a1', filename:'AGR-ACK-260430-SAC-0142.V12', society:'SACEM', received:'2026-04-30 16:08', txn:14, accepted:14, conflict:0, rejected:0, other:0 },
      { id:'a2', filename:'AGR-ACK-260430-GEM-0089.V12', society:'GEMA',  received:'2026-04-30 04:14', txn:8,  accepted:6, conflict:2, rejected:0, other:0 },
      { id:'a3', filename:'AGR-ACK-260428-PRS-0218.V12', society:'PRS',   received:'2026-04-28 13:02', txn:21, accepted:21, conflict:0, rejected:0, other:0 },
      { id:'a4', filename:'AGR-ACK-260423-SCN-0011.V12', society:'SOCAN', received:'2026-04-23 11:50', txn:4,  accepted:1, conflict:3, rejected:0, other:0 },
      { id:'a5', filename:'AGR-ACK-260418-BMI-0331.V12', society:'BMI',   received:'2026-04-18 09:33', txn:18, accepted:14, conflict:1, rejected:2, other:1 },
      { id:'a6', filename:'AGR-ACK-260415-ASC-0508.V12', society:'ASCAP', received:'2026-04-15 14:18', txn:27, accepted:25, conflict:0, rejected:1, other:1 },
    ];
  }

  // ═══════════════════════════════════════════════════════ CONFLICTS TAB
  function ConflictsTab({ go }) {
    const rows = useMemo(buildConflicts, []);
    const [picked, setPicked] = useState(rows[0]?.id);
    const sel = rows.find(x => x.id === picked) || rows[0];
    return (
      <div style={{ display:'grid', gridTemplateColumns:'1fr 1.2fr', border:'1px solid var(--rule)' }}>
        <div style={{ borderRight:'1px solid var(--rule)' }}>
          {rows.map(r => (
            <button key={r.id} onClick={() => setPicked(r.id)} style={{
              display:'block', width:'100%', textAlign:'left', padding:'14px 16px',
              cursor:'pointer', background: sel?.id === r.id ? 'var(--bg-2)' : 'transparent',
              border:0, borderBottom:'1px solid var(--rule-soft)',
            }}>
              <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:4 }}>
                <span className="ff-mono" style={{ fontSize:11, fontWeight:600 }}>{r.agreementId}</span>
                <span className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.08em', padding:'2px 6px', background:'#a04432', color:'#fff' }}>CO</span>
              </div>
              <div style={{ fontSize:12, fontWeight:500, marginBottom:4 }}>{r.title}</div>
              <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)' }}>{r.society} · {r.kind} · {r.detectedAt}</div>
            </button>
          ))}
        </div>
        <div style={{ padding:'20px 24px' }}>
          {sel && <ConflictDetail c={sel} go={go} />}
        </div>
      </div>
    );
  }
  function ConflictDetail({ c, go }) {
    return (
      <div>
        <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:6 }}>CONFLICT · {c.code}</div>
        <div className="ff-display" style={{ fontSize:22, fontWeight:600, letterSpacing:'-.02em', marginBottom:4 }}>{c.title}</div>
        <div className="ff-mono" style={{ fontSize:11, color:'var(--ink-3)', marginBottom:20 }}>
          {c.agreementId} · {c.society} · detected {c.detectedAt}
        </div>

        <div style={{ padding:'14px 16px', background:'var(--bg-2)', border:'1px solid var(--rule-soft)', marginBottom:18 }}>
          <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:6 }}>SOCIETY MESSAGE</div>
          <div style={{ fontSize:12, lineHeight:1.5 }}>{c.message}</div>
        </div>

        <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:8 }}>OVERLAP</div>
        <table style={{ width:'100%', borderCollapse:'collapse', fontSize:11, marginBottom:20 }}>
          <thead>
            <tr style={{ borderBottom:'1px solid var(--rule)' }}>
              <Th>YOUR CLAIM</Th><Th>EXISTING</Th><Th>FIELD</Th>
            </tr>
          </thead>
          <tbody>
            {c.overlap.map((o, i) => (
              <tr key={i} style={{ borderBottom:'1px solid var(--rule-soft)' }}>
                <td style={{ padding:'9px 12px' }}>{o.yours}</td>
                <td style={{ padding:'9px 12px', color:'var(--ink-3)' }}>{o.theirs}</td>
                <td style={{ padding:'9px 12px' }} className="ff-mono">{o.field}</td>
              </tr>
            ))}
          </tbody>
        </table>

        <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
          <button className="ff-mono upper" style={btnPrimary}>resolve & resubmit</button>
          <button className="ff-mono upper" style={btnSecondary}>contact society</button>
          <button className="ff-mono upper" style={btnSecondary}>open agreement</button>
          <button className="ff-mono upper" style={btnSecondary}>withdraw claim</button>
        </div>
      </div>
    );
  }
  function buildConflicts() {
    return [
      { id:'c1', agreementId:'AG-2024-014', title:'Pluralis Music × WC Pueblo Music', society:'GEMA',  kind:'Territory overlap', code:'CO-TER-002', detectedAt:'2026-04-30',
        message:'Submitted territory (Worldwide ex US) overlaps existing agreement #GEM-AGR-918244 (Solange Roca Vega → Edition Atelier Berlin) for territory DE/AT/CH 2023-01-01 → 2026-12-31.',
        overlap: [
          { yours:'Worldwide ex US', theirs:'DE / AT / CH', field:'TER inclusion' },
          { yours:'2024-01-01 → 2027-12-31', theirs:'2023-01-01 → 2026-12-31', field:'Term' },
          { yours:'AS · Solange Roca Vega · IPI 28471605911', theirs:'AS · Solange Roca Vega · IPI 28471605911', field:'Assignor IPI' },
        ]},
      { id:'c2', agreementId:'AG-2025-007', title:'Devonté Carter Sub-Pub × Edition Atelier', society:'SOCAN', kind:'Share inconsistency', code:'CO-SHR-014', detectedAt:'2026-04-23',
        message:'Acquirer PR shares (75%) exceed available residual on this assignor — existing SOCAN registration assigns 50% PR to Carter Songs LLC for the same period.',
        overlap: [
          { yours:'75.00% PR', theirs:'50.00% PR (Carter Songs LLC)', field:'IPA · PR share' },
          { yours:'Worldwide', theirs:'Worldwide', field:'TER inclusion' },
        ]},
      { id:'c3', agreementId:'AG-2024-029', title:'Glasshouse Mornings · admin', society:'SOCAN', kind:'Date mismatch', code:'CO-DTE-008', detectedAt:'2026-04-23',
        message:'Date of signature (2024-03-15) precedes earliest admissible signature date in society registry. Verify and resubmit with corrected AGR field 14.',
        overlap: [
          { yours:'2024-03-15', theirs:'≥ 2024-04-01 (society constraint)', field:'AGR · date of signature' },
        ]},
      { id:'c4', agreementId:'AG-2025-012', title:'Roca Recordings · catalog admin', society:'SOCAN', kind:'Party not registered', code:'CO-IPA-021', detectedAt:'2026-04-23',
        message:'Acquirer IPI 47728165033 is not registered in SOCAN’s database. Either register via IPI Online first, or supply a verified IPI base number.',
        overlap: [
          { yours:'IPI 47728165033', theirs:'(not in registry)', field:'IPA · acquirer IPI' },
        ]},
    ];
  }

  // ─── Shared button styles
  const btnPrimary = { padding:'8px 14px', fontSize:10, fontWeight:600, letterSpacing:'.08em', background:'var(--ink)', color:'var(--paper)', border:0, cursor:'pointer' };
  const btnSecondary = { padding:'8px 12px', fontSize:10, fontWeight:600, letterSpacing:'.08em', background:'var(--paper)', color:'var(--ink)', border:'1px solid var(--rule)', cursor:'pointer' };

  window.ScreenCaf = ScreenCaf;
  window.CafGenTab = CafGenTab;
  window.CafOutboxTab = OutboxTab;
  window.CafAcksTab = AcksTab;
  // ═══════════════════════════════════════════════════════ COMPLIANCE TAB
  function ComplianceTab() {
    const [run, setRun] = useState(null);
    const [running, setRunning] = useState(false);
    useEffect(() => { execute(); }, []);
    const execute = () => {
      setRunning(true);
      setTimeout(() => {
        const r = window.CafFixtures ? window.CafFixtures.run() : { results: [], passed: 0, total: 0, pct: 0 };
        setRun(r); setRunning(false);
      }, 80);
    };
    const recordCoverage = useMemo(() => {
      const v12 = window.CafSpec?.RECORDS_V12 || {};
      const v30 = window.CafSpec?.RECORDS_V30 || {};
      const rows = [];
      const keys = Array.from(new Set([...Object.keys(v12), ...Object.keys(v30)]));
      for (const k of keys) {
        const r12 = v12[k]; const r30 = v30[k];
        rows.push({ type: k, label: r12?.label || r30?.label || k,
          v12Len: r12?.length || null, v12Fields: r12?.fields?.length || 0,
          v30Len: r30?.length || null, v30Fields: r30?.fields?.length || 0,
          required: r12?.required || r30?.required, cardinality: r12?.cardinality || r30?.cardinality });
      }
      return rows;
    }, []);
    const groups = useMemo(() => {
      if (!run) return {};
      const m = {};
      for (const r of run.results) { (m[r.group] = m[r.group] || []).push(r); }
      return m;
    }, [run]);
    const bySoc = useMemo(() => {
      if (!run) return {};
      const m = {};
      for (const r of run.results) {
        const s = r.society || 'all';
        if (!m[s]) m[s] = { passed: 0, total: 0 };
        m[s].total += 1; if (r.ok) m[s].passed += 1;
      }
      return m;
    }, [run]);

    return (
      <div style={{ border:'1px solid var(--rule)' }}>
        {/* Top KPIs */}
        <div style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', borderBottom:'1px solid var(--rule)' }}>
          <KPI label="Fixture pass" value={run ? run.passed + '/' + run.total : '—'} sub={run ? run.pct + '% PASS' : (running ? 'running…' : '')} tone={run && run.pct === 100 ? '#2e7d4f' : run && run.pct >= 75 ? '#d68910' : '#c0392b'} />
          <KPI label="v1.2 records" value={Object.keys(window.CafSpec?.RECORDS_V12 || {}).length} sub="spec-encoded" />
          <KPI label="v3.0 records" value={Object.keys(window.CafSpec?.RECORDS_V30 || {}).length} sub="with deltas" />
          <KPI label="Spec integrity" value={(window.CafSpec?.integrity?.length || 0) === 0 ? 'OK' : 'FAIL'} sub={`${(window.CafSpec?.integrity?.length || 0)} mismatches`} tone={(window.CafSpec?.integrity?.length || 0) === 0 ? '#2e7d4f' : '#c0392b'} />
        </div>

        <div style={{ display:'grid', gridTemplateColumns:'1.2fr 1fr', minHeight:480 }}>
          {/* LEFT: fixture results */}
          <div style={{ borderRight:'1px solid var(--rule)' }}>
            <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'12px 16px', borderBottom:'1px solid var(--rule)', background:'var(--bg-2)' }}>
              <div className="ff-mono upper" style={{ fontSize:10, letterSpacing:'.12em', color:'var(--ink-3)' }}>FIXTURE SUITE</div>
              <button onClick={execute} className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.08em', padding:'5px 9px', background:'var(--paper)', border:'1px solid var(--rule)', cursor:'pointer' }}>RE-RUN</button>
            </div>
            {!run && <div className="ff-mono" style={{ padding:24, color:'var(--ink-3)', fontSize:11 }}>{running ? 'running fixture harness…' : 'awaiting run'}</div>}
            {run && Object.entries(groups).map(([g, rs]) => (
              <div key={g}>
                <div className="ff-mono upper" style={{ padding:'8px 16px', fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)', background:'var(--bg-2)', borderBottom:'1px solid var(--rule-soft)' }}>
                  {g} · {rs.filter(r => r.ok).length}/{rs.length}
                </div>
                {rs.map(r => (
                  <div key={r.id} style={{ display:'grid', gridTemplateColumns:'10px 1fr auto', alignItems:'center', gap:12, padding:'9px 16px', borderBottom:'1px solid var(--rule-soft)' }}>
                    <span style={{ width:8, height:8, borderRadius:99, background: r.ok ? '#2e7d4f' : '#c0392b' }} />
                    <div>
                      <div style={{ fontSize:11.5 }}>{r.label}</div>
                      <div className="ff-mono" style={{ fontSize:9.5, color:'var(--ink-3)', marginTop:2 }}>{r.id} · {r.version} · {r.society}{r.message ? ' · ' + r.message : ''}</div>
                    </div>
                    <span className="ff-mono" style={{ fontSize:9, color:'var(--ink-3)' }}>{r.ms}ms</span>
                  </div>
                ))}
              </div>
            ))}
          </div>

          {/* RIGHT: spec coverage */}
          <div>
            <div style={{ padding:'12px 16px', borderBottom:'1px solid var(--rule)', background:'var(--bg-2)' }}>
              <div className="ff-mono upper" style={{ fontSize:10, letterSpacing:'.12em', color:'var(--ink-3)' }}>SPEC COVERAGE · v1.2 vs v3.0</div>
            </div>
            <table className="ff-mono" style={{ width:'100%', borderCollapse:'collapse', fontSize:11 }}>
              <thead>
                <tr style={{ borderBottom:'1px solid var(--rule)' }}>
                  <Th>REC</Th><Th>LABEL</Th><Th>v1.2</Th><Th>v3.0</Th><Th>FIELDS</Th>
                </tr>
              </thead>
              <tbody>
                {recordCoverage.map(r => (
                  <tr key={r.type} style={{ borderBottom:'1px solid var(--rule-soft)' }}>
                    <td style={{ padding:'7px 12px', fontWeight:600, color: TYPE_COLOR[r.type] || 'var(--ink)' }}>{r.type}</td>
                    <td style={{ padding:'7px 12px', color:'var(--ink-3)' }}>{r.label}</td>
                    <td style={{ padding:'7px 12px' }}>{r.v12Len ? r.v12Len + 'c' : '—'}</td>
                    <td style={{ padding:'7px 12px' }}>{r.v30Len ? (r.v30Len === r.v12Len ? '=' : r.v30Len + 'c') : '—'}</td>
                    <td style={{ padding:'7px 12px', color:'var(--ink-3)' }}>{r.v12Fields || r.v30Fields}</td>
                  </tr>
                ))}
              </tbody>
            </table>

            <div style={{ padding:'12px 16px', borderBottom:'1px solid var(--rule)', borderTop:'1px solid var(--rule)', background:'var(--bg-2)' }}>
              <div className="ff-mono upper" style={{ fontSize:10, letterSpacing:'.12em', color:'var(--ink-3)' }}>SOCIETY READINESS</div>
            </div>
            <div style={{ padding:'8px 0' }}>
              {Object.entries(bySoc).map(([soc, st]) => (
                <div key={soc} style={{ display:'grid', gridTemplateColumns:'90px 1fr 60px', gap:12, alignItems:'center', padding:'7px 16px', borderBottom:'1px solid var(--rule-soft)' }}>
                  <span className="ff-mono" style={{ fontSize:11, fontWeight:600 }}>{soc}</span>
                  <div style={{ height:6, background:'var(--rule-soft)', position:'relative' }}>
                    <div style={{ position:'absolute', left:0, top:0, bottom:0, width:Math.round(st.passed/st.total*100)+'%', background: st.passed === st.total ? '#2e7d4f' : '#d68910' }} />
                  </div>
                  <span className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', textAlign:'right' }}>{st.passed}/{st.total}</span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    );
  }
  function KPI({ label, value, sub, tone }) {
    return (
      <div style={{ padding:'14px 18px', borderRight:'1px solid var(--rule)' }}>
        <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)' }}>{label}</div>
        <div className="ff-display" style={{ fontSize:26, fontWeight:600, letterSpacing:'-.02em', color: tone || 'var(--ink)', marginTop:4 }}>{value}</div>
        {sub && <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:2 }}>{sub}</div>}
      </div>
    );
  }

  window.CafConflictsTab = ConflictsTab;
  window.CafComplianceTab = ComplianceTab;
})();
