// RISK SUB-PLATFORMS — enriched implementations that override the 25-line
// stubs defined in RiskOpps.jsx. Loaded AFTER RiskOpps so the later
// window.Rk* assignments win.
//
// Each sub-platform gets:
//   - KPI strip (3–5 headline metrics)
//   - Chart / heatmap / distribution panel where the data supports it
//   - Filterable/sortable table with empty-state fallback
//   - Action row (Export, New, filter chips)
//   - Telemetry hook on mount
//
// Coverage (14 of 25):
//   Treatment   — RkAppetite, RkControls, RkInsurance
//   Indicators  — RkKRI, RkIncidents, RkCyber, RkRegWatch
//   Quant       — RkTornado, RkVaR, RkReserves, RkStress
//   Reporting   — RkPortfolio, RkMaturity
//   Governance  — RkVendors, RkAttorneyProfiles
//
// The remaining stubs keep working (RkTriggers, RkPriority, RkBowTie,
// RkCommittee, RkReporter, RkEthicalWalls, RkClientRatings, RkSettlementTree,
// RkTreatments, RkMitigationEffect) because RiskOpps defined them first.

(function () {
  const { useState, useMemo, useEffect } = React;
  const T = window.ArbiterTokens;
  const rk = window.rk;
  const Icons = window.Icons || {};
  const A = window.Arbiter || {};

  // ── shared helpers ──────────────────────────────────────────────────────
  const fmtMoney = n => n == null ? '—' :
    '$' + (n >= 1e6 ? (n / 1e6).toFixed(1) + 'M' :
          n >= 1e3 ? (n / 1e3).toFixed(0) + 'K' : String(n));
  const trackView = (id) => useEffect(() => { A.track?.('risk.subplatform.view', { id }); }, [id]);

  // KPI strip — Bloomberg density, Apple elegance
  const Kpi = ({ label, value, hint, color, right }) => (
    <div className="arb-elev-1"
      style={{
        flex: 1, minWidth: 140, padding: '11px 14px 10px',
        background: T.color.bg.card, borderRadius: 8,
        transition: 'transform 160ms var(--easing-standard,ease), box-shadow 160ms',
        cursor: 'default',
      }}
      onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-1px)'; e.currentTarget.style.boxShadow = '0 2px 8px rgba(10,22,40,0.08), 0 0 0 1px var(--color-border-medium)'; }}
      onMouseLeave={e => { e.currentTarget.style.transform = 'none'; e.currentTarget.style.boxShadow = ''; }}>
      <div style={{ fontSize: 9.5, fontWeight: 600, color: T.color.text.tertiary,
        textTransform: 'uppercase', letterSpacing: '0.1em' }}>{label}</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 5 }}>
        <span className="arb-num" style={{ fontSize: 22, fontWeight: 700,
          color: color || T.color.text.primary, letterSpacing: '-0.025em', lineHeight: 1.05 }}>{value}</span>
        {right && <span className="arb-num" style={{ marginLeft: 'auto', fontSize: 11, color: T.color.text.tertiary }}>{right}</span>}
      </div>
      {hint && <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 3, letterSpacing: '-0.005em' }}>{hint}</div>}
    </div>
  );
  const KpiRow = ({ children }) => (
    <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 14 }}>{children}</div>
  );

  const Card = ({ title, right, children, pad = true }) => (
    <div style={rk.card}>
      <div style={rk.cardH}><span>{title}</span>{right}</div>
      <div style={{ padding: pad ? '12px 16px' : 0 }}>{children}</div>
    </div>
  );

  const TH = ({ children, w, r }) => (
    <th style={{ textAlign: r ? 'right' : 'left', padding: '6px 10px', fontSize: 10,
      fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase',
      letterSpacing: '0.08em', borderBottom: `1px solid ${T.color.border.light}`,
      width: w, whiteSpace: 'nowrap' }}>{children}</th>
  );
  const TD = ({ children, mono, r, c, clamp }) => (
    <td style={{ padding: '8px 10px', fontSize: 12, color: c || T.color.text.primary,
      borderBottom: `1px solid ${T.color.border.light}`,
      fontFamily: mono ? T.font.mono : T.font.family, textAlign: r ? 'right' : 'left',
      maxWidth: clamp ? 240 : 'none', overflow: clamp ? 'hidden' : 'visible',
      textOverflow: clamp ? 'ellipsis' : 'clip', whiteSpace: clamp ? 'nowrap' : 'normal' }}>{children}</td>
  );
  const Pill = ({ children, color, strong }) => (
    <span style={{ display: 'inline-flex', padding: '2px 8px', borderRadius: 10,
      fontSize: 10, fontWeight: 600,
      background: (color || T.color.text.tertiary) + (strong ? '' : '22'),
      color: strong ? '#fff' : (color || T.color.text.secondary) }}>{children}</span>
  );

  // Horizontal bar comparing current vs. threshold/target.
  const BarMeter = ({ value, max, color, warn }) => {
    const pct = Math.min(100, Math.max(0, (value / max) * 100));
    const over = value > max;
    const overColor = over ? (warn || '#C23030') : color;
    return (
      <div style={{ width: '100%', height: 6, background: T.color.bg.tertiary, borderRadius: 6, position: 'relative', overflow: 'hidden' }}>
        <div style={{
          width: pct + '%', height: '100%',
          background: `linear-gradient(90deg, ${overColor}B3 0%, ${overColor} 100%)`,
          borderRadius: 6,
          boxShadow: over ? `0 0 6px ${overColor}66` : 'none',
          transition: 'width 300ms var(--easing-standard,ease)',
        }} />
      </div>
    );
  };

  // Sparkline — n-point trend line
  const Sparkline = ({ points, color = '#6E7D9E', w = 64, h = 18 }) => {
    if (!points?.length) return null;
    const min = Math.min(...points), max = Math.max(...points);
    const span = max - min || 1;
    const path = points.map((p, i) =>
      `${i === 0 ? 'M' : 'L'} ${(i / (points.length - 1)) * w} ${h - ((p - min) / span) * h}`
    ).join(' ');
    return (
      <svg width={w} height={h} aria-hidden="true" style={{ display: 'block' }}>
        <path d={path} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    );
  };

  // Stat distribution bar — counts by category
  const Distribution = ({ counts, total, colors }) => (
    <div style={{ display: 'flex', height: 8, borderRadius: 4, overflow: 'hidden',
      border: `1px solid ${T.color.border.light}` }}>
      {Object.entries(counts).map(([k, v]) => (
        <div key={k} title={`${k}: ${v}`} style={{ width: (v / total) * 100 + '%', background: colors[k] || T.color.text.tertiary }} />
      ))}
    </div>
  );

  // Toolbar with search + export
  const Toolbar = ({ search, setSearch, filters, rows, filename, extra }) => (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10, flexWrap: 'wrap' }}>
      {setSearch && (
        <input aria-label="Search"
          placeholder="Search…"
          value={search} onChange={e => setSearch(e.target.value)}
          style={{ height: 28, border: `1px solid ${T.color.border.light}`,
            borderRadius: 6, padding: '0 10px', fontSize: 12, fontFamily: T.font.family,
            background: T.color.bg.card, color: T.color.text.primary, width: 200 }} />
      )}
      {filters}
      <div style={{ marginLeft: 'auto', display: 'flex', gap: 8 }}>
        {extra}
        {rows && A.ExportButton && React.createElement(A.ExportButton, { rows, filename })}
      </div>
    </div>
  );

  const colorByStatus = (s) => ({
    within: '#1B7A4A', 'at-limit': '#D97706', breach: '#C23030',
    effective: '#1B7A4A', partial: '#D97706', ineffective: '#C23030',
    active: '#1B7A4A', tracking: '#3B82F6', analysis: '#D97706',
    complied: '#6E7D9E', closed: '#6E7D9E', rising: '#C23030',
    stable: '#6E7D9E', declining: '#1B7A4A',
  }[s] || T.color.text.secondary);

  const trendArrow = (t) => {
    if (t === 'rising')    return <span style={{ color: '#C23030' }} aria-label="rising">↑</span>;
    if (t === 'declining') return <span style={{ color: '#1B7A4A' }} aria-label="declining">↓</span>;
    return <span style={{ color: T.color.text.tertiary }} aria-label="stable">→</span>;
  };

  const Empty = ({ title, description }) =>
    A.EmptyState ? React.createElement(A.EmptyState, { title, description })
      : <div role="status" style={{ padding: '24px', textAlign: 'center', color: T.color.text.tertiary, fontSize: 12 }}>{title}</div>;

  // ════════════════════════════════════════════════════════════════════════
  //  TREATMENT — Appetite
  // ════════════════════════════════════════════════════════════════════════
  function RkAppetite() {
    trackView('appetite');
    const s = window.useRiskStore(['risk.updated', 'appetite.checked']);
    const rows = s.appetiteThresholds;
    const breach = rows.filter(r => r.status === 'breach').length;
    const atLimit = rows.filter(r => r.status === 'at-limit').length;
    const within = rows.filter(r => r.status === 'within').length;
    const maxExposure = rows.reduce((a, r) => a + r.maxLoss, 0);

    return (
      <div>
        <KpiRow>
          <Kpi label="Categories" value={rows.length} />
          <Kpi label="Within appetite" value={within} color="#1B7A4A" />
          <Kpi label="At limit" value={atLimit} color="#D97706" />
          <Kpi label="In breach" value={breach} color="#C23030" hint="requires committee review" />
          <Kpi label="Max exposure" value={fmtMoney(maxExposure)} hint="sum of category caps" />
        </KpiRow>
        <Card title="Appetite utilization by category"
          right={<Pill color="#C23030">{breach} breach{breach === 1 ? '' : 'es'}</Pill>}>
          <div style={{ display: 'grid', gap: 10 }}>
            {rows.map(a => (
              <div key={a.category} style={{ display: 'grid', gridTemplateColumns: '140px 1fr 80px 70px', gap: 10, alignItems: 'center' }}>
                <div style={{ fontSize: 12, fontWeight: 600 }}>{a.category}</div>
                <div>
                  <BarMeter value={a.currentAvg} max={a.tolerance}
                    color={a.status === 'breach' ? '#C23030' : a.status === 'at-limit' ? '#D97706' : '#1B7A4A'} />
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>
                    <span>target {a.target}</span>
                    <span style={{ fontFamily: T.font.mono, color: a.currentAvg > a.tolerance ? '#C23030' : T.color.text.secondary }}>
                      current {a.currentAvg} / tolerance {a.tolerance}
                    </span>
                  </div>
                </div>
                <div style={{ fontSize: 11, fontFamily: T.font.mono, color: T.color.text.secondary }}>{fmtMoney(a.maxLoss)}</div>
                <Pill color={colorByStatus(a.status)}>{a.status}</Pill>
              </div>
            ))}
          </div>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  TREATMENT — Controls
  // ════════════════════════════════════════════════════════════════════════
  function RkControls() {
    trackView('controls');
    const s = window.useRiskStore(['control.tested']);
    const [q, setQ] = useState('');
    const [result, setResult] = useState('all');
    const filtered = s.controlTests.filter(c =>
      (result === 'all' || c.result === result) &&
      (q === '' || (c.control + c.owner + c.riskId).toLowerCase().includes(q.toLowerCase()))
    );
    const effective = s.controlTests.filter(c => c.result === 'effective').length;
    const partial = s.controlTests.filter(c => c.result === 'partial').length;
    const ineffective = s.controlTests.filter(c => c.result === 'ineffective').length;
    const effectiveness = Math.round((effective / s.controlTests.length) * 100);

    const chip = (v, label) => (
      <button key={v} onClick={() => setResult(v)} style={{
        padding: '4px 10px', borderRadius: 12, border: `1px solid ${result === v ? rk.crimson : T.color.border.medium}`,
        background: result === v ? rk.crimson : 'transparent',
        color: result === v ? '#fff' : T.color.text.secondary,
        fontSize: 11, cursor: 'pointer' }}>{label}</button>
    );

    return (
      <div>
        <KpiRow>
          <Kpi label="Controls" value={s.controlTests.length} />
          <Kpi label="Effective" value={effective} color="#1B7A4A" />
          <Kpi label="Partial" value={partial} color="#D97706" />
          <Kpi label="Ineffective" value={ineffective} color="#C23030" />
          <Kpi label="Overall effectiveness" value={effectiveness + '%'} hint="% effective of tested" />
        </KpiRow>
        <Card title="Control test evidence"
          right={<Distribution counts={{ effective, partial, ineffective }} total={s.controlTests.length}
            colors={{ effective: '#1B7A4A', partial: '#D97706', ineffective: '#C23030' }} />}>
          <Toolbar search={q} setSearch={setQ} rows={filtered} filename="controls"
            filters={<div style={{ display: 'flex', gap: 6 }}>
              {chip('all', 'All')}{chip('effective', 'Effective')}{chip('partial', 'Partial')}{chip('ineffective', 'Ineffective')}
            </div>} />
          {filtered.length === 0 ? <Empty title="No controls match" description="Try clearing the filter." /> :
            <table style={{ width: '100%', borderCollapse: 'collapse' }}>
              <thead><tr><TH>ID</TH><TH>Control</TH><TH>Risk</TH><TH>Last tested</TH><TH>Next</TH><TH>Result</TH><TH>Owner</TH><TH>Findings</TH></tr></thead>
              <tbody>{filtered.map(c => (
                <tr key={c.id}>
                  <TD mono>{c.id}</TD>
                  <TD>{c.control}</TD>
                  <TD mono>{c.riskId}</TD>
                  <TD mono>{c.lastTested}</TD>
                  <TD mono c={T.color.text.tertiary}>{c.nextTest}</TD>
                  <TD><Pill color={colorByStatus(c.result)}>{c.result}</Pill></TD>
                  <TD>{c.owner}</TD>
                  <TD c={T.color.text.tertiary} clamp>{c.findings || '—'}</TD>
                </tr>
              ))}</tbody>
            </table>}
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  TREATMENT — Insurance
  // ════════════════════════════════════════════════════════════════════════
  function RkInsurance() {
    trackView('insurance');
    const s = window.useRiskStore(['insurance.noticed']);
    const rows = s.insurancePolicies;
    const totalLimit = rows.reduce((a, p) => a + p.limit, 0);
    const totalPremium = rows.reduce((a, p) => a + p.annualPremium, 0);
    const totalRetention = rows.reduce((a, p) => a + p.retention, 0);
    const byType = rows.reduce((a, p) => ({ ...a, [p.type]: (a[p.type] || 0) + p.limit }), {});
    const today = new Date('2026-04-23');
    const expiringSoon = rows.filter(p => {
      const d = new Date(p.expires); return (d - today) / 86400000 < 180;
    }).length;

    return (
      <div>
        <KpiRow>
          <Kpi label="Policies" value={rows.length} />
          <Kpi label="Aggregate limits" value={fmtMoney(totalLimit)} />
          <Kpi label="Annual premium" value={fmtMoney(totalPremium)} hint={`blended rate ${(totalPremium / totalLimit * 100).toFixed(2)}%`} />
          <Kpi label="Total retention" value={fmtMoney(totalRetention)} />
          <Kpi label="Expiring ≤ 180d" value={expiringSoon} color={expiringSoon ? '#D97706' : undefined} />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 14 }}>
          <Card title="Policy schedule">
            <Toolbar rows={rows} filename="insurance" />
            <table style={{ width: '100%', borderCollapse: 'collapse' }}>
              <thead><tr>
                <TH>Carrier</TH><TH>Type</TH><TH r>Limit</TH><TH r>Retention</TH><TH r>Premium</TH><TH>Expires</TH><TH>Risks</TH>
              </tr></thead>
              <tbody>{rows.map(p => (
                <tr key={p.id}>
                  <TD>{p.carrier}</TD>
                  <TD>{p.type}</TD>
                  <TD mono r>{fmtMoney(p.limit)}</TD>
                  <TD mono r>{fmtMoney(p.retention)}</TD>
                  <TD mono r>{fmtMoney(p.annualPremium)}</TD>
                  <TD mono>{p.expires}</TD>
                  <TD c={T.color.text.tertiary} clamp>{(p.coveredRisks || []).join(', ') || '—'}</TD>
                </tr>
              ))}</tbody>
            </table>
          </Card>
          <Card title="Limits by type">
            <div style={{ display: 'grid', gap: 8 }}>
              {Object.entries(byType).sort((a,b)=>b[1]-a[1]).map(([type, lim]) => (
                <div key={type}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11 }}>
                    <span>{type}</span>
                    <span style={{ fontFamily: T.font.mono, color: T.color.text.secondary }}>{fmtMoney(lim)}</span>
                  </div>
                  <BarMeter value={lim} max={totalLimit} color={rk.crimson} />
                </div>
              ))}
            </div>
          </Card>
        </div>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  INDICATORS — KRI
  // ════════════════════════════════════════════════════════════════════════
  function RkKRI() {
    trackView('kri');
    const s = window.useRiskStore(['kri.checked', 'risk.updated']);
    const rows = s.kriIndicators;
    const breached = rows.filter(k => k.current > k.threshold);
    const rising = rows.filter(k => k.trend === 'rising');
    // synthetic 7-point history for sparkline
    const synthHistory = (k) => Array.from({ length: 7 }, (_, i) => {
      const trend = k.trend === 'rising' ? i * 0.06 : k.trend === 'declining' ? -i * 0.06 : 0;
      const noise = Math.sin(i * 1.3 + k.id.length) * 0.03;
      return k.current * (1 - trend + noise);
    });

    return (
      <div>
        <KpiRow>
          <Kpi label="Indicators" value={rows.length} />
          <Kpi label="Breached" value={breached.length} color={breached.length ? '#C23030' : '#1B7A4A'} />
          <Kpi label="Rising" value={rising.length} color={rising.length ? '#D97706' : undefined} />
          <Kpi label="Coverage" value={new Set(rows.flatMap(r => r.related)).size} hint="unique risks tracked by KRIs" />
        </KpiRow>
        <Card title="KRI grid · threshold monitoring">
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: 10 }}>
            {rows.map(k => {
              const over = k.current > k.threshold;
              return (
                <div key={k.id} style={{
                  padding: 12, borderRadius: 8,
                  border: `1px solid ${over ? '#C2303040' : T.color.border.light}`,
                  background: over ? 'rgba(194,48,48,0.04)' : T.color.bg.card,
                }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 8 }}>
                    <div style={{ fontSize: 11, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase' }}>{k.name}</div>
                    {trendArrow(k.trend)}
                  </div>
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 4 }}>
                    <span style={{ fontSize: 24, fontWeight: 700, fontFamily: T.font.mono,
                      color: over ? '#C23030' : T.color.text.primary }}>{k.current}</span>
                    <span style={{ fontSize: 11, color: T.color.text.tertiary, fontFamily: T.font.mono }}>/ {k.threshold}</span>
                    <span style={{ marginLeft: 'auto' }}><Sparkline points={synthHistory(k)} color={over ? '#C23030' : T.color.text.tertiary} /></span>
                  </div>
                  <div style={{ marginTop: 6 }}>
                    <BarMeter value={k.current} max={k.threshold} color={over ? '#C23030' : '#3B82F6'} />
                  </div>
                  <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 6, display: 'flex', justifyContent: 'space-between' }}>
                    <span>{k.window} window</span>
                    <span>{k.related.length ? k.related.slice(0, 2).join(', ') + (k.related.length > 2 ? '…' : '') : '—'}</span>
                  </div>
                </div>
              );
            })}
          </div>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  INDICATORS — Incidents
  // ════════════════════════════════════════════════════════════════════════
  function RkIncidents() {
    trackView('incidents');
    const s = window.useRiskStore(['incident.logged']);
    const [severity, setSeverity] = useState('all');
    const rows = s.incidents.filter(i => severity === 'all' || i.severity === severity);
    const nearMiss = s.incidents.filter(i => i.type === 'near-miss').length;
    const incident = s.incidents.filter(i => i.type === 'incident').length;
    const byRoot = s.incidents.reduce((a, i) => ({ ...a, [i.rootCause]: (a[i.rootCause] || 0) + 1 }), {});

    const chip = (v, label) => (
      <button key={v} onClick={() => setSeverity(v)} style={{
        padding: '4px 10px', borderRadius: 12,
        border: `1px solid ${severity === v ? rk.crimson : T.color.border.medium}`,
        background: severity === v ? rk.crimson : 'transparent',
        color: severity === v ? '#fff' : T.color.text.secondary,
        fontSize: 11, cursor: 'pointer' }}>{label}</button>
    );

    return (
      <div>
        <KpiRow>
          <Kpi label="Total events" value={s.incidents.length} />
          <Kpi label="Incidents" value={incident} color="#C23030" />
          <Kpi label="Near-miss" value={nearMiss} color="#D97706" />
          <Kpi label="Resolved" value={s.incidents.filter(i => i.resolved).length} color="#1B7A4A" />
          <Kpi label="Lessons captured" value={s.incidents.filter(i => i.lessons).length} hint="continuous improvement inputs" />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 260px', gap: 14 }}>
          <Card title="Incident & near-miss log">
            <Toolbar rows={rows} filename="incidents"
              filters={<div style={{ display: 'flex', gap: 6 }}>
                {chip('all','All')}{chip('high','High')}{chip('medium','Medium')}{chip('low','Low')}
              </div>} />
            {rows.length === 0 ? <Empty title="No events" /> :
              <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                <thead><tr><TH>ID</TH><TH>Date</TH><TH>Type</TH><TH>Severity</TH><TH>Description</TH><TH>Risk</TH><TH>Lessons</TH></tr></thead>
                <tbody>{rows.map(i => (
                  <tr key={i.id}>
                    <TD mono>{i.id}</TD>
                    <TD mono>{i.date}</TD>
                    <TD><Pill color={i.type === 'incident' ? '#C23030' : '#D97706'}>{i.type}</Pill></TD>
                    <TD><Pill color={i.severity === 'high' ? '#C23030' : i.severity === 'medium' ? '#D97706' : '#6E7D9E'}>{i.severity}</Pill></TD>
                    <TD clamp>{i.description}</TD>
                    <TD mono c={T.color.text.tertiary}>{i.relatedRisk || '—'}</TD>
                    <TD c={T.color.text.tertiary} clamp>{i.lessons || '—'}</TD>
                  </tr>
                ))}</tbody>
              </table>}
          </Card>
          <Card title="Root-cause distribution">
            <div style={{ display: 'grid', gap: 8 }}>
              {Object.entries(byRoot).sort((a,b)=>b[1]-a[1]).map(([root, n]) => (
                <div key={root}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11 }}>
                    <span>{root}</span>
                    <span style={{ fontFamily: T.font.mono, color: T.color.text.secondary }}>{n}</span>
                  </div>
                  <BarMeter value={n} max={Math.max(...Object.values(byRoot))} color="#3B82F6" />
                </div>
              ))}
            </div>
          </Card>
        </div>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  INDICATORS — Cyber
  // ════════════════════════════════════════════════════════════════════════
  function RkCyber() {
    trackView('cyber');
    const s = window.useRiskStore();
    const rows = s.cyberRegister;
    const high = rows.filter(c => c.exposure === 'high').length;
    const totalBreach = rows.reduce((a, c) => a + c.breachScore, 0);
    const today = new Date('2026-04-23');
    const stalePentest = rows.filter(c => (today - new Date(c.lastPenTest)) / 86400000 > 180).length;

    return (
      <div>
        <KpiRow>
          <Kpi label="Assets" value={rows.length} />
          <Kpi label="High exposure" value={high} color={high ? '#C23030' : '#1B7A4A'} />
          <Kpi label="Aggregate breach score" value={totalBreach} hint="0–10 per asset, summed" />
          <Kpi label="Stale pen-test (>180d)" value={stalePentest} color={stalePentest ? '#D97706' : undefined} />
        </KpiRow>
        <Card title="Cyber asset register">
          <Toolbar rows={rows} filename="cyber-assets" />
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead><tr><TH>Asset</TH><TH>Class</TH><TH>Vendor</TH><TH>Last pen-test</TH><TH>Exposure</TH><TH r>Score</TH><TH>Mitigations</TH></tr></thead>
            <tbody>{rows.map(c => (
              <tr key={c.id}>
                <TD>{c.asset}</TD>
                <TD><Pill color={c.classification === 'AEO' ? '#C23030' : c.classification === 'Confidential' ? '#D97706' : '#6E7D9E'}>{c.classification}</Pill></TD>
                <TD>{c.vendor}</TD>
                <TD mono>{c.lastPenTest}</TD>
                <TD><Pill color={c.exposure === 'high' ? '#C23030' : c.exposure === 'medium' ? '#D97706' : '#1B7A4A'}>{c.exposure}</Pill></TD>
                <TD mono r><span style={{ color: c.breachScore >= 6 ? '#C23030' : c.breachScore >= 4 ? '#D97706' : '#1B7A4A' }}>{c.breachScore}</span></TD>
                <TD c={T.color.text.tertiary} clamp>{c.mitigations.join(', ')}</TD>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  INDICATORS — Regulatory Watch
  // ════════════════════════════════════════════════════════════════════════
  function RkRegWatch() {
    trackView('regwatch');
    const s = window.useRiskStore();
    const rows = s.regulatoryWatch;
    const today = new Date('2026-04-23');
    const withDays = rows.map(r => ({ ...r, daysOut: Math.ceil((new Date(r.effective) - today) / 86400000) }))
      .sort((a, b) => a.daysOut - b.daysOut);
    const high = rows.filter(r => r.impact === 'high').length;
    const soon = withDays.filter(r => r.daysOut > 0 && r.daysOut < 90).length;

    return (
      <div>
        <KpiRow>
          <Kpi label="Rules tracked" value={rows.length} />
          <Kpi label="High impact" value={high} color={high ? '#C23030' : undefined} />
          <Kpi label="Effective <90d" value={soon} color={soon ? '#D97706' : undefined} />
          <Kpi label="Jurisdictions" value={new Set(rows.map(r => r.jurisdiction)).size} />
        </KpiRow>
        <Card title="Regulatory horizon · timeline">
          <div style={{ display: 'grid', gap: 10 }}>
            {withDays.map(r => (
              <div key={r.id} style={{ display: 'grid', gridTemplateColumns: '80px 1fr 90px 110px 90px', gap: 10, alignItems: 'center',
                padding: '8px 10px', borderBottom: `1px solid ${T.color.border.light}` }}>
                <div style={{ fontSize: 11, fontFamily: T.font.mono, color: T.color.text.tertiary }}>
                  {r.daysOut < 0 ? `${-r.daysOut}d past` : `${r.daysOut}d out`}
                </div>
                <div>
                  <div style={{ fontSize: 12, fontWeight: 600 }}>{r.rule}</div>
                  <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>
                    effective {r.effective} · {r.area} · matters: {(r.matters || []).join(', ') || 'none'}
                  </div>
                </div>
                <Pill color={r.impact === 'high' ? '#C23030' : r.impact === 'medium' ? '#D97706' : '#6E7D9E'}>{r.impact}</Pill>
                <div style={{ fontSize: 11, color: T.color.text.secondary }}>{r.jurisdiction}</div>
                <Pill color={colorByStatus(r.status)}>{r.status}</Pill>
              </div>
            ))}
          </div>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  QUANT — Tornado (sensitivity)
  // ════════════════════════════════════════════════════════════════════════
  function RkTornado() {
    trackView('tornado');
    const s = window.useRiskStore();
    const rows = [...s.sensitivityFactors].sort((a, b) => b.range - a.range);
    const maxRange = Math.max(...rows.map(r => r.range));
    const base = rows.reduce((a, r) => a + (r.low + r.high) / 2, 0) / rows.length;

    return (
      <div>
        <KpiRow>
          <Kpi label="Factors" value={rows.length} />
          <Kpi label="Baseline EV" value={fmtMoney(base)} hint="avg midpoint of factor swings" />
          <Kpi label="Widest swing" value={fmtMoney(rows[0].range)} hint={rows[0].factor} />
          <Kpi label="Aggregate uncertainty" value={fmtMoney(rows.reduce((a, r) => a + r.range, 0))} />
        </KpiRow>
        <Card title="Tornado — factor sensitivity (sorted by impact)">
          <div style={{ display: 'grid', gap: 6 }}>
            {rows.map(r => {
              const span = (r.high - r.low);
              const pct = (span / maxRange) * 100;
              return (
                <div key={r.id} style={{ display: 'grid', gridTemplateColumns: '160px 1fr 110px', gap: 10, alignItems: 'center' }}>
                  <div style={{ fontSize: 12, fontWeight: 600 }}>{r.factor}</div>
                  <div style={{ position: 'relative', height: 22, background: T.color.bg.tertiary, borderRadius: 4 }}>
                    <div style={{ position: 'absolute', top: 2, bottom: 2, left: `${50 - pct/2}%`, width: `${pct}%`,
                      background: `linear-gradient(90deg, #3B82F6 0%, ${rk.crimson} 100%)`,
                      borderRadius: 3 }} />
                    <div style={{ position: 'absolute', top: 0, bottom: 0, left: '50%', width: 1, background: T.color.text.tertiary }} />
                  </div>
                  <div style={{ fontSize: 11, fontFamily: T.font.mono, color: T.color.text.secondary, textAlign: 'right' }}>
                    {fmtMoney(r.low)} → {fmtMoney(r.high)}
                  </div>
                </div>
              );
            })}
          </div>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  QUANT — VaR / CVaR
  // ════════════════════════════════════════════════════════════════════════
  function RkVaR() {
    trackView('var');
    const s = window.useRiskStore();
    const v = s.varResults;

    return (
      <div>
        <KpiRow>
          <Kpi label="Horizon" value={v.horizon} />
          <Kpi label={`VaR ${Math.round(v.confidence*100)}%`} value={fmtMoney(v.var95)} color="#D97706"
            hint="loss exceeded 5% of the time" />
          <Kpi label="CVaR (tail)" value={fmtMoney(v.cvar95)} color="#C23030"
            hint="avg loss in the worst 5%" />
          <Kpi label="Exposure at default" value={fmtMoney(v.ead)} />
          <Kpi label="Last run" value={v.lastRun} hint={v.method} />
        </KpiRow>
        <Card title="Loss distribution (synthetic)">
          {/* crude bell + tail visualization */}
          <svg width="100%" height="180" viewBox="0 0 400 180" aria-label="Loss distribution">
            <defs>
              <linearGradient id="rkVarG" x1="0" x2="1">
                <stop offset="0%"  stopColor="#3B82F6" stopOpacity="0.1" />
                <stop offset="60%" stopColor="#D97706" stopOpacity="0.25" />
                <stop offset="100%" stopColor="#C23030" stopOpacity="0.45" />
              </linearGradient>
            </defs>
            {/* normal curve */}
            <path d={(() => {
              let d = 'M 0 180';
              for (let x = 0; x <= 400; x += 4) {
                const t = (x - 220) / 55;
                const y = 180 - 120 * Math.exp(-0.5 * t * t);
                d += ` L ${x} ${y}`;
              }
              return d + ' L 400 180 Z';
            })()} fill="url(#rkVarG)" />
            {/* VaR line */}
            <line x1="290" x2="290" y1="20" y2="180" stroke="#D97706" strokeDasharray="3,3" />
            <text x="294" y="32" fontSize="11" fill="#D97706" fontFamily={T.font.mono}>VaR 95%</text>
            {/* CVaR line */}
            <line x1="335" x2="335" y1="20" y2="180" stroke="#C23030" strokeDasharray="3,3" />
            <text x="339" y="46" fontSize="11" fill="#C23030" fontFamily={T.font.mono}>CVaR</text>
            {/* axis */}
            <line x1="0" x2="400" y1="180" y2="180" stroke={T.color.border.medium} />
          </svg>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  QUANT — Reserves (ASC 450)
  // ════════════════════════════════════════════════════════════════════════
  function RkReserves() {
    trackView('reserves');
    const s = window.useRiskStore();
    const rows = s.reserves || [];
    const total = rows.reduce((a, r) => a + (r.accrued || 0), 0);
    const disclosed = rows.filter(r => r.disclosure === 'disclosed').length;

    if (!rows.length) return <Empty title="No reserves recorded" description="ASC 450 accruals appear here after booking." />;

    return (
      <div>
        <KpiRow>
          <Kpi label="Matters" value={rows.length} />
          <Kpi label="Accrued total" value={fmtMoney(total)} color="#C23030" />
          <Kpi label="Disclosed" value={disclosed} hint="per ASC 450-20-50" />
        </KpiRow>
        <Card title="Loss contingency reserves · ASC 450">
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead><tr><TH>Matter</TH><TH>Classification</TH><TH r>Accrued</TH><TH r>Range low</TH><TH r>Range high</TH><TH>Disclosure</TH><TH>As of</TH></tr></thead>
            <tbody>{rows.map(r => (
              <tr key={r.id || r.matter}>
                <TD>{r.matter}</TD>
                <TD><Pill color={r.classification === 'probable' ? '#C23030' : r.classification === 'reasonably-possible' ? '#D97706' : '#6E7D9E'}>{r.classification}</Pill></TD>
                <TD mono r>{fmtMoney(r.accrued)}</TD>
                <TD mono r c={T.color.text.tertiary}>{fmtMoney(r.low)}</TD>
                <TD mono r c={T.color.text.tertiary}>{fmtMoney(r.high)}</TD>
                <TD><Pill color={r.disclosure === 'disclosed' ? '#1B7A4A' : '#6E7D9E'}>{r.disclosure}</Pill></TD>
                <TD mono c={T.color.text.tertiary}>{r.asOf || '—'}</TD>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  QUANT — Stress Tests
  // ════════════════════════════════════════════════════════════════════════
  function RkStress() {
    trackView('stress');
    const s = window.useRiskStore();
    const rows = s.stressTests || [];
    if (!rows.length) return <Empty title="No stress scenarios" description="Configure stress scenarios to see impact per risk." />;
    const maxImpact = Math.max(...rows.map(r => r.impact || 0));

    return (
      <div>
        <KpiRow>
          <Kpi label="Scenarios" value={rows.length} />
          <Kpi label="Worst-case impact" value={fmtMoney(maxImpact)} color="#C23030" />
          <Kpi label="Avg likelihood" value={(rows.reduce((a,r)=>a+(r.probability||0),0) / rows.length * 100).toFixed(0) + '%'} />
        </KpiRow>
        <Card title="Stress scenario impact">
          <div style={{ display: 'grid', gap: 10 }}>
            {rows.map(r => (
              <div key={r.id || r.scenario} style={{ display: 'grid', gridTemplateColumns: '200px 1fr 80px', gap: 10, alignItems: 'center' }}>
                <div style={{ fontSize: 12, fontWeight: 600 }}>{r.scenario}</div>
                <BarMeter value={r.impact || 0} max={maxImpact} color={rk.crimson} />
                <div style={{ fontSize: 11, fontFamily: T.font.mono, color: T.color.text.secondary, textAlign: 'right' }}>{fmtMoney(r.impact)}</div>
              </div>
            ))}
          </div>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  REPORTING — Portfolio
  // ════════════════════════════════════════════════════════════════════════
  function RkPortfolio() {
    trackView('portfolio');
    const s = window.useRiskStore(['risk.updated']);
    const rows = s.clientPortfolios;
    const totalLoss = rows.reduce((a, r) => a + r.expectedLoss, 0);
    const highConc = rows.filter(r => r.concentration === 'high').length;
    const maxScore = Math.max(...rows.map(r => r.aggregateScore));

    return (
      <div>
        <KpiRow>
          <Kpi label="Clients" value={rows.length} />
          <Kpi label="Aggregate expected loss" value={fmtMoney(totalLoss)} color="#C23030" />
          <Kpi label="High concentration" value={highConc} color={highConc ? '#D97706' : undefined} />
          <Kpi label="Active risks" value={rows.reduce((a, r) => a + r.activeRisks, 0)} />
          <Kpi label="Avg relationship score" value={(rows.filter(r => r.relationshipScore != null).reduce((a, r) => a + r.relationshipScore, 0) / rows.filter(r => r.relationshipScore != null).length).toFixed(1)} hint="1–10 partner survey" />
        </KpiRow>
        <Card title="Client exposure · sorted by aggregate score">
          <Toolbar rows={rows} filename="portfolio" />
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead><tr><TH>Client</TH><TH r>Matters</TH><TH r>Active risks</TH><TH>Score</TH><TH r>Expected loss</TH><TH>Concentration</TH><TH r>Relationship</TH></tr></thead>
            <tbody>{[...rows].sort((a,b)=>b.aggregateScore-a.aggregateScore).map(c => (
              <tr key={c.id}>
                <TD>{c.client}</TD>
                <TD mono r>{c.matters}</TD>
                <TD mono r>{c.activeRisks}</TD>
                <TD>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                    <span style={{ fontFamily: T.font.mono, color: c.aggregateScore > 60 ? '#C23030' : T.color.text.primary, minWidth: 32 }}>{c.aggregateScore}</span>
                    <div style={{ flex: 1, minWidth: 80 }}><BarMeter value={c.aggregateScore} max={maxScore} color={c.aggregateScore > 60 ? '#C23030' : '#3B82F6'} /></div>
                  </div>
                </TD>
                <TD mono r>{fmtMoney(c.expectedLoss)}</TD>
                <TD><Pill color={c.concentration === 'high' ? '#C23030' : c.concentration === 'medium' ? '#D97706' : '#1B7A4A'}>{c.concentration}</Pill></TD>
                <TD mono r c={T.color.text.tertiary}>{c.relationshipScore ?? '—'}</TD>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  REPORTING — ERM Maturity
  // ════════════════════════════════════════════════════════════════════════
  function RkMaturity() {
    trackView('maturity');
    const s = window.useRiskStore();
    const rows = s.ermMaturity;
    const avg = rows.reduce((a, r) => a + r.current, 0) / rows.length;
    const targetAvg = rows.reduce((a, r) => a + r.target, 0) / rows.length;
    const gaps = rows.filter(r => r.current < r.target).length;

    return (
      <div>
        <KpiRow>
          <Kpi label="Dimensions" value={rows.length} />
          <Kpi label="Avg maturity" value={avg.toFixed(1) + ' / 5'} />
          <Kpi label="Target avg" value={targetAvg.toFixed(1) + ' / 5'} hint="12-month target" />
          <Kpi label="Dimensions with gap" value={gaps} color={gaps ? '#D97706' : '#1B7A4A'} />
        </KpiRow>
        <Card title="ERM maturity · per dimension (COSO 2017 / ISO 31000)">
          <div style={{ display: 'grid', gap: 12 }}>
            {rows.map(r => {
              const gap = r.target - r.current;
              return (
                <div key={r.dimension} style={{ display: 'grid', gridTemplateColumns: '180px 1fr 60px', gap: 10, alignItems: 'center' }}>
                  <div>
                    <div style={{ fontSize: 12, fontWeight: 600 }}>{r.dimension}</div>
                    <div style={{ fontSize: 10, color: T.color.text.tertiary }}>{r.framework}</div>
                  </div>
                  <div>
                    <div style={{ position: 'relative', height: 14, background: T.color.bg.tertiary, borderRadius: 7 }}>
                      <div style={{ width: (r.current / 5) * 100 + '%', height: '100%', background: gap > 0 ? '#D97706' : '#1B7A4A', borderRadius: 7 }} />
                      <div style={{ position: 'absolute', top: 0, bottom: 0, left: (r.target / 5) * 100 + '%', borderLeft: `2px dashed ${T.color.text.secondary}` }} />
                    </div>
                    {r.gap && <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>gap — {r.gap}</div>}
                  </div>
                  <div style={{ fontSize: 13, fontFamily: T.font.mono, textAlign: 'right',
                    color: gap > 0 ? '#D97706' : '#1B7A4A' }}>{r.current} / {r.target}</div>
                </div>
              );
            })}
          </div>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  GOVERNANCE — Vendors
  // ════════════════════════════════════════════════════════════════════════
  function RkVendors() {
    trackView('vendors');
    const s = window.useRiskStore();
    const rows = s.vendorPanel;
    const flagged = rows.filter(v => v.risks.length > 0).length;
    const avgRating = (rows.reduce((a, v) => a + v.rating, 0) / rows.length).toFixed(1);
    const totalEng = rows.reduce((a, v) => a + v.engagements, 0);
    const stars = (n) => '●'.repeat(Math.round(n)) + '○'.repeat(5 - Math.round(n));

    return (
      <div>
        <KpiRow>
          <Kpi label="Panel vendors" value={rows.length} />
          <Kpi label="Active" value={rows.filter(v => v.status === 'active').length} color="#1B7A4A" />
          <Kpi label="Avg rating" value={avgRating + ' / 5'} />
          <Kpi label="Flagged" value={flagged} color={flagged ? '#D97706' : undefined} hint="issues open" />
          <Kpi label="Total engagements" value={totalEng} />
        </KpiRow>
        <Card title="Vendor panel · ratings & retention history">
          <Toolbar rows={rows} filename="vendors" />
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead><tr><TH>Vendor</TH><TH>Type</TH><TH>Specialty</TH><TH>Rating</TH><TH r>Engagements</TH><TH>Last retained</TH><TH>Status</TH><TH>Open issues</TH></tr></thead>
            <tbody>{rows.map(v => (
              <tr key={v.id}>
                <TD>{v.name}</TD>
                <TD>{v.type}</TD>
                <TD c={T.color.text.tertiary}>{v.specialty}</TD>
                <TD>
                  <span style={{ color: '#C9A84C', fontFamily: T.font.mono, letterSpacing: '0.1em' }}>{stars(v.rating)}</span>
                  <span style={{ marginLeft: 6, fontFamily: T.font.mono, fontSize: 11, color: T.color.text.secondary }}>{v.rating}</span>
                </TD>
                <TD mono r>{v.engagements}</TD>
                <TD mono>{v.lastRetained}</TD>
                <TD><Pill color={v.status === 'active' ? '#1B7A4A' : '#6E7D9E'}>{v.status}</Pill></TD>
                <TD c={v.risks.length ? '#D97706' : T.color.text.tertiary} clamp>{v.risks.join(', ') || '—'}</TD>
              </tr>
            ))}</tbody>
          </table>
        </Card>
      </div>
    );
  }

  // ════════════════════════════════════════════════════════════════════════
  //  GOVERNANCE — Attorney Profiles
  // ════════════════════════════════════════════════════════════════════════
  function RkAttorneyProfiles() {
    trackView('attorneys');
    const s = window.useRiskStore();
    const rows = s.attorneyProfiles;
    const overUtil = rows.filter(a => a.utilization > 100).length;
    const cleOut = rows.filter(a => !a.cleSuffiencies).length;
    const malpractice = rows.reduce((a, r) => a + r.malpractice, 0);
    const avgWin = (rows.filter(r => r.winRate != null).reduce((a, r) => a + r.winRate, 0) / rows.filter(r => r.winRate != null).length).toFixed(0);

    return (
      <div>
        <KpiRow>
          <Kpi label="Attorneys" value={rows.length} />
          <Kpi label="Over-utilized (>100%)" value={overUtil} color={overUtil ? '#C23030' : '#1B7A4A'} />
          <Kpi label="CLE deficient" value={cleOut} color={cleOut ? '#D97706' : '#1B7A4A'} />
          <Kpi label="Avg win rate" value={avgWin + '%'} />
          <Kpi label="Malpractice claims" value={malpractice} color={malpractice ? '#C23030' : '#1B7A4A'} />
        </KpiRow>
        <Card title="Attorney profile · utilization, realization, training">
          <Toolbar rows={rows} filename="attorneys" />
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead><tr><TH>Attorney</TH><TH>Role</TH><TH>Utilization</TH><TH>Realization</TH><TH r>Win rate</TH><TH>CLE</TH><TH>Cyber training</TH><TH r>Complaints</TH></tr></thead>
            <tbody>{rows.map(a => {
              const overU = a.utilization > 100;
              return (
                <tr key={a.id}>
                  <TD>{a.name}</TD>
                  <TD c={T.color.text.secondary}>{a.role}</TD>
                  <TD>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      <span style={{ minWidth: 36, fontFamily: T.font.mono, color: overU ? '#C23030' : T.color.text.primary }}>{a.utilization}%</span>
                      <div style={{ flex: 1, minWidth: 70 }}><BarMeter value={a.utilization} max={100} color={overU ? '#C23030' : '#3B82F6'} /></div>
                    </div>
                  </TD>
                  <TD>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      <span style={{ minWidth: 36, fontFamily: T.font.mono }}>{a.realization}%</span>
                      <div style={{ flex: 1, minWidth: 70 }}><BarMeter value={a.realization} max={100} color="#1B7A4A" /></div>
                    </div>
                  </TD>
                  <TD mono r>{a.winRate ?? '—'}{a.winRate != null && '%'}</TD>
                  <TD><Pill color={a.cleSuffiencies ? '#1B7A4A' : '#C23030'}>{a.cleSuffiencies ? 'current' : 'deficient'}</Pill></TD>
                  <TD mono c={T.color.text.tertiary}>{a.cyberTraining}</TD>
                  <TD mono r c={a.complaints ? '#C23030' : T.color.text.tertiary}>{a.complaints}</TD>
                </tr>
              );
            })}</tbody>
          </table>
        </Card>
      </div>
    );
  }

  // ── Override exports (RiskOpps assigned first; we win on second assignment)
  Object.assign(window, {
    RkAppetite, RkControls, RkInsurance,
    RkKRI, RkIncidents, RkCyber, RkRegWatch,
    RkTornado, RkVaR, RkReserves, RkStress,
    RkPortfolio, RkMaturity,
    RkVendors, RkAttorneyProfiles,
  });

  // ── Re-define the hub wrappers so their sub-tab dispatch reads from
  // window.* at render time instead of the module-local closures that
  // RiskOpps.jsx captured. Without this, our overrides above never reach
  // the render path.
  const RkSubTabs = window.RkSubTabs;
  const pick = (name, fallbackName) => window[name] || window[fallbackName];

  function RiskTreatmentHub() {
    const [sub, setSub] = useState('appetite');
    const tabs = [
      { id: 'appetite',   label: 'Appetite' },
      { id: 'controls',   label: 'Controls' },
      { id: 'treatments', label: 'Treatments' },
      { id: 'insurance',  label: 'Insurance' },
      { id: 'effect',     label: 'Effectiveness' },
    ];
    const map = {
      appetite:   window.RkAppetite,
      controls:   window.RkControls,
      treatments: window.RkTreatments,
      insurance:  window.RkInsurance,
      effect:     window.RkMitigationEffect,
    };
    const Comp = map[sub] || (() => null);
    return <div><RkSubTabs tabs={tabs} active={sub} onChange={setSub} /><Comp /></div>;
  }

  function RiskIndicatorsHub() {
    const [sub, setSub] = useState('kri');
    const tabs = [
      { id: 'kri',       label: 'KRIs' },
      { id: 'triggers',  label: 'Triggers' },
      { id: 'regwatch',  label: 'Regulatory' },
      { id: 'incidents', label: 'Incidents' },
      { id: 'cyber',     label: 'Cyber' },
      { id: 'priority',  label: 'Priority Queue' },
    ];
    const map = {
      kri: window.RkKRI, triggers: window.RkTriggers, regwatch: window.RkRegWatch,
      incidents: window.RkIncidents, cyber: window.RkCyber, priority: window.RkPriority,
    };
    const Comp = map[sub] || (() => null);
    return <div><RkSubTabs tabs={tabs} active={sub} onChange={setSub} /><Comp /></div>;
  }

  function RiskQuantHub() {
    const [sub, setSub] = useState('tornado');
    const tabs = [
      { id: 'tornado',  label: 'Tornado' },
      { id: 'var',      label: 'VaR / CVaR' },
      { id: 'reserves', label: 'ASC 450' },
      { id: 'bowtie',   label: 'Bow-Tie' },
      { id: 'stress',   label: 'Stress Tests' },
    ];
    const map = {
      tornado: window.RkTornado, var: window.RkVaR, reserves: window.RkReserves,
      bowtie: window.RkBowTie, stress: window.RkStress,
    };
    const Comp = map[sub] || (() => null);
    return <div><RkSubTabs tabs={tabs} active={sub} onChange={setSub} /><Comp /></div>;
  }

  function RiskReportingHub() {
    const [sub, setSub] = useState('portfolio');
    const tabs = [
      { id: 'portfolio', label: 'Portfolio' },
      { id: 'committee', label: 'Committee' },
      { id: 'templates', label: 'Templates' },
      { id: 'maturity',  label: 'ERM Maturity' },
    ];
    const map = {
      portfolio: window.RkPortfolio, committee: window.RkCommittee,
      templates: window.RkReporter, maturity: window.RkMaturity,
    };
    const Comp = map[sub] || (() => null);
    return <div><RkSubTabs tabs={tabs} active={sub} onChange={setSub} /><Comp /></div>;
  }

  function RiskGovernanceHub() {
    const [sub, setSub] = useState('walls');
    const tabs = [
      { id: 'walls',      label: 'Ethical Walls' },
      { id: 'vendors',    label: 'Vendors' },
      { id: 'clients',    label: 'Client Ratings' },
      { id: 'attorneys',  label: 'Attorney Profiles' },
      { id: 'settlement', label: 'Settlement Tree' },
    ];
    const map = {
      walls: window.RkEthicalWalls, vendors: window.RkVendors,
      clients: window.RkClientRatings, attorneys: window.RkAttorneyProfiles,
      settlement: window.RkSettlementTree,
    };
    const Comp = map[sub] || (() => null);
    return <div><RkSubTabs tabs={tabs} active={sub} onChange={setSub} /><Comp /></div>;
  }

  Object.assign(window, {
    RiskTreatmentHub, RiskIndicatorsHub, RiskQuantHub,
    RiskReportingHub, RiskGovernanceHub,
  });

  // Risk-specific commands
  if (window.Arbiter?.CommandRegistry) {
    const R = window.Arbiter.CommandRegistry;
    [
      ['treatment',  'Risk: Treatment'],
      ['indicators', 'Risk: Indicators'],
      ['quant',      'Risk: Quantification'],
      ['reporting',  'Risk: Reporting'],
      ['governance', 'Risk: Governance'],
    ].forEach(([sub, label]) => R.register(`risk.${sub}`, {
      label, group: 'Risk', keywords: 'risk ' + sub,
      run: () => {
        window.dispatchEvent(new CustomEvent('arbiter:navigate', { detail: { view: 'risk' } }));
        // Consumer must listen for a secondary event to switch Risk sub-tab; here we
        // just drop a toast that the section was requested.
        window.Arbiter?.toast?.({ title: label, message: 'Section opened.' });
      },
    }));
  }
})();
