// predict.jsx — Main UI for ASTRO predictions module
// ─────────────────────────────────────────────────────────────────
// Renders 5 prediction surfaces:
//   01 SUCCESS · per-song hit-potential scorecard (drawer + embed)
//   02 SALES   · territory/DSP optimization with recs
//   03 PLAYLIST · likelihood of editorial placement
//   04 MINING  · catalog ranked by upside
//   05 SYNC    · cinematic-fit per archetype
//
// EXPORT: window.ScreenPredictions, window.PredictScorecard
// ─────────────────────────────────────────────────────────────────
(function () {
  if (typeof window === 'undefined') return;
  const _S = React.useState, _M = React.useMemo, _E = React.useEffect;
  const E = window.PredictEngine;
  if (!E) { console.error('predict.jsx: PredictEngine missing'); return; }

  const fmt = (n) => Math.round(n).toLocaleString();
  const fmtK = (n) => n >= 1_000_000 ? (n/1_000_000).toFixed(2)+'M' : n >= 1000 ? (n/1000).toFixed(1)+'k' : Math.round(n).toString();
  const fmtPct = (n, sign) => (sign && n > 0 ? '+' : '') + Math.round(n*100) + '%';
  const fmtUsd = (n) => '$' + fmtK(n);

  // ─── Mono helper
  function Mono({ children, upper, size, color, style, ...rest }) {
    return <span className={'ff-mono' + (upper?' upper':'')} style={{ fontSize: size||11, color: color||'var(--ink)', letterSpacing: upper?'.08em':0, ...style }} {...rest}>{children}</span>;
  }

  // ─── Score badge: big circular-ish display
  function ScoreBadge({ score, conf, bucket, large }) {
    const color = score > 75 ? '#0a8754' : score > 60 ? '#0070d6' : score > 45 ? '#d4881f' : score > 30 ? '#a35418' : '#a32a18';
    const sz = large ? 92 : 56;
    return (
      <div style={{ display:'inline-flex', alignItems:'center', gap: 12 }}>
        <div style={{
          width: sz, height: sz, borderRadius: '50%',
          border: '2px solid '+color, color: color,
          display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center',
          fontFamily: 'var(--ff-mono, monospace)', fontWeight: 500,
        }}>
          <div style={{ fontSize: large?28:18, lineHeight:1 }}>{score}</div>
          <div style={{ fontSize: large?9:8, opacity:0.7, marginTop:2 }}>/100</div>
        </div>
        {bucket && (
          <div>
            <Mono upper size={9} color="var(--ink-3)">{bucket.toUpperCase()}</Mono>
            {conf != null && <div style={{ fontSize: 11, color:'var(--ink-2)', marginTop:3 }}>conf {Math.round(conf*100)}%</div>}
          </div>
        )}
      </div>
    );
  }

  // ─── Attribution waterfall (for success score)
  function Attribution({ items }) {
    return (
      <div>
        <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>FEATURE ATTRIBUTION</Mono>
        {items.map((it, i) => (
          <div key={i} style={{ display:'grid', gridTemplateColumns:'140px 1fr 60px 50px', gap: 10, alignItems:'center', padding:'7px 0', borderBottom:'1px solid var(--rule-soft)' }}>
            <div style={{ fontSize: 12, color:'var(--ink-2)' }}>{it.k}</div>
            <div style={{ height: 6, background:'var(--bg-2)', position:'relative' }}>
              <div style={{ position:'absolute', left:0, top:0, height:'100%', width: it.v+'%', background:'var(--ink)' }}/>
            </div>
            <Mono size={11} color="var(--ink)" style={{ textAlign:'right' }}>{Math.round(it.v)}</Mono>
            <Mono size={10} color="var(--ink-3)" style={{ textAlign:'right' }}>×{it.w.toFixed(2)}</Mono>
          </div>
        ))}
      </div>
    );
  }

  // ─── 01 SCORECARD (per-song)
  function PredictScorecard({ rec, embed, onClose }) {
    const [tab, setTab] = _S('overview');
    const card = _M(() => E.scorecard(rec, { allRecs: window.RECORDINGS || [] }), [rec && rec.id]);
    if (!card) return null;
    const TABS = [
      { k:'overview',  l:'Overview' },
      { k:'sales',     l:'Sales' },
      { k:'playlist',  l:'Playlists' },
      { k:'sync',      l:'Sync' },
      { k:'comps',     l:'Comps' },
    ];

    return (
      <div style={{ background: 'var(--paper)', border: embed ? 0 : '1px solid var(--rule)', padding: embed ? 0 : '24px 28px' }}>
        {!embed && (
          <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom: 18 }}>
            <div>
              <Mono upper size={9} color="var(--ink-3)">PREDICTION SCORECARD</Mono>
              <div style={{ fontSize: 22, fontWeight: 500, letterSpacing:'-0.01em', marginTop: 4 }}>{rec.title || rec.name || 'Untitled'}</div>
              {rec.isrc && <Mono size={11} color="var(--ink-3)" style={{ marginTop: 2, display:'block' }}>{rec.isrc}</Mono>}
            </div>
            {onClose && <button onClick={onClose} className="ff-mono upper" style={{ fontSize: 10, padding:'6px 12px', background:'transparent', border:'1px solid var(--rule)', cursor:'pointer', color:'var(--ink-2)' }}>CLOSE ✕</button>}
          </div>
        )}

        {/* Hero score row */}
        <div style={{ display:'grid', gridTemplateColumns:'auto 1fr auto', gap: 24, alignItems:'center', padding:'18px 0', borderTop: embed?0:'1px solid var(--rule)', borderBottom:'1px solid var(--rule)' }}>
          <ScoreBadge score={card.success.score} conf={card.success.conf} bucket={card.success.bucket} large/>
          <div>
            <Mono upper size={9} color="var(--ink-3)">PROJECTED 90-DAY STREAMS</Mono>
            <div style={{ fontSize: 24, fontWeight: 500, marginTop: 4 }}>
              {fmt(card.sales.projected)}
              <span style={{ fontSize: 13, marginLeft: 10, color: card.sales.delta > 0 ? '#0a8754' : '#a32a18' }}>
                {fmtPct(card.sales.deltaPct, true)}
              </span>
            </div>
            <Mono size={11} color="var(--ink-3)" style={{ marginTop:3, display:'block' }}>
              vs {fmt(card.sales.currentTotal)} current · conf {Math.round(card.sales.conf*100)}%
            </Mono>
          </div>
          <div style={{ textAlign:'right' }}>
            <Mono upper size={9} color="var(--ink-3)">TOP RECOMMENDATION</Mono>
            <div style={{ fontSize: 13, fontWeight: 500, marginTop: 4, maxWidth: 280, textAlign:'left' }}>{card.sales.recs[0]?.title}</div>
          </div>
        </div>

        {/* Tabs */}
        <div style={{ display:'flex', borderBottom:'1px solid var(--rule)', margin:'18px 0 0' }}>
          {TABS.map(t => (
            <button key={t.k} onClick={()=>setTab(t.k)} className="ff-mono upper" style={{
              padding:'10px 16px', background:'transparent', border:0,
              borderBottom:'2px solid '+(tab===t.k?'var(--ink)':'transparent'),
              cursor:'pointer', color: tab===t.k?'var(--ink)':'var(--ink-3)', fontSize: 10, letterSpacing:'.1em',
            }}>{t.l}</button>
          ))}
        </div>

        <div style={{ paddingTop: 18 }}>
          {tab==='overview' && <CardOverview card={card}/>}
          {tab==='sales' && <CardSales card={card}/>}
          {tab==='playlist' && <CardPlaylist card={card}/>}
          {tab==='sync' && <CardSync card={card}/>}
          {tab==='comps' && <CardComps card={card}/>}
        </div>
      </div>
    );
  }

  function CardOverview({ card }) {
    const f = card.feat;
    return (
      <div style={{ display:'grid', gridTemplateColumns:'1.2fr 1fr', gap: 28 }}>
        <div>
          <Attribution items={card.success.attribution}/>
          <div style={{ marginTop: 22 }}>
            <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>SIGNAL SNAPSHOT</Mono>
            <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap: 10 }}>
              <Sig l="BPM" v={f.audio.bpm}/>
              <Sig l="Key" v={`${f.audio.key} ${f.audio.mode==='Major'?'maj':'min'}`}/>
              <Sig l="Energy" v={f.audio.energy.toFixed(2)}/>
              <Sig l="Valence" v={f.audio.valence.toFixed(2)}/>
              <Sig l="30d streams" v={fmtK(f.velocity.d30)}/>
              <Sig l="30d growth" v={fmtPct(f.velocity.growth30, true)} accent={f.velocity.growth30 > 0}/>
              <Sig l="TikTok" v={fmtK(f.external.tiktok)}/>
              <Sig l="Shazam" v={fmtK(f.external.shazam)}/>
            </div>
          </div>
        </div>
        <div>
          <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>RECOMMENDED ACTIONS</Mono>
          {card.sales.recs.map((r, i) => (
            <div key={i} style={{ borderLeft: '3px solid '+(r.priority==='high'?'#a32a18':r.priority==='medium'?'#d4881f':'var(--ink-3)'), padding: '10px 14px', marginBottom: 10, background:'var(--bg-2)' }}>
              <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline' }}>
                <Mono upper size={9} color="var(--ink-3)">{r.priority.toUpperCase()} · {r.kind.toUpperCase()}</Mono>
                <Mono size={11} color="var(--ink-2)">+{fmtK(r.impact)} streams</Mono>
              </div>
              <div style={{ fontSize: 13, fontWeight: 500, marginTop: 4 }}>{r.title}</div>
              <div style={{ fontSize: 12, color: 'var(--ink-2)', marginTop: 4, lineHeight: 1.5 }}>{r.detail}</div>
            </div>
          ))}
        </div>
      </div>
    );
  }
  function Sig({ l, v, accent }) {
    return (
      <div style={{ border:'1px solid var(--rule-soft)', padding:'8px 10px' }}>
        <Mono upper size={8} color="var(--ink-3)">{l}</Mono>
        <div className="ff-mono num" style={{ fontSize: 14, marginTop: 2, color: accent ? '#0a8754' : 'var(--ink)' }}>{v}</div>
      </div>
    );
  }

  function CardSales({ card }) {
    const s = card.sales;
    return (
      <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap: 28 }}>
        <div>
          <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>BY TERRITORY · 90D PROJECTION</Mono>
          {s.territories.slice(0,8).map((t, i) => (
            <div key={t.code} style={{ display:'grid', gridTemplateColumns:'30px 1fr 90px 70px', gap: 10, alignItems:'center', padding:'7px 0', borderBottom:'1px solid var(--rule-soft)' }}>
              <Mono size={10} color="var(--ink-3)">{t.code}</Mono>
              <div style={{ fontSize: 12 }}>{t.name}</div>
              <Mono size={11} style={{ textAlign:'right' }}>{fmtK(t.projected)}</Mono>
              <Mono size={11} color={t.deltaPct > 0 ? '#0a8754' : '#a32a18'} style={{ textAlign:'right' }}>{fmtPct(t.deltaPct, true)}</Mono>
            </div>
          ))}
        </div>
        <div>
          <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>BY DSP · 90D PROJECTION</Mono>
          {s.dsps.map((d, i) => (
            <div key={d.name} style={{ display:'grid', gridTemplateColumns:'1fr 90px 70px', gap: 10, alignItems:'center', padding:'7px 0', borderBottom:'1px solid var(--rule-soft)' }}>
              <div style={{ fontSize: 12 }}>{d.name}</div>
              <Mono size={11} style={{ textAlign:'right' }}>{fmtK(d.projected)}</Mono>
              <Mono size={11} color={d.deltaPct > 0 ? '#0a8754' : '#a32a18'} style={{ textAlign:'right' }}>{fmtPct(d.deltaPct, true)}</Mono>
            </div>
          ))}
        </div>
      </div>
    );
  }

  function CardPlaylist({ card }) {
    const r = card.playlists.ranked;
    return (
      <div>
        <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>EDITORIAL PLAYLIST LIKELIHOOD</Mono>
        {r.map((p, i) => (
          <div key={i} style={{ display:'grid', gridTemplateColumns:'90px 1.4fr 100px 80px 90px', gap: 12, alignItems:'center', padding:'10px 0', borderBottom:'1px solid var(--rule-soft)' }}>
            <Mono upper size={9} color="var(--ink-3)">{p.dsp}</Mono>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{p.name}</div>
            <div style={{ height: 6, background:'var(--bg-2)', position:'relative' }}>
              <div style={{ position:'absolute', left:0, top:0, height:'100%', width: (p.likelihood*100)+'%', background: p.likelihood>0.55?'#0a8754':p.likelihood>0.32?'#d4881f':'var(--ink-3)' }}/>
            </div>
            <Mono size={11} style={{ textAlign:'right' }}>{Math.round(p.likelihood*100)}%</Mono>
            <Mono upper size={9} color={p.likelihood>0.55?'#0a8754':'var(--ink-3)'} style={{ textAlign:'right' }}>{p.verdict.toUpperCase()}</Mono>
          </div>
        ))}
      </div>
    );
  }

  function CardSync({ card }) {
    const r = card.sync.ranked;
    return (
      <div>
        <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>SYNC PLACEMENT FIT</Mono>
        {r.map((a, i) => (
          <div key={i} style={{ padding:'12px 14px', border:'1px solid var(--rule-soft)', marginBottom: 8, background: a.viable ? 'var(--paper)' : 'var(--bg-2)' }}>
            <div style={{ display:'grid', gridTemplateColumns:'1fr auto auto', gap: 12, alignItems:'center' }}>
              <div>
                <Mono upper size={10} style={{ color: a.viable?'var(--ink)':'var(--ink-3)' }}>{a.tag}</Mono>
                <div style={{ fontSize: 11, color:'var(--ink-3)', marginTop: 4 }}>Brand fit: {a.brands.slice(0,3).join(' · ')}</div>
              </div>
              <Mono size={11} color="var(--ink-2)">{fmtUsd(a.feeRange[0])}–{fmtUsd(a.feeRange[1])}</Mono>
              <Mono size={11} style={{ minWidth: 50, textAlign:'right' }}>{Math.round(a.fit*100)}%</Mono>
            </div>
          </div>
        ))}
      </div>
    );
  }

  function CardComps({ card }) {
    return (
      <div>
        <Mono upper size={9} color="var(--ink-3)" style={{ display:'block', marginBottom: 10 }}>NEAREST-NEIGHBOR COMPS · BY AUDIO FEATURES</Mono>
        {card.comps.map((c, i) => (
          <div key={i} style={{ display:'grid', gridTemplateColumns:'30px 1fr 80px 80px 80px', gap: 12, alignItems:'center', padding:'10px 0', borderBottom:'1px solid var(--rule-soft)' }}>
            <Mono size={10} color="var(--ink-3)">#{i+1}</Mono>
            <div style={{ fontSize: 13 }}>{c.rec.title || c.rec.name || c.rec.id}</div>
            <Mono size={11} color="var(--ink-3)">sim {(c.sim*100).toFixed(0)}%</Mono>
            <Mono size={11}>success {c.success}</Mono>
            <Mono size={11} color="var(--ink-3)">{fmtK(c.feat.velocity.d30)} 30d</Mono>
          </div>
        ))}
      </div>
    );
  }

  // ─── MAIN PREDICTIONS SCREEN
  function ScreenPredictions({ go, payload, embed }) {
    const [tab, setTab] = _S(payload?.tab || 'success');
    const [active, setActive] = _S(null);
    const allRecs = (window.RECORDINGS || []).slice(0, 240);
    const TABS = [
      { k:'success',  l:'Song Success' },
      { k:'sales',    l:'Sales Optimization' },
      { k:'playlist', l:'Playlist Placement' },
      { k:'mining',   l:'Catalog Mining' },
      { k:'sync',     l:'Sync Placement' },
      { k:'timing',   l:'Release Timing' },
    ];

    return (
      <div>
        {!embed && (
          <PageHeader
            eyebrow={['ML', 'PREDICTIONS', 'ALGORITHMS']}
            title="predictions"
            highlight="predictions"
            sub="Five model surfaces driving sales optimization, playlist placement, and song success forecasting. Real linear math where tractable; ensemble scoring for hit prediction. All runs deterministic, scoped to your catalog."
          />
        )}
        <div style={{ borderBottom: '1px solid var(--rule)', display: 'flex', gap: 0, marginTop: embed ? 8 : 0 }}>
          {TABS.map(t => (
            <button key={t.k} onClick={() => setTab(t.k)} style={{
              padding: '14px 22px', background: 'transparent', border: 0,
              borderBottom: '2px solid ' + (tab === t.k ? 'var(--ink)' : 'transparent'),
              cursor: 'pointer', color: tab === t.k ? 'var(--ink)' : 'var(--ink-3)',
              fontSize: 13, fontWeight: tab === t.k ? 600 : 400
            }}>{t.l}</button>
          ))}
        </div>
        <div style={{ paddingTop: 24 }}>
          {tab==='success'  && <TabSuccess  allRecs={allRecs} onPick={(r)=>setActive(r)} go={go}/>}
          {tab==='sales'    && <TabSales    allRecs={allRecs} onPick={(r)=>setActive(r)}/>}
          {tab==='playlist' && <TabPlaylist allRecs={allRecs} onPick={(r)=>setActive(r)}/>}
          {tab==='mining'   && <TabMining   allRecs={allRecs} onPick={(r)=>setActive(r)} go={go}/>}
          {tab==='sync'     && <TabSync     allRecs={allRecs} onPick={(r)=>setActive(r)}/>}
          {tab==='timing'   && window.PredictTimingTab && <window.PredictTimingTab allRecs={allRecs} onPick={(r)=>setActive(r)}/>}
        </div>
        {active && (
          <div style={{
            position:'fixed', inset: 0, background:'rgba(0,0,0,0.4)', zIndex: 200,
            display:'flex', justifyContent:'flex-end',
          }} onClick={(e)=>{ if (e.target === e.currentTarget) setActive(null); }}>
            <div style={{ width: 920, maxWidth:'95vw', height:'100vh', overflowY:'auto', background:'var(--paper)', padding:'28px 32px' }}>
              <PredictScorecard rec={active} onClose={()=>setActive(null)}/>
            </div>
          </div>
        )}
      </div>
    );
  }

  // ─── Tab: SUCCESS — ranked list of all recordings by predicted score
  function TabSuccess({ allRecs, onPick }) {
    const ranked = _M(() => allRecs.map(r => {
      const f = E.getFeatures(r);
      const s = E.songSuccess(f);
      return { rec: r, feat: f, success: s };
    }).sort((a,b)=>b.success.score - a.success.score), [allRecs.length]);
    return (
      <div>
        <Mono upper size={10} color="var(--ink-3)" style={{ display:'block', marginBottom: 14 }}>TOP 50 BY HIT POTENTIAL · ENSEMBLE SCORE</Mono>
        <div style={{ display:'grid', gridTemplateColumns:'40px 1fr 60px 90px 90px 80px', gap: 14, padding:'8px 0', borderBottom:'1px solid var(--rule)' }}>
          <Mono upper size={9} color="var(--ink-3)">RANK</Mono>
          <Mono upper size={9} color="var(--ink-3)">TITLE</Mono>
          <Mono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>SCORE</Mono>
          <Mono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>30D</Mono>
          <Mono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>30D Δ</Mono>
          <Mono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>BUCKET</Mono>
        </div>
        {ranked.slice(0, 50).map((row, i) => (
          <div key={row.rec.id || i} onClick={()=>onPick(row.rec)} style={{ display:'grid', gridTemplateColumns:'40px 1fr 60px 90px 90px 80px', gap: 14, alignItems:'center', padding:'10px 0', borderBottom:'1px solid var(--rule-soft)', cursor:'pointer' }}>
            <Mono size={11} color="var(--ink-3)">{i+1}</Mono>
            <div style={{ fontSize: 13 }}>{row.rec.title || row.rec.name || row.rec.id}</div>
            <Mono size={12} style={{ textAlign:'right', fontWeight:500, color: row.success.score>60?'#0a8754':'var(--ink)' }}>{row.success.score}</Mono>
            <Mono size={11} color="var(--ink-2)" style={{ textAlign:'right' }}>{fmtK(row.feat.velocity.d30)}</Mono>
            <Mono size={11} style={{ textAlign:'right', color: row.feat.velocity.growth30>0?'#0a8754':'#a32a18' }}>{fmtPct(row.feat.velocity.growth30,true)}</Mono>
            <Mono upper size={9} color="var(--ink-3)" style={{ textAlign:'right' }}>{row.success.bucket.toUpperCase()}</Mono>
          </div>
        ))}
      </div>
    );
  }

  // ─── Tab: SALES — pick a track, see territory/DSP optimization
  function TabSales({ allRecs, onPick }) {
    const top = _M(() => allRecs.slice(0, 24).map(r => {
      const f = E.getFeatures(r);
      const s = E.salesProjection(f);
      return { rec: r, feat: f, sales: s };
    }).sort((a,b)=>b.sales.delta-a.sales.delta), [allRecs.length]);
    return (
      <div>
        <Mono upper size={10} color="var(--ink-3)" style={{ display:'block', marginBottom: 14 }}>TOP TRACKS BY 90D PROJECTED LIFT</Mono>
        {top.map((row, i) => (
          <div key={row.rec.id || i} onClick={()=>onPick(row.rec)} style={{ display:'grid', gridTemplateColumns:'1fr 100px 100px 80px 1.2fr', gap: 14, alignItems:'center', padding:'12px 0', borderBottom:'1px solid var(--rule-soft)', cursor:'pointer' }}>
            <div style={{ fontSize: 13 }}>{row.rec.title || row.rec.name || row.rec.id}</div>
            <Mono size={11} color="var(--ink-3)" style={{ textAlign:'right' }}>{fmtK(row.sales.currentTotal)} now</Mono>
            <Mono size={12} style={{ textAlign:'right' }}>{fmtK(row.sales.projected)}</Mono>
            <Mono size={11} style={{ textAlign:'right', color: row.sales.deltaPct>0?'#0a8754':'#a32a18' }}>{fmtPct(row.sales.deltaPct, true)}</Mono>
            <div style={{ fontSize: 11, color:'var(--ink-2)' }}>{row.sales.recs[0]?.title || '—'}</div>
          </div>
        ))}
      </div>
    );
  }

  // ─── Tab: PLAYLIST — by playlist, show top candidate tracks
  function TabPlaylist({ allRecs, onPick }) {
    const [pl, setPl] = _S(E.PLAYLISTS[0].name);
    const playlist = E.PLAYLISTS.find(p => p.name === pl);
    const candidates = _M(() => allRecs.map(r => {
      const f = E.getFeatures(r);
      const m = E.playlistMatch(f, playlist);
      return { rec: r, feat: f, match: m, lik: Math.max(0.02, Math.min(0.92, m * 0.78 + (f.catalog.writerScore - 0.4) * 0.18)) };
    }).sort((a,b)=>b.lik-a.lik).slice(0,30), [pl, allRecs.length]);
    return (
      <div>
        <div style={{ display:'flex', flexWrap:'wrap', gap: 6, marginBottom: 18 }}>
          {E.PLAYLISTS.map(p => (
            <button key={p.name} onClick={()=>setPl(p.name)} className="ff-mono upper" style={{
              fontSize: 10, letterSpacing:'.08em', padding:'6px 10px',
              background: pl===p.name?'var(--ink)':'transparent',
              color: pl===p.name?'var(--bg)':'var(--ink-2)',
              border: '1px solid '+(pl===p.name?'var(--ink)':'var(--rule)'),
              cursor:'pointer',
            }}>{p.dsp.split(' ')[0]} · {p.name}</button>
          ))}
        </div>
        <Mono upper size={10} color="var(--ink-3)" style={{ display:'block', marginBottom: 12 }}>
          TOP 30 CANDIDATES FOR {playlist.name.toUpperCase()} ({fmtK(playlist.followers)} FOLLOWERS)
        </Mono>
        {candidates.map((c, i) => (
          <div key={c.rec.id || i} onClick={()=>onPick(c.rec)} style={{ display:'grid', gridTemplateColumns:'40px 1fr 100px 90px 80px', gap: 14, alignItems:'center', padding:'9px 0', borderBottom:'1px solid var(--rule-soft)', cursor:'pointer' }}>
            <Mono size={11} color="var(--ink-3)">{i+1}</Mono>
            <div style={{ fontSize: 13 }}>{c.rec.title || c.rec.name || c.rec.id}</div>
            <div style={{ height: 6, background:'var(--bg-2)', position:'relative' }}>
              <div style={{ position:'absolute', left:0, top:0, height:'100%', width: (c.lik*100)+'%', background: c.lik>0.55?'#0a8754':c.lik>0.32?'#d4881f':'var(--ink-3)' }}/>
            </div>
            <Mono size={11} style={{ textAlign:'right' }}>{Math.round(c.lik*100)}% lik</Mono>
            <Mono upper size={9} color={c.lik>0.55?'#0a8754':'var(--ink-3)'} style={{ textAlign:'right' }}>{c.lik>0.55?'STRONG':c.lik>0.32?'PLAUSIBLE':'LONG-SHOT'}</Mono>
          </div>
        ))}
      </div>
    );
  }

  // ─── Tab: MINING — top upside catalog
  function TabMining({ allRecs, onPick }) {
    const ranked = _M(() => E.catalogMining(allRecs, { limit: 50 }), [allRecs.length]);
    return (
      <div>
        <Mono upper size={10} color="var(--ink-3)" style={{ display:'block', marginBottom: 14 }}>
          TOP 50 UNDERPERFORMING WITH UPSIDE · HIGH SCORE × LOW RECENT VELOCITY
        </Mono>
        <div style={{ display:'grid', gridTemplateColumns:'40px 1fr 80px 90px 90px 1.2fr', gap: 14, padding:'8px 0', borderBottom:'1px solid var(--rule)' }}>
          <Mono upper size={9} color="var(--ink-3)">RANK</Mono>
          <Mono upper size={9} color="var(--ink-3)">TITLE</Mono>
          <Mono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>UPSIDE</Mono>
          <Mono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>SCORE</Mono>
          <Mono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>30D</Mono>
          <Mono upper size={9} color="var(--ink-3)">SUGGESTED ACTION</Mono>
        </div>
        {ranked.map((row, i) => {
          const action = row.feat.audio.bpm < 100 ? 'Lo-fi/study playlist push' :
                         row.feat.external.tiktok > 100_000 ? 'TikTok creator pack' :
                         row.feat.catalog.age >= 3 ? 'Anniversary repush' : 'Sync library submit';
          return (
            <div key={row.rec.id || i} onClick={()=>onPick(row.rec)} style={{ display:'grid', gridTemplateColumns:'40px 1fr 80px 90px 90px 1.2fr', gap: 14, alignItems:'center', padding:'10px 0', borderBottom:'1px solid var(--rule-soft)', cursor:'pointer' }}>
              <Mono size={11} color="var(--ink-3)">{i+1}</Mono>
              <div style={{ fontSize: 13 }}>{row.rec.title || row.rec.name || row.rec.id}</div>
              <Mono size={12} style={{ textAlign:'right', fontWeight:500, color: row.upside>60?'#0a8754':'var(--ink)' }}>{row.upside}</Mono>
              <Mono size={11} color="var(--ink-2)" style={{ textAlign:'right' }}>{row.success.score}</Mono>
              <Mono size={11} color="var(--ink-3)" style={{ textAlign:'right' }}>{fmtK(row.feat.velocity.d30)}</Mono>
              <div style={{ fontSize: 12, color: 'var(--ink-2)' }}>{action}</div>
            </div>
          );
        })}
      </div>
    );
  }

  // ─── Tab: SYNC — by archetype, show top fits
  function TabSync({ allRecs, onPick }) {
    const [tag, setTag] = _S(E.SYNC_ARCHETYPES[0].tag);
    const arch = E.SYNC_ARCHETYPES.find(a => a.tag === tag);
    const candidates = _M(() => allRecs.map(r => {
      const f = E.getFeatures(r);
      const fit = E.syncFit(f).ranked.find(a => a.tag === tag);
      return { rec: r, feat: f, fit: fit?.fit || 0, fee: fit?.feeRange };
    }).sort((a,b)=>b.fit-a.fit).slice(0,24), [tag, allRecs.length]);
    return (
      <div>
        <div style={{ display:'flex', flexWrap:'wrap', gap: 6, marginBottom: 18 }}>
          {E.SYNC_ARCHETYPES.map(a => (
            <button key={a.tag} onClick={()=>setTag(a.tag)} className="ff-mono upper" style={{
              fontSize: 10, letterSpacing:'.08em', padding:'6px 10px',
              background: tag===a.tag?'var(--ink)':'transparent',
              color: tag===a.tag?'var(--bg)':'var(--ink-2)',
              border: '1px solid '+(tag===a.tag?'var(--ink)':'var(--rule)'),
              cursor:'pointer',
            }}>{a.tag}</button>
          ))}
        </div>
        <Mono upper size={10} color="var(--ink-3)" style={{ display:'block', marginBottom: 8 }}>
          TOP FITS · {tag.toUpperCase()} · TARGET BRANDS: {arch.brands.slice(0,3).join(' · ')}
        </Mono>
        {candidates.map((c, i) => (
          <div key={c.rec.id || i} onClick={()=>onPick(c.rec)} style={{ display:'grid', gridTemplateColumns:'40px 1fr 90px 130px 60px', gap: 14, alignItems:'center', padding:'9px 0', borderBottom:'1px solid var(--rule-soft)', cursor:'pointer' }}>
            <Mono size={11} color="var(--ink-3)">{i+1}</Mono>
            <div style={{ fontSize: 13 }}>{c.rec.title || c.rec.name || c.rec.id}</div>
            <Mono size={11} style={{ textAlign:'right' }}>{Math.round(c.fit*100)}% fit</Mono>
            <Mono size={11} color="var(--ink-2)" style={{ textAlign:'right' }}>{c.fee?fmtUsd(c.fee[0])+'–'+fmtUsd(c.fee[1]):'—'}</Mono>
            <Mono upper size={9} color={c.fit>0.7?'#0a8754':c.fit>0.55?'#d4881f':'var(--ink-3)'} style={{ textAlign:'right' }}>{c.fit>0.7?'STRONG':c.fit>0.55?'VIABLE':'WEAK'}</Mono>
          </div>
        ))}
      </div>
    );
  }

  window.PredictScorecard = PredictScorecard;
  window.ScreenPredictions = ScreenPredictions;
})();
