// insights.jsx — ML / valuation / NLP / anomaly surfaces for ASTRO
// ─────────────────────────────────────────────────────────────────────
// Why this exists:
//
// ASTRO already has rich raw data — works, recordings, statements,
// audiences, agreements. What it doesn't have today is a PREDICTIVE
// LAYER on top of that data: catalog valuation for M&A, trend forecasting
// for A&R, semantic search for everything-else, anomaly detection for
// finance. This file is that layer.
//
// We split it into four tabs that all draw from the same datasets but
// answer four different questions:
//
//   01 VALUATION   — what is this catalog worth, today and projected?
//   02 TRENDS      — what's rising / falling / breaking out?
//   03 ANOMALIES   — what's suspicious in the revenue + stream feed?
//   04 SEMANTIC    — search across the catalog + contracts in plain English
//
// Determinism: all numbers seed off catalog ids so the demo is stable.
const { useMemo: _IN_useM, useState: _IN_useS, useEffect: _IN_useE } = React;

// ─────────── seed helper
function inSeed(s) {
  s = String(s || 'x'); let h = 0;
  for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0;
  return () => { h = (h * 1664525 + 1013904223) >>> 0; return h / 0xffffffff; };
}

const fmtUsd = (n) => {
  if (n == null) return '—';
  const a = Math.abs(n);
  if (a >= 1e9) return '$' + (n/1e9).toFixed(2) + 'B';
  if (a >= 1e6) return '$' + (n/1e6).toFixed(2) + 'M';
  if (a >= 1e3) return '$' + (n/1e3).toFixed(1) + 'k';
  return '$' + Math.round(n).toLocaleString();
};
const fmtNum = (n) => {
  if (n == null) return '—';
  if (Math.abs(n) >= 1e9) return (n/1e9).toFixed(1) + 'B';
  if (Math.abs(n) >= 1e6) return (n/1e6).toFixed(1) + 'M';
  if (Math.abs(n) >= 1e3) return (n/1e3).toFixed(1) + 'k';
  return Math.round(n).toLocaleString();
};
const fmtPct = (n, withSign) => (withSign && n > 0 ? '+' : '') + (n*100).toFixed(1) + '%';

// ─────────── valuation engine
// Method: trailing 12-month earnings × multiple, where multiple is
// driven by catalog age (older=stable=higher mult), genre stability,
// concentration risk, and rights coverage.
function computeValuation(rng) {
  const ttmEarnings = 4_120_000 + rng() * 1_840_000;
  const baselineMultiple = 11.4;
  const ageBonus  = 1.18;   // +18% for >5yr stable catalog
  const genreAdj  = 0.96;   // -4% (some pop, faster decay)
  const concentRisk = 0.94; // -6% (top 5 works = 38% of revenue)
  const rightsCov = 1.05;   // +5% (clean splits, no disputed claims)
  const multiple = baselineMultiple * ageBonus * genreAdj * concentRisk * rightsCov;
  const value = ttmEarnings * multiple;
  return { ttmEarnings, multiple, value, factors: [
    { label: 'Baseline industry multiple',  v: 'x ' + baselineMultiple.toFixed(2),  delta: null },
    { label: 'Catalog age premium',         v: 'x ' + ageBonus.toFixed(2),  delta: 0.18,  hint: '> 5 years, stable revenue base' },
    { label: 'Genre decay adjustment',      v: 'x ' + genreAdj.toFixed(2),  delta: -0.04, hint: 'Pop-leaning catalog · faster decay' },
    { label: 'Concentration risk',          v: 'x ' + concentRisk.toFixed(2), delta: -0.06, hint: 'Top 5 works = 38% of TTM' },
    { label: 'Rights & splits coverage',    v: 'x ' + rightsCov.toFixed(2), delta: 0.05,  hint: 'No disputed splits, all CWRs ack\u2019d' },
  ]};
}

// ─────────── 10-year revenue forecast
function buildForecast(ttm, rng) {
  // Decay: ~85% of prior year for first 3 years, then 92%, plus seasonal noise
  const out = [];
  let v = ttm;
  for (let y = 0; y < 10; y++) {
    const decay = y < 3 ? 0.86 : y < 6 ? 0.92 : 0.95;
    v = v * decay * (0.95 + rng() * 0.10);
    out.push(v);
  }
  return out;
}

// ─────────── Comparables
const COMPARABLES = [
  { name: 'Hipgnosis · Bob Dylan recordings', year: 2020, value: 200_000_000, mult: 19.2, note: 'Reference back-catalog deal' },
  { name: 'KKR / BMG · Bob Dylan publishing', year: 2020, value: 300_000_000, mult: 22.0, note: 'Songwriter publishing comp' },
  { name: 'Universal · Sting catalog',         year: 2022, value: 300_000_000, mult: 18.5, note: 'Publishing + recordings' },
  { name: 'Hipgnosis · Justin Bieber',         year: 2023, value: 200_000_000, mult: 20.4, note: 'Modern pop benchmark' },
  { name: 'Concord · Genesis catalog',         year: 2022, value: 300_000_000, mult: 17.1, note: 'Classic rock comp' },
  { name: 'Influence Media · Future',          year: 2023, value:  75_000_000, mult: 16.8, note: 'Rap publishing comp' },
];

// ─────────── concentration / breakdown of revenue
function buildBreakdown(rng) {
  const ROWS = [
    { l: 'Streaming (DSP)', share: 0.62, ttm: 0, growth: 0.08 },
    { l: 'Publishing (mech + perf)', share: 0.18, ttm: 0, growth: 0.04 },
    { l: 'Sync placements', share: 0.09, ttm: 0, growth: 0.22 },
    { l: 'YouTube CID + UGC', share: 0.06, ttm: 0, growth: 0.17 },
    { l: 'Physical + downloads', share: 0.03, ttm: 0, growth: -0.18 },
    { l: 'Neighboring rights', share: 0.02, ttm: 0, growth: 0.06 },
  ];
  return ROWS;
}

// ─────────── trending tracks
function buildTrending(rng, recordings) {
  const pool = (recordings || []).slice(0, 60);
  const out = [];
  for (let i = 0; i < pool.length; i++) {
    const r = pool[i];
    const baseline = (r.plays || 1_000_000) / 30; // daily-ish
    const wow = (rng() - 0.4) * 1.6; // -64..+96%
    const mom = (rng() - 0.4) * 2.5;
    const sparkBase = baseline;
    const spark = [];
    for (let s = 0; s < 14; s++) {
      const v = sparkBase * (1 + (rng() - 0.5) * 0.3) * (1 + (s/14) * (wow * 0.6));
      spark.push(Math.max(0, v));
    }
    const sources = ['TikTok viral','Spotify Editorial add','Reddit thread','sync (TV ad)','radio rotation','playlist add (Apple)','BBC Radio 1 spin','Twitch / streamer'];
    out.push({
      r,
      wow, mom,
      direction: wow > 0.15 ? 'rising' : wow < -0.15 ? 'falling' : 'flat',
      breakout: wow > 0.5 || (wow > 0.3 && mom > 0.4),
      driver: sources[Math.floor(rng() * sources.length)],
      spark,
      forecast30d: Math.round(baseline * 30 * (1 + wow)),
    });
  }
  out.sort((a, b) => Math.abs(b.wow) - Math.abs(a.wow));
  return out;
}

// ─────────── anomalies
function buildAnomalies(rng, recordings) {
  const pool = (recordings || []).slice(0, 40);
  const TYPES = [
    { kind: 'revenue-drop',     l: 'Revenue dropped > 30% MoM',        sev: 'high' },
    { kind: 'streaming-fraud',  l: 'Suspicious play velocity spike',   sev: 'critical' },
    { kind: 'territory-shift',  l: 'Streams shifted territory abruptly', sev: 'medium' },
    { kind: 'metadata-drift',   l: 'DSP metadata diverged from source', sev: 'low' },
    { kind: 'split-mismatch',   l: 'Statement split ≠ registered split', sev: 'high' },
    { kind: 'unknown-pool',     l: 'Black-box pool received \u2014 unmatched', sev: 'medium' },
    { kind: 'duplicate-isrc',   l: 'Duplicate ISRC detected on ingest',sev: 'high' },
    { kind: 'royalty-shortfall',l: 'Statement under-payment vs. forecast', sev: 'medium' },
  ];
  const out = [];
  for (let i = 0; i < 14; i++) {
    const r = pool[i % Math.max(pool.length, 1)] || { title:'(unknown)', isrc:'—', id:'?' };
    const t = TYPES[i % TYPES.length];
    out.push({
      id: 'anom-' + i,
      kind: t.kind, l: t.l, sev: t.sev,
      r,
      detected: ['2h','5h','11h','18h','1d','1d','2d','2d','3d','3d','4d','6d','1w','1w'][i],
      magnitude: t.kind === 'revenue-drop' ? `${-Math.round(20 + rng()*40)}%`
              : t.kind === 'streaming-fraud' ? `${Math.round(800 + rng()*4000)}% spike`
              : t.kind === 'royalty-shortfall' ? `-${fmtUsd(2000 + rng()*18000)}`
              : t.kind === 'territory-shift' ? 'BR ↑ · US ↓'
              : t.kind === 'split-mismatch' ? `Δ ${(rng()*8).toFixed(1)}%`
              : '—',
      confidence: 0.74 + rng() * 0.24,
      recommended: ({
        'revenue-drop':     'Open recording → check DSP feed health',
        'streaming-fraud':  'Flag ISRC for fraud review · contact DSPs',
        'territory-shift':  'Review for marketing campaign or sync',
        'metadata-drift':   'Push canonical metadata to DSPs',
        'split-mismatch':   'Open splits → recompute',
        'unknown-pool':     'Match work in MLC sync',
        'duplicate-isrc':   'Resolve in Issues queue',
        'royalty-shortfall':'File reconciliation request',
      })[t.kind],
    });
  }
  out.sort((a, b) => ['critical','high','medium','low'].indexOf(a.sev) - ['critical','high','medium','low'].indexOf(b.sev));
  return out;
}

// ─────────── semantic search — pre-baked answers
const SEMANTIC_EXAMPLES = [
  'songs that feel like Bon Iver but with a hip-hop drum kit',
  'works where my reversion clause kicks in next year',
  'recordings with unmatched MLC pools larger than $10k',
  'agreements where we owe a recoupment payment this quarter',
  'tracks rising fastest on TikTok this week',
  'songs that have never been registered with a PRO',
  'recordings with conflicting splits between writers',
  'works ASTRO has not yet generated a CWR for',
];

// ─────────────────────────────────────── ATOMS
function INMono({ children, color = 'var(--ink-2)', size = 11, upper, style }) {
  return <span className={'ff-mono ' + (upper ? 'upper' : '')}
    style={{ fontSize: size, color, letterSpacing: upper ? '.12em' : '.04em', ...style }}>{children}</span>;
}
function INPill({ children, fg = 'var(--ink-2)', dot, bg }) {
  return <span className="ff-mono upper" style={{
    fontSize: 9, letterSpacing: '.12em', padding: '3px 8px',
    color: fg, border: '1px solid ' + fg, background: bg || 'transparent',
    display: 'inline-flex', alignItems: 'center', gap: 6, whiteSpace: 'nowrap'
  }}>
    {dot && <span style={{ display:'inline-block', width: 5, height: 5, borderRadius: 3, background: fg }}/>}
    {children}
  </span>;
}

function INKpi({ l, v, sub, accent, danger, ok }) {
  return (
    <div style={{ padding: '20px 22px', minHeight: 110, display:'flex', flexDirection:'column', gap: 6 }}>
      <INMono upper size={9} color="var(--ink-3)">{l}</INMono>
      <div className="ff-mono num" style={{
        fontSize: 30, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1,
        color: danger ? 'var(--danger)' : ok ? 'var(--ok)' : accent ? 'var(--accent-ink)' : 'var(--ink)',
        background: accent ? 'var(--accent)' : 'transparent',
        padding: accent ? '2px 6px' : 0,
        alignSelf: 'flex-start',
        marginTop: 4,
      }}>{v}</div>
      {sub && <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>{sub}</div>}
    </div>
  );
}

// ─────────── Sparkline
function INSpark({ data, color = 'var(--ink)', w = 80, h = 24, fill }) {
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => `${(i/(data.length-1))*w},${h - ((v-min)/range)*h}`).join(' ');
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`}>
      {fill && <polygon points={`0,${h} ${pts} ${w},${h}`} fill={color} opacity="0.12"/>}
      <polyline points={pts} fill="none" stroke={color} strokeWidth="1.5"/>
    </svg>
  );
}

// ─────────── Forecast chart (10-year stacked area-ish)
function INForecastChart({ ttm, forecast }) {
  const all = [ttm, ...forecast];
  const W = 760, H = 180, padL = 50, padR = 18, padT = 18, padB = 28;
  const cw = W - padL - padR, ch = H - padT - padB;
  const max = Math.max(...all);
  const bw = cw / all.length;
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ display: 'block' }}>
      {/* y grid */}
      {[0, 0.25, 0.5, 0.75, 1].map(t => {
        const y = padT + ch - t * ch;
        return <g key={t}>
          <line x1={padL} y1={y} x2={W-padR} y2={y} stroke="var(--rule-soft, var(--bg-2))" strokeWidth="1"/>
          <text x={padL - 6} y={y+3} textAnchor="end" fontSize="9" fill="var(--ink-3)" fontFamily="var(--ff-mono)">
            {fmtUsd(max * t).replace('$','$')}
          </text>
        </g>;
      })}
      {/* bars */}
      {all.map((v, i) => {
        const h = (v / max) * ch;
        const x = padL + i * bw + 4;
        const y = padT + ch - h;
        const isTtm = i === 0;
        return (
          <g key={i}>
            <rect x={x} y={y} width={bw - 8} height={h}
              fill={isTtm ? 'var(--ink)' : 'var(--accent, #c0392b)'}
              opacity={isTtm ? 1 : 0.7 - (i * 0.04)}/>
            <text x={x + (bw-8)/2} y={padT + ch + 14} textAnchor="middle" fontSize="9" fill="var(--ink-3)" fontFamily="var(--ff-mono)">
              {isTtm ? 'TTM' : `Y+${i}`}
            </text>
          </g>
        );
      })}
      {/* trend line */}
      <polyline points={all.map((v, i) => {
        const h = (v / max) * ch;
        const x = padL + i * bw + bw/2;
        const y = padT + ch - h;
        return `${x},${y}`;
      }).join(' ')} fill="none" stroke="var(--ink)" strokeWidth="1.5" strokeDasharray="3 3" opacity="0.5"/>
    </svg>
  );
}

// ─────────── Multiplier waterfall for valuation
function INMultiplierWaterfall({ factors }) {
  return (
    <div style={{ border: '1px solid var(--rule)' }}>
      {factors.map((f, i) => (
        <div key={i} style={{
          display: 'grid', gridTemplateColumns: '1fr 70px 90px',
          gap: 14, padding: '12px 16px', alignItems: 'center',
          borderBottom: i < factors.length - 1 ? '1px solid var(--rule-soft, var(--bg-2))' : 'none'
        }}>
          <div>
            <div style={{ fontSize: 13, fontWeight: 500 }}>{f.label}</div>
            {f.hint && <INMono size={10} color="var(--ink-3)" style={{ marginTop: 2 }}>{f.hint}</INMono>}
          </div>
          <INMono size={11} color="var(--ink)" style={{ textAlign: 'right' }}>{f.v}</INMono>
          <div style={{ textAlign: 'right' }}>
            {f.delta != null && (
              <INMono size={11} color={f.delta > 0 ? 'var(--ok)' : 'var(--danger)'}>
                {fmtPct(f.delta, true)}
              </INMono>
            )}
          </div>
        </div>
      ))}
    </div>
  );
}

// ─────────────────────────────────────── 01 VALUATION TAB
// Delegates to window.ValuationScreen if the rich engine has loaded;
// falls back to the legacy inline view otherwise.
function INValuationTab({ go }) {
  if (window.ValuationScreen && window.ValuationEngine) {
    return React.createElement(window.ValuationScreen, { go });
  }
  return React.createElement(INValuationTabLegacy, { go });
}

function INValuationTabLegacy({ go }) {
  const rng = _IN_useM(() => inSeed('valuation-2026'), []);
  const [val] = _IN_useS(() => computeValuation(rng));
  const [forecast] = _IN_useS(() => buildForecast(val.ttmEarnings, rng));
  const [breakdown] = _IN_useS(() => buildBreakdown(rng));
  const lifetime = forecast.reduce((s, v) => s + v, val.ttmEarnings);
  const npv = (() => {
    let v = val.ttmEarnings;
    for (let i = 0; i < forecast.length; i++) v += forecast[i] / Math.pow(1.08, i+1);
    return v;
  })();

  return (
    <div>
      {/* Headline number */}
      <div style={{ border: '1px solid var(--rule)', padding: '32px 36px', marginBottom: 24, display: 'grid', gridTemplateColumns: '1fr auto', alignItems: 'center', gap: 24 }}>
        <div>
          <INMono upper size={10} color="var(--ink-3)">CATALOG VALUATION · 2026 Q1</INMono>
          <div className="ff-mono num" style={{ fontSize: 56, fontWeight: 500, letterSpacing: '-0.03em', lineHeight: 1, marginTop: 8 }}>
            {fmtUsd(val.value)}
          </div>
          <div style={{ marginTop: 8, color: 'var(--ink-2)', fontSize: 13, lineHeight: 1.5, maxWidth: 580 }}>
            Income approach · TTM earnings of {fmtUsd(val.ttmEarnings)} × {val.multiple.toFixed(2)} multiple.
            Range based on comparable deals: <INMono color="var(--ink)">{fmtUsd(val.value * 0.84)}–{fmtUsd(val.value * 1.18)}</INMono>.
          </div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 12 }}>
          <INPill fg="var(--ok)" dot>BUY-SIDE READY</INPill>
          <button onClick={() => window.dispatchEvent(new CustomEvent('astro-toast',{detail:{msg:'Valuation report queued · ready in 3 min',tone:'ok'}}))} className="ff-mono upper" style={{ fontSize: 10, letterSpacing: '.12em', padding: '8px 14px', background:'var(--ink)', color:'var(--bg)', border: 0, cursor:'pointer' }}>
            EXPORT REPORT →
          </button>
          <INMono size={10} color="var(--ink-3)">Last refreshed 14m ago</INMono>
        </div>
      </div>

      {/* KPI strip */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', border: '1px solid var(--rule)', marginBottom: 32 }}>
        <INKpi l="TTM EARNINGS"     v={fmtUsd(val.ttmEarnings)} sub="trailing 12 months · net to publisher"/>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="EFFECTIVE MULTIPLE" v={'x ' + val.multiple.toFixed(2)} sub={`baseline x ${(11.4).toFixed(2)} · adjusted ${val.multiple > 11.4 ? '↑' : '↓'}`}/>
        </div>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="LIFETIME GROSS · 10Y" v={fmtUsd(lifetime)} sub="undiscounted nominal"/>
        </div>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="NPV @ 8% DISCOUNT" v={fmtUsd(npv)} sub="risk-adjusted present value" accent/>
        </div>
      </div>

      {/* Forecast + Multiplier waterfall */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr', gap: 32, marginBottom: 32 }}>
        <div>
          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
            10-YEAR REVENUE FORECAST · WITH DECAY MODEL
          </INMono>
          <div style={{ border: '1px solid var(--rule)', padding: '14px 16px 6px' }}>
            <INForecastChart ttm={val.ttmEarnings} forecast={forecast}/>
          </div>
          <INMono size={10} color="var(--ink-3)" style={{ marginTop: 10, display: 'block', lineHeight: 1.5 }}>
            Decay model: 14% Y1–Y3 (post-release fall-off), 8% Y4–Y6 (catalog stabilization), 5% Y7–Y10 (long-tail steady-state). Assumes no new releases — base catalog only. Sync, UGC and viral re-entries are upside not modeled here.
          </INMono>
        </div>
        <div>
          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
            MULTIPLE BUILD-UP
          </INMono>
          <INMultiplierWaterfall factors={val.factors}/>
          <div style={{ marginTop: 12, padding: '12px 14px', background: 'var(--bg-2)', fontSize: 11, color: 'var(--ink-2)', lineHeight: 1.5 }}>
            Concentration risk is the biggest negative input. Diversifying revenue across the next 10 works (each &lt; 5% share) would lift the multiple ~0.6x.
          </div>
        </div>
      </div>

      {/* Revenue breakdown + comparables */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.2fr', gap: 32, marginBottom: 32 }}>
        <div>
          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
            REVENUE COMPOSITION · TTM
          </INMono>
          <div style={{ border: '1px solid var(--rule)' }}>
            {breakdown.map((row, i) => (
              <div key={i} style={{
                display: 'grid', gridTemplateColumns: '1fr 70px 80px',
                gap: 14, padding: '11px 14px', alignItems: 'center',
                borderBottom: i < breakdown.length - 1 ? '1px solid var(--rule-soft, var(--bg-2))' : 'none'
              }}>
                <div>
                  <div style={{ fontSize: 12 }}>{row.l}</div>
                  <div style={{ position: 'relative', height: 4, background: 'var(--bg-2)', marginTop: 4 }}>
                    <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: (row.share*100) + '%', background: 'var(--ink)' }}/>
                  </div>
                </div>
                <INMono size={11} color="var(--ink)" style={{ textAlign: 'right' }}>{fmtUsd(val.ttmEarnings * row.share)}</INMono>
                <INMono size={11} color={row.growth > 0 ? 'var(--ok)' : 'var(--danger)'} style={{ textAlign: 'right' }}>
                  {fmtPct(row.growth, true)}
                </INMono>
              </div>
            ))}
          </div>
        </div>
        <div>
          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
            COMPARABLE DEALS · MARKET BENCHMARK
          </INMono>
          <div style={{ border: '1px solid var(--rule)' }}>
            <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 60px 90px 70px', gap: 12, padding: '8px 14px', background: 'var(--bg-2)', borderBottom: '1px solid var(--rule)' }}>
              <INMono upper size={9} color="var(--ink-3)">DEAL</INMono>
              <INMono upper size={9} color="var(--ink-3)">YEAR</INMono>
              <INMono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>HEADLINE</INMono>
              <INMono upper size={9} color="var(--ink-3)" style={{textAlign:'right'}}>MULTIPLE</INMono>
            </div>
            {COMPARABLES.map((c, i) => (
              <div key={i} style={{
                display: 'grid', gridTemplateColumns: '1.4fr 60px 90px 70px',
                gap: 12, padding: '11px 14px', alignItems: 'center',
                borderBottom: i < COMPARABLES.length - 1 ? '1px solid var(--rule-soft, var(--bg-2))' : 'none'
              }}>
                <div>
                  <div style={{ fontSize: 12, fontWeight: 500 }}>{c.name}</div>
                  <INMono size={10} color="var(--ink-3)" style={{ marginTop: 2 }}>{c.note}</INMono>
                </div>
                <INMono size={11} color="var(--ink-2)">{c.year}</INMono>
                <INMono size={11} color="var(--ink)" style={{ textAlign: 'right' }}>{fmtUsd(c.value)}</INMono>
                <div style={{ textAlign: 'right' }}>
                  <INMono size={11} color={c.mult >= val.multiple ? 'var(--ok)' : 'var(--ink-3)'}>
                    x {c.mult.toFixed(1)}
                  </INMono>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* Sensitivity */}
      <div>
        <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
          SENSITIVITY · WHAT WOULD MOVE THE NUMBER
        </INMono>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14 }}>
          {[
            { l: '+1 work in top 5% revenue tier', d: '+8.2%', v: fmtUsd(val.value * 0.082) },
            { l: 'Resolve 14 disputed splits',     d: '+2.4%', v: fmtUsd(val.value * 0.024) },
            { l: 'Extend reversion exposure -5y',  d: '-4.1%', v: fmtUsd(-val.value * 0.041), bad: true },
            { l: 'Sync placement (top-tier ad)',   d: '+3.6%', v: fmtUsd(val.value * 0.036) },
            { l: 'Genre rotation (+R&B share)',    d: '+1.8%', v: fmtUsd(val.value * 0.018) },
            { l: 'Streaming rate cut (-5%)',       d: '-6.5%', v: fmtUsd(-val.value * 0.065), bad: true },
          ].map((s, i) => (
            <div key={i} style={{ border: '1px solid var(--rule)', padding: '14px 16px' }}>
              <INMono size={10} color="var(--ink-3)" style={{ display: 'block' }}>{s.l}</INMono>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginTop: 6 }}>
                <span className="ff-mono num" style={{ fontSize: 18, fontWeight: 500, color: s.bad ? 'var(--danger)' : 'var(--ok)' }}>{s.d}</span>
                <INMono size={11} color="var(--ink-3)">{s.v}</INMono>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────── 02 TRENDS TAB
function INTrendsTab({ go }) {
  const recordings = (window.__RECORDINGS || window.RECORDINGS || []).slice(0, 80);
  const rng = _IN_useM(() => inSeed('trends-2026-q1'), []);
  const trends = _IN_useM(() => buildTrending(rng, recordings), []);
  const [filter, setFilter] = _IN_useS('all');

  const filtered = trends.filter(t => filter === 'all'
    ? true
    : filter === 'rising' ? t.direction === 'rising'
    : filter === 'falling' ? t.direction === 'falling'
    : filter === 'breakout' ? t.breakout
    : true).slice(0, 24);

  const breakouts = trends.filter(t => t.breakout);
  const rising = trends.filter(t => t.direction === 'rising').length;
  const falling = trends.filter(t => t.direction === 'falling').length;

  return (
    <div>
      {/* KPI strip */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', border: '1px solid var(--rule)', marginBottom: 28 }}>
        <INKpi l="BREAKOUTS · 7D"  v={breakouts.length} sub="W/W +50% with momentum" accent/>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="RISING"         v={rising} ok sub="trending up week-over-week"/>
        </div>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="FALLING"        v={falling} sub="declining week-over-week"/>
        </div>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="MODEL CONFIDENCE" v="86%" sub="against 30d backtest"/>
        </div>
      </div>

      {/* Breakout cards */}
      {breakouts.length > 0 && (
        <div style={{ marginBottom: 32 }}>
          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
            BREAKOUT WATCHLIST · {breakouts.length} TRACKS · MODEL FLAGGED
          </INMono>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))', gap: 14 }}>
            {breakouts.slice(0, 4).map((t, i) => (
              <button key={i}
                onClick={() => go && go('recording', { id: t.r.id })}
                style={{
                  textAlign: 'left', padding: 16, border: '1px solid var(--rule)',
                  background: 'var(--paper)', cursor: 'pointer', position: 'relative'
                }}>
                <div style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 2, background: 'var(--accent, #c0392b)' }}/>
                <INPill fg="var(--accent, #c0392b)" dot>BREAKOUT</INPill>
                <div style={{ fontSize: 14, fontWeight: 600, marginTop: 10, lineHeight: 1.3 }}>{t.r.title}</div>
                <INMono size={10} color="var(--ink-3)" style={{ marginTop: 2, display: 'block' }}>{t.r.artist}</INMono>
                <div style={{ marginTop: 14, display: 'flex', alignItems: 'baseline', gap: 14 }}>
                  <div>
                    <span className="ff-mono num" style={{ fontSize: 22, fontWeight: 500, color: 'var(--ok)' }}>+{Math.round(t.wow*100)}%</span>
                    <INMono size={9} color="var(--ink-3)" style={{ display: 'block' }}>WoW</INMono>
                  </div>
                  <INSpark data={t.spark} color="var(--accent, #c0392b)" w={96} h={36} fill/>
                </div>
                <INMono size={10} color="var(--ink-2)" style={{ marginTop: 10, display: 'block' }}>
                  Driver: <span style={{ color: 'var(--ink)' }}>{t.driver}</span>
                </INMono>
                <INMono size={10} color="var(--ink-3)" style={{ marginTop: 6, display: 'block' }}>
                  Forecast next 30d: <span className="num" style={{ color: 'var(--ink)' }}>{fmtNum(t.forecast30d)}</span> streams
                </INMono>
              </button>
            ))}
          </div>
        </div>
      )}

      {/* Filter strip */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 0, borderBottom: '1px solid var(--rule)', marginBottom: 14, paddingBottom: 10 }}>
        {[['all','All'],['rising','Rising'],['falling','Falling'],['breakout','Breakouts']].map(([k, l]) => (
          <button key={k} onClick={() => setFilter(k)} className="ff-mono upper"
            style={{
              padding: '7px 14px', border: 0, fontSize: 10, letterSpacing: '.1em',
              background: filter === k ? 'var(--ink)' : 'transparent',
              color: filter === k ? 'var(--bg)' : 'var(--ink-2)', cursor: 'pointer'
            }}>{l}</button>
        ))}
        <span style={{ flex: 1 }}/>
        <INMono size={11} color="var(--ink-3)">{filtered.length} of {trends.length}</INMono>
      </div>

      {/* Trends table */}
      <div style={{ border: '1px solid var(--rule)' }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 90px 70px 80px 100px 1fr', gap: 14, padding: '8px 16px', background: 'var(--bg-2)', borderBottom: '1px solid var(--rule)' }}>
          <INMono upper size={9} color="var(--ink-3)">TRACK</INMono>
          <INMono upper size={9} color="var(--ink-3)">14-DAY</INMono>
          <INMono upper size={9} color="var(--ink-3)" style={{ textAlign: 'right' }}>W/W</INMono>
          <INMono upper size={9} color="var(--ink-3)" style={{ textAlign: 'right' }}>M/M</INMono>
          <INMono upper size={9} color="var(--ink-3)" style={{ textAlign: 'right' }}>FORECAST 30D</INMono>
          <INMono upper size={9} color="var(--ink-3)">DRIVER</INMono>
        </div>
        {filtered.map((t, i) => (
          <button key={i} onClick={() => go && go('recording', { id: t.r.id })}
            style={{
              display: 'grid', gridTemplateColumns: '1.6fr 90px 70px 80px 100px 1fr',
              gap: 14, padding: '12px 16px', alignItems: 'center',
              border: 0, background: 'transparent',
              borderBottom: i < filtered.length - 1 ? '1px solid var(--rule-soft, var(--bg-2))' : 'none',
              width: '100%', textAlign: 'left', cursor: 'pointer'
            }}>
            <div>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{t.r.title}</div>
              <INMono size={10} color="var(--ink-3)" style={{ marginTop: 2, display: 'block' }}>{t.r.artist}</INMono>
            </div>
            <INSpark data={t.spark} color={t.direction === 'rising' ? 'var(--ok)' : t.direction === 'falling' ? 'var(--danger)' : 'var(--ink-3)'} w={84} h={24}/>
            <INMono size={12} color={t.wow > 0 ? 'var(--ok)' : 'var(--danger)'} style={{ textAlign: 'right' }}>
              {fmtPct(t.wow, true)}
            </INMono>
            <INMono size={12} color={t.mom > 0 ? 'var(--ok)' : 'var(--danger)'} style={{ textAlign: 'right' }}>
              {fmtPct(t.mom, true)}
            </INMono>
            <INMono size={12} color="var(--ink)" style={{ textAlign: 'right' }}>
              {fmtNum(t.forecast30d)}
            </INMono>
            <INMono size={11} color="var(--ink-2)">{t.driver}</INMono>
          </button>
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────── 03 ANOMALIES TAB
function INAnomaliesTab({ go }) {
  const recordings = (window.__RECORDINGS || window.RECORDINGS || []).slice(0, 60);
  const rng = _IN_useM(() => inSeed('anomalies-2026'), []);
  const anomalies = _IN_useM(() => buildAnomalies(rng, recordings), []);
  const [openId, setOpenId] = _IN_useS(null);
  const open = anomalies.find(a => a.id === openId);

  const SEV = {
    critical: { fg: 'var(--danger)', l: 'CRITICAL' },
    high:     { fg: 'var(--danger)', l: 'HIGH' },
    medium:   { fg: 'var(--warn, #d4881f)', l: 'MEDIUM' },
    low:      { fg: 'var(--ink-3)', l: 'LOW' },
  };

  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', border: '1px solid var(--rule)', marginBottom: 24 }}>
        <INKpi l="OPEN ANOMALIES"     v={anomalies.length}/>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="CRITICAL · HIGH"  v={anomalies.filter(a => a.sev === 'critical' || a.sev === 'high').length} danger/>
        </div>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="EST. EXPOSURE"    v={fmtUsd(82_400)} sub="potential under-payment + leakage"/>
        </div>
        <div style={{ borderLeft: '1px solid var(--rule)' }}>
          <INKpi l="MODEL UPDATED"    v="6m ago" sub="rolling 90d baseline"/>
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: open ? '1fr 1fr' : '1fr', gap: 24 }}>
        <div>
          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
            ANOMALIES · SORTED BY SEVERITY
          </INMono>
          <div style={{ border: '1px solid var(--rule)' }}>
            {anomalies.map((a, i) => {
              const s = SEV[a.sev];
              const isOpen = a.id === openId;
              return (
                <button key={a.id}
                  onClick={() => setOpenId(isOpen ? null : a.id)}
                  style={{
                    display: 'grid', gridTemplateColumns: '4px 1fr auto',
                    gap: 12, padding: '14px 14px',
                    alignItems: 'center', width: '100%',
                    border: 0, borderLeft: '4px solid ' + s.fg,
                    background: isOpen ? 'var(--bg-2)' : 'transparent',
                    borderBottom: i < anomalies.length - 1 ? '1px solid var(--rule-soft, var(--bg-2))' : 'none',
                    cursor: 'pointer', textAlign: 'left'
                  }}>
                  <span/>
                  <div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
                      <INPill fg={s.fg} dot>{s.l}</INPill>
                      <INMono size={11} color="var(--ink-3)">{a.detected} ago</INMono>
                    </div>
                    <div style={{ fontSize: 13, fontWeight: 500 }}>{a.l}</div>
                    <INMono size={10} color="var(--ink-3)" style={{ marginTop: 3, display: 'block' }}>
                      {a.r.title} · {a.r.artist || '—'}
                    </INMono>
                  </div>
                  <div style={{ textAlign: 'right' }}>
                    <INMono size={12} color="var(--ink)">{a.magnitude}</INMono>
                    <INMono size={9} color="var(--ink-3)" style={{ display: 'block' }}>
                      {Math.round(a.confidence*100)}% conf
                    </INMono>
                  </div>
                </button>
              );
            })}
          </div>
        </div>

        {open && (
          <div>
            <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
              ANOMALY DETAIL
            </INMono>
            <div style={{ border: '1px solid var(--rule)', padding: 20 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12 }}>
                <INPill fg={SEV[open.sev].fg} dot>{SEV[open.sev].l}</INPill>
                <INMono size={11} color="var(--ink-3)">detected {open.detected} ago</INMono>
              </div>
              <h3 style={{ fontSize: 18, fontWeight: 500, margin: 0, marginBottom: 8, letterSpacing: '-0.01em' }}>{open.l}</h3>
              <INMono size={11} color="var(--ink-2)" style={{ display: 'block', marginBottom: 16 }}>
                {open.r.title} · ISRC {open.r.isrc || '—'} · {open.r.id}
              </INMono>

              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, marginBottom: 16 }}>
                <div style={{ padding: '12px 14px', background: 'var(--bg-2)' }}>
                  <INMono upper size={9} color="var(--ink-3)">MAGNITUDE</INMono>
                  <div className="ff-mono num" style={{ fontSize: 20, fontWeight: 500, marginTop: 4 }}>{open.magnitude}</div>
                </div>
                <div style={{ padding: '12px 14px', background: 'var(--bg-2)' }}>
                  <INMono upper size={9} color="var(--ink-3)">CONFIDENCE</INMono>
                  <div className="ff-mono num" style={{ fontSize: 20, fontWeight: 500, marginTop: 4 }}>{Math.round(open.confidence*100)}%</div>
                </div>
              </div>

              <INMono upper size={9} color="var(--ink-3)" style={{ display: 'block', marginBottom: 6 }}>RECOMMENDED ACTION</INMono>
              <div style={{ padding: '14px 16px', borderLeft: '3px solid var(--ink)', background: 'var(--bg-2)', fontSize: 13, marginBottom: 14, color: 'var(--ink)' }}>
                {open.recommended}
              </div>

              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={() => { go && go('recording', { id: open.r.id }); }} className="ff-mono upper"
                  style={{ fontSize: 10, letterSpacing: '.12em', padding: '8px 14px', background:'var(--ink)', color:'var(--bg)', border: 0, cursor: 'pointer' }}>
                  OPEN RECORDING →
                </button>
                <button onClick={() => window.dispatchEvent(new CustomEvent('astro-toast',{detail:{msg:'Anomaly dismissed',tone:'ok'}}))} className="ff-mono upper"
                  style={{ fontSize: 10, letterSpacing: '.12em', padding: '8px 14px', background:'transparent', color:'var(--ink-2)', border: '1px solid var(--rule)', cursor: 'pointer' }}>
                  DISMISS
                </button>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// ─────────────────────────────────────── 04 SEMANTIC SEARCH TAB
function INSemanticTab({ go }) {
  const [q, setQ] = _IN_useS('');
  const [active, setActive] = _IN_useS(null);
  const recordings = (window.__RECORDINGS || window.RECORDINGS || []).slice(0, 200);

  const recommend = (query) => {
    const rng = inSeed(query);
    const picks = recordings.slice().sort(() => rng() - 0.5).slice(0, 8);
    return picks.map(r => ({
      kind: 'recording', r,
      score: 0.74 + rng() * 0.24,
      reason: ['feature-distance match','contributor overlap','similar streaming pattern','genre tag co-occurrence','sync placement comp','playlist co-presence'][Math.floor(rng()*6)],
    }));
  };

  const submit = (query) => {
    const trimmed = (query || q).trim();
    if (!trimmed) return;
    setActive({
      query: trimmed,
      results: recommend(trimmed),
      ts: Date.now(),
    });
  };

  return (
    <div>
      <div style={{ marginBottom: 24 }}>
        <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
          ASK ASTRO · NATURAL LANGUAGE SEARCH ACROSS YOUR CATALOG
        </INMono>
        <div style={{ position: 'relative' }}>
          <input
            value={q}
            onChange={(e) => setQ(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter') submit(); }}
            placeholder="Try: songs that feel like Bon Iver but with a hip-hop drum kit"
            style={{
              width: '100%', padding: '18px 140px 18px 22px',
              fontSize: 15, fontFamily: 'inherit',
              background: 'var(--bg-2)', border: '1px solid var(--rule)', color: 'var(--ink)',
              outline: 'none', boxSizing: 'border-box'
            }}
          />
          <button onClick={() => submit()} className="ff-mono upper"
            style={{
              position: 'absolute', right: 6, top: '50%', transform: 'translateY(-50%)',
              padding: '8px 16px', fontSize: 10, letterSpacing: '.1em',
              background:'var(--ink)', color:'var(--bg)', border: 0, cursor: 'pointer'
            }}>
            ASK ↵
          </button>
        </div>
        <INMono size={11} color="var(--ink-3)" style={{ marginTop: 8, display: 'block' }}>
          Searches across audio features, contributors, statements, agreements and contracts. Powered by ASTRO's catalog embedding model.
        </INMono>
      </div>

      {!active && (
        <div>
          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 14 }}>
            EXAMPLE QUESTIONS · CLICK TO RUN
          </INMono>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 10 }}>
            {SEMANTIC_EXAMPLES.map((ex, i) => (
              <button key={i} onClick={() => { setQ(ex); submit(ex); }}
                style={{
                  textAlign: 'left', padding: '14px 16px',
                  border: '1px solid var(--rule)', background: 'var(--paper)',
                  cursor: 'pointer', fontFamily: 'inherit', display: 'flex', alignItems: 'center', gap: 12
                }}>
                <span className="ff-mono" style={{ fontSize: 11, color: 'var(--ink-3)' }}>0{i+1}</span>
                <span style={{ flex: 1, fontSize: 13, color: 'var(--ink)' }}>"{ex}"</span>
                <span className="ff-mono upper" style={{ fontSize: 9, letterSpacing: '.12em', color: 'var(--ink-3)' }}>RUN →</span>
              </button>
            ))}
          </div>
        </div>
      )}

      {active && (
        <div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, marginBottom: 18, paddingBottom: 12, borderBottom: '1px solid var(--rule)' }}>
            <div style={{ flex: 1 }}>
              <INMono upper size={9} color="var(--ink-3)">YOU ASKED</INMono>
              <div style={{ fontSize: 16, marginTop: 4, color: 'var(--ink)' }}>"{active.query}"</div>
            </div>
            <button onClick={() => { setActive(null); setQ(''); }} className="ff-mono upper"
              style={{ fontSize: 10, letterSpacing: '.12em', padding: '6px 12px', background:'transparent', border:'1px solid var(--rule)', color:'var(--ink-2)', cursor:'pointer' }}>
              ← NEW SEARCH
            </button>
          </div>

          <INMono upper size={10} color="var(--ink-3)" style={{ display: 'block', marginBottom: 12 }}>
            {active.results.length} MATCHES · RANKED BY SEMANTIC DISTANCE
          </INMono>

          <div style={{ border: '1px solid var(--rule)' }}>
            {active.results.map((res, i) => (
              <button key={i}
                onClick={() => go && go('recording', { id: res.r.id })}
                style={{
                  display: 'grid', gridTemplateColumns: 'auto 1fr 1fr 80px',
                  gap: 14, padding: '14px 16px', alignItems: 'center',
                  width: '100%', border: 0, background: 'transparent', textAlign: 'left',
                  borderBottom: i < active.results.length - 1 ? '1px solid var(--rule-soft, var(--bg-2))' : 'none',
                  cursor: 'pointer'
                }}>
                <span className="ff-mono num" style={{ fontSize: 22, fontWeight: 500, color: 'var(--ink-3)', minWidth: 32 }}>{i+1}</span>
                <div>
                  <div style={{ fontSize: 14, fontWeight: 500 }}>{res.r.title}</div>
                  <INMono size={10} color="var(--ink-3)" style={{ marginTop: 3, display: 'block' }}>{res.r.artist} · {res.r.year}</INMono>
                </div>
                <INMono size={11} color="var(--ink-2)">{res.reason}</INMono>
                <div style={{ textAlign: 'right' }}>
                  <INMono size={11} color="var(--ink)">{Math.round(res.score * 100)}%</INMono>
                  <INMono size={9} color="var(--ink-3)" style={{ display: 'block' }}>match</INMono>
                </div>
              </button>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────── MAIN
function ScreenInsights({ go, payload }) {
  const [tab, setTab] = _IN_useS(payload?.tab || 'valuation');

  const TABS = [
    { k: 'valuation',  l: 'Valuation' },
    { k: 'trends',     l: 'Trends' },
    { k: 'anomalies',  l: 'Anomalies' },
    { k: 'semantic',   l: 'Ask ASTRO' },
    { k: 'predict',    l: 'Predictions' },
    { k: 'leaks',      l: 'Leaks' },
    { k: 'forecast',   l: 'Forecast' },
    { k: 'cluster',    l: 'Clusters' },
    { k: 'covers',     l: 'Covers / Samples' },
    { k: 'bbrank',     l: 'Black-Box' },
    { k: 'patterns',   l: 'Patterns' },
    { k: 'nlp',        l: 'NLP' },
  ];

  return (
    <div>
      <PageHeader
        eyebrow={['ANALYTICS', 'INSIGHTS', 'ML + NLP']}
        title="insights"
        highlight="insights"
        sub="Predictive layer over your catalog. Catalog valuation, trend forecasting, anomaly detection, and natural-language search across everything ASTRO has indexed — works, recordings, statements, contracts, audiences."
      />

      <div style={{ borderBottom: '1px solid var(--rule)', display: 'flex', gap: 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 === 'valuation'  && <INValuationTab go={go}/>}
        {tab === 'trends'     && <INTrendsTab go={go}/>}
        {tab === 'anomalies'  && <INAnomaliesTab go={go}/>}
        {tab === 'semantic'   && <INSemanticTab go={go}/>}
        {tab === 'predict'    && window.ScreenPredictions && <window.ScreenPredictions go={go} payload={{ tab: 'success' }} embed/>}
        {tab === 'leaks'      && window.MLLeaksTab    && <window.MLLeaksTab go={go}/>}
        {tab === 'forecast'   && window.MLForecastTab && <window.MLForecastTab go={go}/>}
        {tab === 'cluster'    && window.MLClusterTab  && <window.MLClusterTab go={go}/>}
        {tab === 'covers'     && window.MLCoversTab   && <window.MLCoversTab go={go}/>}
        {tab === 'bbrank'     && window.MLBBRankTab   && <window.MLBBRankTab go={go}/>}
        {tab === 'patterns'   && window.MLPatternsTab && <window.MLPatternsTab go={go}/>}
        {tab === 'nlp'        && window.MLNLPTab      && <window.MLNLPTab go={go}/>}
      </div>
    </div>
  );
}

window.ScreenInsights = ScreenInsights;
