// CALENDAR — enterprise upgrades for 20 sub-platform opportunities.
// Loaded AFTER CalendarOpps.jsx / CalendarAdvanced.jsx / CalendarExtras.jsx
// so window.Cal* reassignments win.
//
// Structure:
//   1. Shared primitives (KPI, Sparkline, Heatmap, TimelineSwimlanes, etc.)
//   2. 20 enriched components (grouped by sub-platform)
//   3. Hub overrides (Views, Resources, Prep, Analytics, Rules, Schedule,
//      Practice, Compliance)
//
// Style: Apple meets Bloomberg — generous whitespace, dense data, strong
// semantic color, tabular numerics.

(function () {
  const { useState, useMemo, useEffect, useRef, useCallback } = React;
  const T  = window.ArbiterTokens;
  const cal = window.cal;
  const A  = window.Arbiter || {};
  const TODAY = new Date('2026-04-20');

  // ═════════════════════════════════════════════════════════════════════════
  //  SHARED PRIMITIVES
  // ═════════════════════════════════════════════════════════════════════════

  const CARD = {
    background: T.color.bg.card,
    border: `1px solid ${T.color.border.light}`,
    borderRadius: 8,
    overflow: 'hidden',
  };

  const Kpi = ({ label, value, hint, color, right, delta }) => (
    <div className="arb-elev-1"
      style={{
        padding: '12px 14px 11px',
        background: T.color.bg.card, borderRadius: 8,
        display: 'flex', flexDirection: 'column', gap: 2,
        transition: 'transform 160ms var(--easing-standard,ease), box-shadow 160ms',
      }}
      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 = ''; }}>
      <span style={{ fontSize: 9.5, fontWeight: 600, color: T.color.text.tertiary,
        textTransform: 'uppercase', letterSpacing: '0.1em' }}>{label}</span>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
        <span className="arb-num" style={{ fontSize: 22, fontWeight: 700,
          color: color || T.color.text.primary, letterSpacing: '-0.025em', lineHeight: 1.05 }}>{value}</span>
        {delta && <span className="arb-num" style={{ fontSize: 10.5, color: delta.startsWith('-') ? '#C23030' : delta.startsWith('+') ? '#059669' : T.color.text.tertiary }}>{delta}</span>}
        {right && <span className="arb-num" style={{ marginLeft: 'auto', fontSize: 11, color: T.color.text.tertiary }}>{right}</span>}
      </div>
      {hint && <span style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>{hint}</span>}
    </div>
  );
  const KpiRow = ({ cols, children }) => (
    <div style={{ display: 'grid', gridTemplateColumns: cols || 'repeat(auto-fit, minmax(160px, 1fr))', gap: 10, marginBottom: 14 }}>
      {children}
    </div>
  );

  const Card = ({ title, right, children, pad = true, dense }) => (
    <div style={{ ...CARD, marginBottom: 14 }}>
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: dense ? '8px 14px' : '10px 16px',
        borderBottom: `1px solid ${T.color.border.light}`,
        fontSize: 11, fontWeight: 600, color: T.color.text.secondary,
        textTransform: 'uppercase', letterSpacing: '0.08em',
      }}>
        <span>{title}</span>{right}
      </div>
      <div style={{ padding: pad ? (dense ? 10 : 14) : 0 }}>{children}</div>
    </div>
  );

  const Pill = ({ children, color, strong }) => (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '2px 8px', borderRadius: 10, fontSize: 10, fontWeight: 600,
      background: strong ? color : (color || T.color.text.tertiary) + '18',
      color: strong ? '#fff' : (color || T.color.text.secondary),
    }}>{children}</span>
  );

  const priorityColor = (p) =>
    p === 'critical' ? '#C23030' : p === 'high' ? '#D97706' :
    p === 'medium'   ? '#2563EB' : '#6E7D9E';

  const daysBetween = (a, b) => Math.ceil((new Date(a) - new Date(b)) / 86400000);
  const fmtDate = (d) => new Date(d).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
  const fmtDateY = (d) => new Date(d).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: '2-digit' });

  const Sparkline = ({ points, color = '#2563EB', w = 80, h = 24, showArea = true }) => {
    if (!points?.length) return null;
    const min = Math.min(...points), max = Math.max(...points);
    const span = max - min || 1;
    const step = w / Math.max(1, points.length - 1);
    const pts = points.map((p, i) => ({ x: i * step, y: h - ((p - min) / span) * h }));
    const d = pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ');
    const a = showArea ? d + ` L${w},${h} L0,${h} Z` : '';
    return (
      <svg width={w} height={h} aria-hidden="true" style={{ display: 'block' }}>
        {showArea && <path d={a} fill={color} opacity="0.12" />}
        <path d={d} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
        <circle cx={pts[pts.length-1].x} cy={pts[pts.length-1].y} r="2.5" fill={color} />
      </svg>
    );
  };

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

  const Toolbar = ({ left, right, dense }) => (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 8,
      marginBottom: 10, flexWrap: 'wrap',
      padding: dense ? 0 : '0 2px',
    }}>
      <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>{left}</div>
      <div style={{ flex: 1 }} />
      <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>{right}</div>
    </div>
  );

  const Input = ({ style, ...rest }) => (
    <input className="arb-input" style={{ height: 28, fontSize: 11.5, ...style }} {...rest} />
  );
  const Chip = ({ active, onClick, children, color }) => (
    <button onClick={onClick} style={{
      padding: '3px 10px', fontSize: 11, borderRadius: 12,
      border: `1px solid ${active ? (color || '#2563EB') : T.color.border.medium}`,
      background: active ? (color || '#2563EB') + '14' : 'transparent',
      color: active ? (color || '#2563EB') : T.color.text.secondary,
      cursor: 'pointer', fontFamily: T.font.family, whiteSpace: 'nowrap',
    }}>{children}</button>
  );

  // ═════════════════════════════════════════════════════════════════════════
  //  #1 + #19 — Timeline Swimlanes (unified matter view)
  // ═════════════════════════════════════════════════════════════════════════
  function CalSwimlanes() {
    const dl = window.DOCKET_DEADLINES || [];
    A.useTrack?.('cal.views.swimlanes', {}, []);
    const [scale, setScale] = useState(6);          // px per day
    const [windowDays, setWindowDays] = useState(90);
    const startDate = new Date(TODAY); startDate.setDate(startDate.getDate() - 14);
    const days = Array.from({ length: windowDays }, (_, i) => {
      const d = new Date(startDate); d.setDate(d.getDate() + i); return d;
    });
    // Group by matter
    const matters = useMemo(() => {
      const map = {};
      dl.forEach(d => { (map[d.matter] = map[d.matter] || []).push(d); });
      return Object.entries(map).map(([matter, items]) => ({ matter, items: items.sort((a,b) => a.date.localeCompare(b.date)) }));
    }, [dl]);
    const laneHeight = 44;
    const rowWidth = days.length * scale;
    const dayIndex = (dateStr) => {
      const n = daysBetween(dateStr, startDate);
      return Math.max(0, Math.min(days.length - 1, n));
    };
    const todayX = dayIndex(TODAY) * scale;

    return (
      <div>
        <KpiRow>
          <Kpi label="Active matters" value={matters.length} />
          <Kpi label="Deadlines plotted" value={dl.length} />
          <Kpi label="Next 14 days" value={dl.filter(d => daysBetween(d.date, TODAY) >= 0 && daysBetween(d.date, TODAY) <= 14).length} color="#D97706" />
          <Kpi label="Window" value={`${windowDays}d`} hint="zoom with chips" />
        </KpiRow>
        <Card title="Matter swimlanes" dense
          right={<div style={{ display: 'flex', gap: 6 }}>
            {[{w:30,l:'30d'},{w:90,l:'90d'},{w:180,l:'6mo'},{w:365,l:'1y'}].map(o =>
              <Chip key={o.w} active={windowDays === o.w} onClick={() => setWindowDays(o.w)}>{o.l}</Chip>)}
            <span style={{ width: 1, background: T.color.border.light, margin: '0 4px' }} />
            {[{s:4,l:'–'},{s:6,l:'◇'},{s:10,l:'+'}].map(o =>
              <Chip key={o.s} active={scale === o.s} onClick={() => setScale(o.s)}>{o.l}</Chip>)}
          </div>} pad={false}>
          <div style={{ overflow: 'auto', maxHeight: 520 }}>
            {/* Day axis */}
            <div style={{ display: 'grid', gridTemplateColumns: `200px ${rowWidth}px`, position: 'sticky', top: 0, zIndex: 2, background: T.color.bg.secondary }}>
              <div style={{ padding: '8px 12px', fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em', borderBottom: `1px solid ${T.color.border.light}` }}>Matter</div>
              <div style={{ position: 'relative', height: 32, borderBottom: `1px solid ${T.color.border.light}` }}>
                {days.filter((_, i) => i % 7 === 0).map((d, i) => (
                  <div key={i} style={{
                    position: 'absolute', left: daysBetween(d, startDate) * scale,
                    fontSize: 9, color: T.color.text.tertiary, fontFamily: T.font.mono,
                    padding: '8px 0 0 2px', borderLeft: `1px solid ${T.color.border.light}`,
                    height: '100%',
                  }}>{fmtDate(d)}</div>
                ))}
                {/* Today line */}
                <div style={{ position: 'absolute', left: todayX, top: 0, bottom: 0, width: 2, background: '#C23030', zIndex: 3 }} />
              </div>
            </div>
            {/* Swimlanes */}
            {matters.map(({ matter, items }, mi) => (
              <div key={matter} style={{
                display: 'grid', gridTemplateColumns: `200px ${rowWidth}px`,
                borderBottom: `1px solid ${T.color.border.light}`,
                background: mi % 2 ? T.color.bg.primary : T.color.bg.card,
              }}>
                <div style={{
                  padding: '10px 12px', fontSize: 11, fontWeight: 600, color: T.color.text.primary,
                  borderRight: `1px solid ${T.color.border.light}`,
                  position: 'sticky', left: 0, background: 'inherit',
                  display: 'flex', flexDirection: 'column', gap: 2, minHeight: laneHeight,
                }}>
                  {matter}
                  <span className="arb-num" style={{ fontSize: 10, color: T.color.text.tertiary }}>{items.length} deadlines</span>
                </div>
                <div style={{ position: 'relative', height: laneHeight }}>
                  {/* Today line */}
                  <div style={{ position: 'absolute', left: todayX, top: 0, bottom: 0, width: 1, background: '#C23030', opacity: 0.4 }} />
                  {items.map(d => {
                    const x = dayIndex(d.date) * scale;
                    const c = priorityColor(d.priority);
                    const past = new Date(d.date) < TODAY;
                    return (
                      <div key={d.id} title={`${d.label} — ${fmtDateY(d.date)}`}
                        onClick={() => A.toast?.({ title: d.label, message: `${d.matter} · ${fmtDateY(d.date)}` })}
                        style={{
                          position: 'absolute', left: x - 3, top: 10,
                          width: 6, height: 24, background: c,
                          borderRadius: 2, cursor: 'pointer',
                          opacity: past ? 0.45 : 1,
                          boxShadow: `0 0 0 2px ${c}22`,
                          transition: 'transform 140ms, box-shadow 140ms',
                        }}
                        onMouseEnter={e => { e.currentTarget.style.transform = 'scaleX(1.6)'; e.currentTarget.style.boxShadow = `0 0 0 3px ${c}44, 0 2px 8px ${c}66`; }}
                        onMouseLeave={e => { e.currentTarget.style.transform = 'none'; e.currentTarget.style.boxShadow = `0 0 0 2px ${c}22`; }} />
                    );
                  })}
                </div>
              </div>
            ))}
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #2 — Today Mode (72-hour focus)
  // ═════════════════════════════════════════════════════════════════════════
  function CalTodayMode() {
    const dl = window.DOCKET_DEADLINES || [];
    A.useTrack?.('cal.views.today', {}, []);
    const buckets = useMemo(() => {
      const overdue = [], today = [], tomorrow = [];
      dl.forEach(d => {
        const diff = daysBetween(d.date, TODAY);
        if (diff < 0) overdue.push(d);
        else if (diff === 0) today.push(d);
        else if (diff === 1) tomorrow.push(d);
      });
      return { overdue, today, tomorrow };
    }, [dl]);

    const Lane = ({ title, items, color, subtitle }) => (
      <div style={{ ...CARD, display: 'flex', flexDirection: 'column', minHeight: 320 }}>
        <div style={{
          padding: '10px 14px', borderBottom: `1px solid ${T.color.border.light}`,
          background: color + '0F',
        }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <span style={{ fontSize: 11, fontWeight: 700, color, textTransform: 'uppercase', letterSpacing: '0.08em' }}>{title}</span>
            <span className="arb-num" style={{ fontSize: 13, fontWeight: 700, color, fontFamily: T.font.mono }}>{items.length}</span>
          </div>
          {subtitle && <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>{subtitle}</div>}
        </div>
        <div style={{ flex: 1, overflowY: 'auto', padding: 6 }}>
          {items.length === 0 && (
            <div role="status" style={{ padding: 24, textAlign: 'center', fontSize: 11, color: T.color.text.tertiary, fontStyle: 'italic' }}>
              Nothing here — breathe.
            </div>
          )}
          {items.map(d => {
            const c = priorityColor(d.priority);
            return (
              <div key={d.id}
                onClick={() => A.toast?.({ title: d.label, message: d.matter })}
                className="arb-row"
                style={{
                  padding: '10px 12px', borderRadius: 6,
                  borderLeft: `3px solid ${c}`,
                  marginBottom: 6,
                  background: T.color.bg.card,
                  cursor: 'pointer',
                  boxShadow: '0 1px 2px rgba(10,22,40,0.04)',
                }}>
                <div style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary, marginBottom: 3 }}>{d.label}</div>
                <div style={{ display: 'flex', gap: 8, alignItems: 'center', fontSize: 10, color: T.color.text.tertiary }}>
                  <span>{d.matter}</span>
                  <span>·</span>
                  <span className="arb-num">{fmtDateY(d.date)}</span>
                  <span style={{ marginLeft: 'auto' }}><Pill color={c}>{d.priority}</Pill></span>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    );

    return (
      <div>
        <KpiRow>
          <Kpi label="Overdue" value={buckets.overdue.length} color="#C23030" hint="action required" />
          <Kpi label="Due today" value={buckets.today.length} color="#D97706" />
          <Kpi label="Due tomorrow" value={buckets.tomorrow.length} color="#2563EB" />
          <Kpi label="This week" value={dl.filter(d => { const n = daysBetween(d.date, TODAY); return n >= 0 && n <= 7; }).length} />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14 }}>
          <Lane title="Overdue"       items={buckets.overdue}   color="#C23030" subtitle="filed late / remediation" />
          <Lane title="Today"         items={buckets.today}     color="#D97706" subtitle="all hands"                 />
          <Lane title="Tomorrow"      items={buckets.tomorrow}  color="#2563EB" subtitle="final prep window"         />
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #4 — Scheduling Assistant
  // ═════════════════════════════════════════════════════════════════════════
  function CalSchedulingAssistant() {
    const attorneys = window.ATTORNEYS || [];
    const [selected, setSelected] = useState(attorneys.slice(0, 3).map(a => a.id));
    const [duration, setDuration] = useState(60); // minutes
    const [preferMornings, setPreferMornings] = useState(true);
    A.useTrack?.('cal.schedule.assistant', {}, []);

    const slots = useMemo(() => {
      const result = [];
      const pool = attorneys.filter(a => selected.includes(a.id));
      for (let day = 1; day <= 5; day++) {
        const date = new Date(TODAY); date.setDate(date.getDate() + day);
        if (date.getDay() === 0 || date.getDay() === 6) continue;
        [9, 10.5, 13, 14.5, 16].forEach(hour => {
          if (preferMornings && hour >= 13) return;
          // Synthesize conflicts: hash of attorney+day+hour
          const conflicts = pool.filter(a => ((a.id.length + day * 7 + Math.floor(hour * 2)) % 7) < 2);
          const score = 100 - conflicts.length * 30;
          result.push({
            date, hour, conflicts, score,
            id: `${day}-${hour}`,
          });
        });
      }
      return result.sort((a, b) => b.score - a.score);
    }, [attorneys, selected, duration, preferMornings]);

    return (
      <div>
        <KpiRow cols="repeat(4,1fr)">
          <Kpi label="Attendees" value={selected.length} />
          <Kpi label="Duration" value={`${duration}m`} />
          <Kpi label="Top slot score" value={slots[0]?.score + '%' || '—'} color={slots[0]?.score >= 90 ? '#059669' : '#D97706'} />
          <Kpi label="Candidates" value={slots.length} />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: 14 }}>
          <Card title="Participants" dense>
            {attorneys.map(a => {
              const active = selected.includes(a.id);
              return (
                <div key={a.id} onClick={() => setSelected(s => active ? s.filter(x => x !== a.id) : [...s, a.id])}
                  className="arb-row"
                  style={{
                    padding: '8px 10px', borderRadius: 6, cursor: 'pointer',
                    display: 'flex', alignItems: 'center', gap: 8,
                    background: active ? a.color + '12' : 'transparent',
                    border: `1px solid ${active ? a.color + '55' : T.color.border.light}`,
                    marginBottom: 4,
                  }}>
                  <span style={{ width: 24, height: 24, borderRadius: '50%', background: a.color, color: '#fff', fontSize: 10, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>{a.initials}</span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 11.5, fontWeight: 600, color: T.color.text.primary }}>{a.name}</div>
                    <div style={{ fontSize: 10, color: T.color.text.tertiary }}>{a.role} · {a.capacity}% avail</div>
                  </div>
                  {active && <span style={{ fontSize: 9, color: a.color, fontWeight: 700 }}>✓</span>}
                </div>
              );
            })}
            <div style={{ paddingTop: 10, marginTop: 8, borderTop: `1px solid ${T.color.border.light}` }}>
              <div style={{ fontSize: 10, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6 }}>Duration</div>
              <div style={{ display: 'flex', gap: 4 }}>
                {[30, 60, 90, 120].map(d => <Chip key={d} active={duration === d} onClick={() => setDuration(d)}>{d}m</Chip>)}
              </div>
              <div style={{ fontSize: 10, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em', margin: '10px 0 6px' }}>Preferences</div>
              <Chip active={preferMornings} onClick={() => setPreferMornings(v => !v)}>Prefer mornings</Chip>
            </div>
          </Card>
          <Card title="Suggested times" dense
            right={<span style={{ fontSize: 10, color: T.color.text.tertiary }}>sorted by conflict score</span>}>
            {slots.slice(0, 10).map(s => {
              const hh = Math.floor(s.hour);
              const mm = (s.hour - hh) * 60;
              const timeStr = `${hh}:${String(mm).padStart(2, '0')}`;
              const scoreColor = s.score >= 90 ? '#059669' : s.score >= 70 ? '#D97706' : '#C23030';
              return (
                <div key={s.id} className="arb-row"
                  onClick={() => A.toast?.({ kind: 'active', title: 'Scheduled', message: `${fmtDateY(s.date)} ${timeStr} · ${selected.length} attendees` })}
                  style={{
                    display: 'grid', gridTemplateColumns: '72px 90px 1fr 50px',
                    gap: 10, padding: '10px 12px', borderRadius: 6, cursor: 'pointer',
                    borderLeft: `3px solid ${scoreColor}`,
                    marginBottom: 4, alignItems: 'center',
                  }}>
                  <span className="arb-num" style={{ fontSize: 11, color: T.color.text.secondary }}>{fmtDate(s.date)}</span>
                  <span className="arb-num" style={{ fontSize: 13, fontWeight: 700, color: T.color.text.primary }}>{timeStr}</span>
                  <div>
                    <div style={{ height: 6, borderRadius: 3, background: T.color.bg.tertiary }}>
                      <div style={{ width: s.score + '%', height: '100%', borderRadius: 3, background: `linear-gradient(90deg, ${scoreColor}B3, ${scoreColor})` }} />
                    </div>
                    <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 3 }}>
                      {s.conflicts.length === 0 ? 'no conflicts' : `${s.conflicts.length} conflict${s.conflicts.length === 1 ? '' : 's'}: ${s.conflicts.map(a => a.initials).join(', ')}`}
                    </div>
                  </div>
                  <span className="arb-num" style={{ fontSize: 13, fontWeight: 700, color: scoreColor, textAlign: 'right' }}>{s.score}</span>
                </div>
              );
            })}
          </Card>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #5 — Recurring rule builder (visual preview)
  // ═════════════════════════════════════════════════════════════════════════
  function CalRecurring() {
    const rules = window.RECURRING_EVENTS || [];
    const [selected, setSelected] = useState(rules[0]?.id);
    const rule = rules.find(r => r.id === selected) || rules[0];
    A.useTrack?.('cal.resources.recurring', {}, []);
    // Generate next 12 occurrences
    const occurrences = useMemo(() => {
      if (!rule) return [];
      const result = [];
      const start = new Date(TODAY);
      const bySameWeekday = { weekly: 7, biweekly: 14, monthly: 30, quarterly: 90 };
      const step = bySameWeekday[rule.frequency] || 30;
      for (let i = 0; i < 12; i++) {
        const d = new Date(start); d.setDate(d.getDate() + step * (i + 1));
        result.push(d);
      }
      return result;
    }, [rule]);

    return (
      <div>
        <KpiRow>
          <Kpi label="Active rules" value={rules.length} />
          <Kpi label="Skip holidays" value={rules.filter(r => r.skipHolidays).length} hint="court-day aware" />
          <Kpi label="Next 90 days" value={rules.reduce((a, r) => a + (r.frequency === 'weekly' ? 13 : r.frequency === 'biweekly' ? 6 : 3), 0)} hint="synthesized" />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 14 }}>
          <Card title="Rules" dense>
            {rules.map(r => (
              <div key={r.id} onClick={() => setSelected(r.id)}
                className="arb-row"
                style={{
                  padding: '10px 12px', borderRadius: 6, cursor: 'pointer',
                  background: selected === r.id ? '#2563EB11' : 'transparent',
                  border: `1px solid ${selected === r.id ? '#2563EB55' : T.color.border.light}`,
                  marginBottom: 4,
                }}>
                <div style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary }}>{r.name}</div>
                <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>
                  {r.frequency} · {r.time || 'all day'} · {r.skipHolidays ? 'court-day aware' : 'calendar-day'}
                </div>
              </div>
            ))}
          </Card>
          <Card title={rule ? `Preview · ${rule.name}` : 'Preview'} dense>
            {!rule && <div style={{ padding: 24, textAlign: 'center', color: T.color.text.tertiary, fontSize: 12 }}>Select a rule</div>}
            {rule && (
              <>
                <div style={{
                  padding: '10px 12px', background: T.color.bg.secondary, borderRadius: 6, marginBottom: 12,
                  fontSize: 12, color: T.color.text.primary, lineHeight: 1.6,
                }}>
                  <span style={{ fontSize: 10, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em' }}>Rule</span>
                  <div style={{ fontFamily: T.font.mono, fontSize: 12, marginTop: 4 }}>
                    every <b>{rule.frequency === 'weekly' ? '7 days' : rule.frequency === 'biweekly' ? '14 days' : 'month'}</b> at {rule.time || 'all day'},
                    {rule.skipHolidays ? ' skip court holidays, shift to next business day' : ' calendar days only'}
                  </div>
                </div>
                <div style={{ fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 8 }}>
                  Next 12 occurrences
                </div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 6 }}>
                  {occurrences.map((d, i) => (
                    <div key={i} style={{
                      padding: '10px 8px', textAlign: 'center', borderRadius: 6,
                      border: `1px solid ${T.color.border.light}`, background: T.color.bg.card,
                    }}>
                      <div style={{ fontSize: 10, color: T.color.text.tertiary, fontFamily: T.font.mono, textTransform: 'uppercase' }}>
                        {d.toLocaleDateString('en-US', { month: 'short' })}
                      </div>
                      <div className="arb-num" style={{ fontSize: 18, fontWeight: 700, color: T.color.text.primary }}>
                        {String(d.getDate()).padStart(2, '0')}
                      </div>
                      <div style={{ fontSize: 9, color: T.color.text.tertiary }}>
                        {d.toLocaleDateString('en-US', { weekday: 'short' })}
                      </div>
                    </div>
                  ))}
                </div>
              </>
            )}
          </Card>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #6 — Active Rule Stack
  // ═════════════════════════════════════════════════════════════════════════
  function CalRuleStack() {
    A.useTrack?.('cal.rules.stack', {}, []);
    const layers = [
      { id: 'frcp',      label: 'FRCP — Federal Base',         rules: 42, color: '#2563EB', overrides: 0,  critical: false },
      { id: 'circuit',   label: '2nd Circuit — Local',          rules: 18, color: '#7C3AED', overrides: 6,  critical: false },
      { id: 'district',  label: 'SDNY District — Local Rules',  rules: 24, color: '#059669', overrides: 9,  critical: false },
      { id: 'judge',     label: 'Judge Torres — Standing Order', rules: 8,  color: '#D97706', overrides: 11, critical: true  },
      { id: 'case',      label: 'Case Management Order',        rules: 5,  color: '#C23030', overrides: 4,  critical: true  },
    ];
    return (
      <div>
        <KpiRow>
          <Kpi label="Active layers" value={layers.length} />
          <Kpi label="Effective rules" value={layers.reduce((a, l) => a + l.rules, 0) - layers.reduce((a, l) => a + l.overrides, 0)} hint="net of overrides" />
          <Kpi label="Overrides" value={layers.reduce((a, l) => a + l.overrides, 0)} color="#D97706" />
          <Kpi label="Binding order" value="Case → Judge → District" hint="most specific wins" />
        </KpiRow>
        <Card title="Rule stack — Redstone v. Meridian · SDNY"
          right={<span style={{ fontSize: 10, color: T.color.text.tertiary }}>top layer wins</span>}>
          <div style={{ display: 'grid', gap: 8 }}>
            {layers.map((l, i) => (
              <div key={l.id} style={{
                display: 'grid', gridTemplateColumns: '24px 1fr 100px 120px 80px',
                alignItems: 'center', gap: 12,
                padding: '10px 14px', borderRadius: 8,
                borderLeft: `4px solid ${l.color}`,
                background: l.color + '08',
                border: `1px solid ${l.color}22`,
              }}>
                <span className="arb-num" style={{ fontSize: 14, fontWeight: 700, color: l.color }}>{i + 1}</span>
                <div>
                  <div style={{ fontSize: 13, fontWeight: 600, color: T.color.text.primary }}>{l.label}</div>
                  <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>
                    {l.critical ? 'case-specific — supersedes all above' : i === 0 ? 'foundational baseline' : `overrides ${l.overrides} rule${l.overrides === 1 ? '' : 's'} from layers above`}
                  </div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: T.color.text.tertiary }}>rules</div>
                  <div className="arb-num" style={{ fontSize: 15, fontWeight: 700, color: l.color }}>{l.rules}</div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: T.color.text.tertiary }}>overrides</div>
                  <div className="arb-num" style={{ fontSize: 15, fontWeight: 700, color: l.overrides ? '#D97706' : T.color.text.tertiary }}>{l.overrides}</div>
                </div>
                <button style={{
                  padding: '4px 10px', fontSize: 10, border: `1px solid ${l.color}55`,
                  background: 'transparent', color: l.color, borderRadius: 5, cursor: 'pointer',
                }}>inspect</button>
              </div>
            ))}
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #7 — Rule Diff (cross-jurisdiction)
  // ═════════════════════════════════════════════════════════════════════════
  function CalRuleDiff() {
    A.useTrack?.('cal.rules.diff', {}, []);
    const JURISDICTIONS = ['SDNY', 'CDCA', 'EDVA', 'NDTX', 'DDC'];
    const [left, setLeft] = useState('SDNY');
    const [right, setRight] = useState('EDVA');
    const items = [
      { event: 'Motion to Dismiss — opposition', SDNY: 14, CDCA: 21, EDVA: 11, NDTX: 14, DDC: 14, unit: 'days' },
      { event: 'Reply brief',                    SDNY: 7,  CDCA: 14, EDVA: 6,  NDTX: 7,  DDC: 7,  unit: 'days' },
      { event: 'Summary Judgment — opposition',  SDNY: 28, CDCA: 21, EDVA: 21, NDTX: 21, DDC: 21, unit: 'days' },
      { event: 'Discovery — interrogatories',    SDNY: 30, CDCA: 30, EDVA: 21, NDTX: 30, DDC: 30, unit: 'days' },
      { event: 'Expert disclosures (initial)',   SDNY: 90, CDCA: 90, EDVA: 75, NDTX: 90, DDC: 90, unit: 'days' },
      { event: 'Daubert deadline',               SDNY: 60, CDCA: 45, EDVA: 45, NDTX: 60, DDC: 60, unit: 'days' },
      { event: 'Pretrial conference — filings',  SDNY: 14, CDCA: 21, EDVA: 7,  NDTX: 14, DDC: 10, unit: 'days' },
      { event: 'Motion in limine — opposition',  SDNY: 7,  CDCA: 14, EDVA: 7,  NDTX: 7,  DDC: 7,  unit: 'days' },
      { event: 'Notice of appeal (civil)',       SDNY: 30, CDCA: 30, EDVA: 30, NDTX: 30, DDC: 30, unit: 'days' },
    ];
    const differ = items.filter(r => r[left] !== r[right]);
    return (
      <div>
        <KpiRow>
          <Kpi label="Deadlines compared" value={items.length} />
          <Kpi label="Different between" value={differ.length} color={differ.length ? '#D97706' : '#059669'} />
          <Kpi label={`${left} tighter`} value={differ.filter(r => r[left] < r[right]).length} hint="fewer days to respond" />
          <Kpi label={`${right} tighter`} value={differ.filter(r => r[right] < r[left]).length} hint="fewer days to respond" />
        </KpiRow>
        <Card title="Jurisdiction diff"
          right={<div style={{ display: 'flex', gap: 6 }}>
            <select value={left} onChange={e => setLeft(e.target.value)} className="arb-input" style={{ padding: '4px 8px', fontSize: 11 }}>
              {JURISDICTIONS.map(j => <option key={j}>{j}</option>)}
            </select>
            <span style={{ fontSize: 10, color: T.color.text.tertiary, padding: '6px 4px' }}>vs</span>
            <select value={right} onChange={e => setRight(e.target.value)} className="arb-input" style={{ padding: '4px 8px', fontSize: 11 }}>
              {JURISDICTIONS.map(j => <option key={j}>{j}</option>)}
            </select>
          </div>}>
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead>
              <tr style={{ background: T.color.bg.secondary }}>
                <th style={{ textAlign: 'left', padding: '8px 12px', fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em' }}>Event</th>
                <th style={{ textAlign: 'right', padding: '8px 12px', fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em', width: 100 }}>{left}</th>
                <th style={{ textAlign: 'right', padding: '8px 12px', fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em', width: 100 }}>{right}</th>
                <th style={{ textAlign: 'right', padding: '8px 12px', fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em', width: 80 }}>Δ</th>
              </tr>
            </thead>
            <tbody>{items.map(r => {
              const l = r[left], rr = r[right], delta = rr - l;
              const sameLR = l === rr;
              return (
                <tr key={r.event} style={{ background: sameLR ? 'transparent' : '#D9770608', borderBottom: `1px solid ${T.color.border.light}` }}>
                  <td style={{ padding: '8px 12px', fontSize: 12, color: T.color.text.primary }}>{r.event}</td>
                  <td className="arb-num" style={{ padding: '8px 12px', fontSize: 12, textAlign: 'right', color: sameLR ? T.color.text.secondary : (l < rr ? '#C23030' : '#059669'), fontWeight: 600 }}>{l}d</td>
                  <td className="arb-num" style={{ padding: '8px 12px', fontSize: 12, textAlign: 'right', color: sameLR ? T.color.text.secondary : (rr < l ? '#C23030' : '#059669'), fontWeight: 600 }}>{rr}d</td>
                  <td className="arb-num" style={{ padding: '8px 12px', fontSize: 12, textAlign: 'right', color: sameLR ? T.color.text.tertiary : '#D97706', fontWeight: 700 }}>{sameLR ? '·' : (delta > 0 ? '+' : '') + delta + 'd'}</td>
                </tr>
              );
            })}</tbody>
          </table>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #8 — Cascade Preview (trigger → downstream)
  // ═════════════════════════════════════════════════════════════════════════
  function CalCascadePreview() {
    A.useTrack?.('cal.rules.cascade.preview', {}, []);
    const triggers = [
      { id: 'complaint', label: 'Filing of Complaint', date: '2026-04-25' },
      { id: 'answer',    label: 'Filing of Answer',    date: '2026-05-15' },
      { id: 'sched',     label: 'Scheduling Order',    date: '2026-06-01' },
      { id: 'close',     label: 'Discovery Close',     date: '2026-12-15' },
    ];
    const [triggerId, setTriggerId] = useState(triggers[0].id);
    const trigger = triggers.find(t => t.id === triggerId);
    // Synthesize cascade
    const cascade = useMemo(() => {
      const base = new Date(trigger.date);
      const mk = (offset, label, priority = 'medium', citation = 'FRCP 12') => {
        const d = new Date(base); d.setDate(d.getDate() + offset);
        return { offset, label, priority, citation, date: d };
      };
      if (trigger.id === 'complaint') return [
        mk(0,   'Complaint filed',                 'critical','Caption'),
        mk(21,  'Answer / Rule 12 motion',         'critical','FRCP 12(a)'),
        mk(26,  'Service of process deadline',     'high',    'FRCP 4(m)'),
        mk(35,  'Rule 26(f) conference',           'high',    'FRCP 26(f)'),
        mk(45,  'Initial disclosures',             'high',    'FRCP 26(a)(1)'),
        mk(60,  'Scheduling order due',            'medium',  'FRCP 16(b)'),
        mk(90,  'Written discovery may begin',     'low',     'FRCP 33'),
        mk(120, '1st set of interrogatories due',  'medium',  'FRCP 33(b)'),
        mk(180, 'Expert disclosures (initial)',    'high',    'FRCP 26(a)(2)'),
        mk(270, 'Discovery close',                 'critical','CMO'),
        mk(300, 'Dispositive motion deadline',     'critical','CMO'),
      ];
      if (trigger.id === 'answer') return [
        mk(0,   'Answer filed',                    'critical','FRCP 12'),
        mk(14,  'Rule 26(f) conference window',    'high',    'FRCP 26(f)'),
        mk(21,  'Initial disclosures',             'high',    'FRCP 26(a)(1)'),
        mk(45,  'Scheduling conference',           'medium',  'FRCP 16'),
      ];
      if (trigger.id === 'sched') return [
        mk(0,   'Scheduling order entered',        'high',    'FRCP 16(b)'),
        mk(60,  'Amend pleadings deadline',        'medium',  'Order'),
        mk(120, 'Fact discovery close',            'critical','Order'),
        mk(150, 'Expert reports',                  'high',    'Order'),
        mk(180, 'Daubert motions',                 'critical','Order'),
      ];
      return [
        mk(0,   'Discovery closed',                'critical','Order'),
        mk(21,  'Dispositive motions',             'critical','Order'),
        mk(45,  'Motions in limine',               'high',    'Order'),
        mk(60,  'Pretrial order',                  'critical','FRCP 16(e)'),
        mk(90,  'Trial begins',                    'critical','Order'),
      ];
    }, [triggerId]);

    return (
      <div>
        <KpiRow>
          <Kpi label="Trigger" value={trigger.label.split(' ')[trigger.label.split(' ').length - 1]} />
          <Kpi label="Downstream deadlines" value={cascade.length} />
          <Kpi label="Critical" value={cascade.filter(c => c.priority === 'critical').length} color="#C23030" />
          <Kpi label="Total span" value={`${cascade[cascade.length - 1]?.offset || 0}d`} />
        </KpiRow>
        <Card title="Select trigger event" dense pad={false}>
          <div style={{ display: 'flex', gap: 6, padding: 10, overflowX: 'auto' }}>
            {triggers.map(t => (
              <Chip key={t.id} active={triggerId === t.id} onClick={() => setTriggerId(t.id)}>
                {t.label}
              </Chip>
            ))}
          </div>
        </Card>
        <Card title="Cascade preview — waterfall"
          right={<span style={{ fontSize: 10, color: T.color.text.tertiary }}>click any deadline to commit</span>}>
          <div style={{ position: 'relative', padding: '0 20px 0 100px' }}>
            {/* Spine */}
            <div style={{ position: 'absolute', left: 100, top: 10, bottom: 10, width: 2, background: T.color.border.medium }} />
            {cascade.map((c, i) => {
              const color = priorityColor(c.priority);
              return (
                <div key={i} style={{ position: 'relative', padding: '8px 0' }}>
                  <div style={{ position: 'absolute', left: -14, top: 14, width: 12, height: 12, borderRadius: '50%', background: color, boxShadow: `0 0 0 3px ${color}33, 0 0 0 4px var(--color-bg-card)` }} />
                  <div className="arb-num" style={{ position: 'absolute', left: -96, top: 10, fontSize: 11, fontWeight: 600, color, width: 72, textAlign: 'right' }}>
                    +{c.offset}d
                  </div>
                  <div className="arb-row" style={{
                    borderRadius: 6, padding: '8px 12px',
                    background: T.color.bg.card,
                    border: `1px solid ${T.color.border.light}`,
                    borderLeft: `3px solid ${color}`,
                    marginLeft: 10, cursor: 'pointer',
                  }}>
                    <div style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary }}>{c.label}</div>
                    <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>
                      <span className="arb-num">{fmtDateY(c.date)}</span> · {c.citation}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #10 — Motion Kanban (pipeline view)
  // ═════════════════════════════════════════════════════════════════════════
  function CalMotionsTab() {
    const motions = window.MOTIONS || [];
    A.useTrack?.('cal.practice.motions.kanban', {}, []);
    const stages = [
      { id: 'drafting',  label: 'Drafting',     color: '#2563EB', match: m => /draft/i.test(m.status) },
      { id: 'filed',     label: 'Filed',        color: '#7C3AED', match: m => /filed/i.test(m.status) && !m.oppDue },
      { id: 'opp',       label: 'Opp Pending',  color: '#D97706', match: m => m.oppDue && !m.replyDue },
      { id: 'reply',     label: 'Reply Due',    color: '#0891B2', match: m => m.replyDue && !m.argument },
      { id: 'arg',       label: 'Argument',     color: '#EA580C', match: m => m.argument && !m.ruling },
      { id: 'submitted', label: 'Submitted',    color: '#64748B', match: m => /submit/i.test(m.status) && !m.ruling },
      { id: 'ruled',     label: 'Ruled',        color: '#059669', match: m => /ruled/i.test(m.status) || m.ruling },
    ];
    const byStage = {};
    stages.forEach(s => byStage[s.id] = []);
    motions.forEach(m => {
      const stage = stages.find(s => s.match(m)) || stages[0];
      byStage[stage.id].push(m);
    });

    return (
      <div>
        <KpiRow cols="repeat(4,1fr)">
          <Kpi label="Active motions" value={motions.length} />
          <Kpi label="Awaiting opp" value={byStage.opp.length} color="#D97706" />
          <Kpi label="Reply due" value={byStage.reply.length} color="#0891B2" />
          <Kpi label="Ruled" value={byStage.ruled.length} color="#059669" />
        </KpiRow>
        <div style={{ overflowX: 'auto' }}>
          <div style={{
            display: 'grid',
            gridTemplateColumns: `repeat(${stages.length}, minmax(200px, 1fr))`,
            gap: 10, minWidth: stages.length * 220,
          }}>
            {stages.map(s => {
              const items = byStage[s.id];
              return (
                <div key={s.id} style={{
                  ...CARD, background: s.color + '04', borderColor: s.color + '22',
                  display: 'flex', flexDirection: 'column', minHeight: 360,
                }}>
                  <div style={{
                    padding: '10px 12px', borderBottom: `1px solid ${s.color}22`,
                    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                    background: s.color + '0A',
                  }}>
                    <span style={{ fontSize: 10.5, fontWeight: 700, color: s.color, textTransform: 'uppercase', letterSpacing: '0.08em' }}>{s.label}</span>
                    <span className="arb-num" style={{ fontSize: 12, fontWeight: 700, color: s.color }}>{items.length}</span>
                  </div>
                  <div style={{ flex: 1, padding: 6, overflowY: 'auto' }}>
                    {items.length === 0 && <div role="status" style={{ textAlign: 'center', fontSize: 10, color: T.color.text.tertiary, padding: 16, fontStyle: 'italic' }}>empty</div>}
                    {items.map(m => (
                      <div key={m.id} draggable
                        onClick={() => A.toast?.({ title: m.type, message: m.matter })}
                        className="arb-row"
                        style={{
                          ...CARD, padding: 10, marginBottom: 6, cursor: 'grab',
                          borderLeft: `3px solid ${s.color}`,
                        }}>
                        <div style={{ fontSize: 11.5, fontWeight: 600, color: T.color.text.primary, marginBottom: 4, lineHeight: 1.3 }}>{m.type}</div>
                        <div style={{ fontSize: 10, color: T.color.text.tertiary, marginBottom: 6 }}>{m.matter}</div>
                        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                          {m.oppDue && <span className="arb-num" style={{ fontSize: 9.5, color: T.color.text.secondary, background: T.color.bg.tertiary, padding: '1px 6px', borderRadius: 3 }}>opp {fmtDate(m.oppDue)}</span>}
                          {m.replyDue && <span className="arb-num" style={{ fontSize: 9.5, color: T.color.text.secondary, background: T.color.bg.tertiary, padding: '1px 6px', borderRadius: 3 }}>reply {fmtDate(m.replyDue)}</span>}
                          {m.argument && <span className="arb-num" style={{ fontSize: 9.5, color: '#EA580C', background: '#EA580C14', padding: '1px 6px', borderRadius: 3 }}>arg {fmtDate(m.argument)}</span>}
                        </div>
                        {m.ruling && <div style={{ fontSize: 10, color: '#059669', fontWeight: 600, marginTop: 6 }}>✓ {m.ruling}</div>}
                      </div>
                    ))}
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #11 — Service of Process (map-like + timeline)
  // ═════════════════════════════════════════════════════════════════════════
  function CalServiceTab() {
    const svcs = window.SERVICE_OF_PROCESS || [];
    A.useTrack?.('cal.practice.service', {}, []);
    const onTime = svcs.filter(s => s.status === 'on-time').length;
    const late = svcs.filter(s => s.status === 'late').length;
    const atRisk = svcs.filter(s => s.status === 'at-risk').length;
    const byMethod = svcs.reduce((a, s) => ((a[s.method] = (a[s.method] || 0) + 1), a), {});
    return (
      <div>
        <KpiRow>
          <Kpi label="Total served" value={svcs.length} />
          <Kpi label="On-time" value={onTime} color="#059669" />
          <Kpi label="At risk" value={atRisk} color="#D97706" />
          <Kpi label="Late" value={late} color="#C23030" />
          <Kpi label="Methods" value={Object.keys(byMethod).length} />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 280px', gap: 14 }}>
          <Card title="Service timeline" dense>
            {svcs.map(s => {
              const color = s.status === 'on-time' ? '#059669' : s.status === 'late' ? '#C23030' : s.status === 'at-risk' ? '#D97706' : T.color.text.tertiary;
              const servedD = new Date(s.served);
              const answerD = new Date(s.answerDue);
              const spanDays = Math.max(1, daysBetween(answerD, servedD));
              const progressDays = Math.max(0, Math.min(spanDays, daysBetween(TODAY, servedD)));
              const pct = (progressDays / spanDays) * 100;
              return (
                <div key={s.id} style={{
                  padding: '12px 14px', borderBottom: `1px solid ${T.color.border.light}`,
                  display: 'grid', gridTemplateColumns: '1fr 100px', gap: 12,
                }}>
                  <div>
                    <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 4 }}>
                      <span style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary }}>{s.matter}</span>
                      <Pill color={color}>{s.status}{s.daysLate > 0 ? ` +${s.daysLate}d` : ''}</Pill>
                    </div>
                    <div style={{ fontSize: 10, color: T.color.text.tertiary, marginBottom: 8 }}>
                      {s.party} · {s.method} · {s.server}
                    </div>
                    <div style={{ position: 'relative', height: 8, background: T.color.bg.tertiary, borderRadius: 4 }}>
                      <div style={{ width: pct + '%', height: '100%', borderRadius: 4, background: `linear-gradient(90deg, ${color}B3, ${color})` }} />
                    </div>
                    <div className="arb-num" style={{ display: 'flex', justifyContent: 'space-between', fontSize: 9.5, color: T.color.text.tertiary, marginTop: 4 }}>
                      <span>served {fmtDate(s.served)}</span>
                      <span>answer {fmtDate(s.answerDue)}</span>
                    </div>
                  </div>
                  <div style={{ textAlign: 'right' }}>
                    <div className="arb-num" style={{ fontSize: 18, fontWeight: 700, color }}>
                      {daysBetween(s.answerDue, TODAY)}<span style={{ fontSize: 10, fontWeight: 500 }}>d</span>
                    </div>
                    <div style={{ fontSize: 9, color: T.color.text.tertiary }}>remaining</div>
                  </div>
                </div>
              );
            })}
          </Card>
          <Card title="Methods" dense>
            {Object.entries(byMethod).sort((a, b) => b[1] - a[1]).map(([m, n]) => (
              <div key={m} style={{ padding: '10px 12px', borderBottom: `1px solid ${T.color.border.light}` }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
                  <span style={{ fontSize: 11, color: T.color.text.primary, fontWeight: 500 }}>{m}</span>
                  <span className="arb-num" style={{ fontSize: 11, fontWeight: 600, color: T.color.text.secondary }}>{n}</span>
                </div>
                <BarMeter value={n} max={Math.max(...Object.values(byMethod))} color="#2563EB" />
              </div>
            ))}
          </Card>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #12 — Workload Heatmap (attorney × week)
  // ═════════════════════════════════════════════════════════════════════════
  function CalWorkloadHeatmap() {
    const attorneys = window.ATTORNEYS || [];
    const dl = window.DOCKET_DEADLINES || [];
    A.useTrack?.('cal.resources.workload', {}, []);
    // Build 12-week matrix
    const weeks = Array.from({ length: 12 }, (_, i) => {
      const start = new Date(TODAY); start.setDate(start.getDate() + i * 7);
      return start;
    });
    const cellLoad = (att, week) => {
      const weekEnd = new Date(week); weekEnd.setDate(weekEnd.getDate() + 7);
      return dl.filter(d => d.assignee === att.name).filter(d => {
        const dd = new Date(d.date);
        return dd >= week && dd < weekEnd;
      }).reduce((a, d) => a + (d.priority === 'critical' ? 4 : d.priority === 'high' ? 2 : 1), 0);
    };
    const max = Math.max(1, ...attorneys.flatMap(a => weeks.map(w => cellLoad(a, w))));
    const hotCells = attorneys.flatMap(a => weeks.map(w => ({ a, w, v: cellLoad(a, w) }))).filter(c => c.v >= max * 0.7).length;

    const heatColor = (v) => {
      if (v === 0) return T.color.bg.secondary;
      const t = v / max;
      if (t < 0.33) return '#2563EB'  + Math.round(t * 3 * 200).toString(16).padStart(2, '0');
      if (t < 0.66) return '#D97706'  + Math.round((t - 0.33) * 3 * 200 + 55).toString(16).padStart(2, '0');
      return '#C23030'  + Math.round((t - 0.66) * 3 * 200 + 55).toString(16).padStart(2, '0');
    };

    return (
      <div>
        <KpiRow>
          <Kpi label="Attorneys tracked" value={attorneys.length} />
          <Kpi label="Forecast window" value="12 weeks" />
          <Kpi label="Hot cells ≥ 70%" value={hotCells} color={hotCells ? '#C23030' : '#059669'} hint="concentration risk" />
          <Kpi label="Peak load" value={max} color="#C23030" hint="weighted deadline-points" />
        </KpiRow>
        <Card title="Workload heat · attorney × week"
          right={<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
            <span style={{ fontSize: 9.5, color: T.color.text.tertiary }}>low</span>
            <div style={{ display: 'flex', gap: 0 }}>
              {[0.15, 0.33, 0.5, 0.7, 0.9].map(t => (
                <div key={t} style={{ width: 16, height: 10, background: heatColor(t * max) }} />
              ))}
            </div>
            <span style={{ fontSize: 9.5, color: T.color.text.tertiary }}>high</span>
          </div>} pad={false}>
          <div style={{ overflowX: 'auto' }}>
            <table style={{ borderCollapse: 'separate', borderSpacing: 4, padding: 12 }}>
              <thead>
                <tr>
                  <th style={{ padding: '4px 10px', textAlign: 'left', fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.08em' }}>Attorney</th>
                  {weeks.map((w, i) => (
                    <th key={i} style={{ padding: '4px 0', fontSize: 9, fontFamily: T.font.mono, color: T.color.text.tertiary, textAlign: 'center', minWidth: 38 }}>
                      {fmtDate(w)}
                    </th>
                  ))}
                  <th style={{ padding: '4px 8px', fontSize: 10, color: T.color.text.tertiary, textAlign: 'right' }}>Total</th>
                </tr>
              </thead>
              <tbody>
                {attorneys.map(a => {
                  const row = weeks.map(w => cellLoad(a, w));
                  const total = row.reduce((s, v) => s + v, 0);
                  return (
                    <tr key={a.id}>
                      <td style={{ padding: '3px 10px', fontSize: 11, fontWeight: 600, color: T.color.text.primary, whiteSpace: 'nowrap' }}>
                        <span style={{ width: 8, height: 8, borderRadius: '50%', background: a.color, display: 'inline-block', marginRight: 6 }} />
                        {a.name}
                      </td>
                      {row.map((v, i) => (
                        <td key={i} title={`${a.name} · week of ${fmtDate(weeks[i])} — load ${v}`}
                          style={{
                            width: 38, height: 28,
                            background: heatColor(v),
                            borderRadius: 4, textAlign: 'center',
                            fontSize: 10, color: v > max * 0.5 ? '#fff' : T.color.text.primary,
                            fontFamily: T.font.mono, fontWeight: 600,
                            cursor: 'pointer',
                            transition: 'transform 140ms',
                          }}
                          onMouseEnter={e => e.currentTarget.style.transform = 'scale(1.12)'}
                          onMouseLeave={e => e.currentTarget.style.transform = 'none'}>
                          {v || ''}
                        </td>
                      ))}
                      <td className="arb-num" style={{ padding: '3px 8px', fontSize: 11, fontWeight: 700, color: T.color.text.primary, textAlign: 'right' }}>{total}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #13 — Conflicts (overlap visualization)
  // ═════════════════════════════════════════════════════════════════════════
  function CalConflicts() {
    const attorneys = window.ATTORNEYS || [];
    const conflicts = attorneys.flatMap(a => (a.conflicts || []).map(c => ({ attorney: a, desc: c })));
    A.useTrack?.('cal.resources.conflicts', {}, []);
    return (
      <div>
        <KpiRow>
          <Kpi label="Open conflicts" value={conflicts.length} color={conflicts.length ? '#C23030' : '#059669'} />
          <Kpi label="Attorneys affected" value={attorneys.filter(a => a.conflicts?.length).length} />
          <Kpi label="Resolution SLA" value="48h" hint="internal policy" />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <Card title="Active conflicts" dense>
            {conflicts.length === 0 && (
              <div role="status" style={{ padding: 24, textAlign: 'center', color: T.color.text.tertiary, fontSize: 12 }}>
                All clear — no conflicts on the calendar.
              </div>
            )}
            {conflicts.map((c, i) => (
              <div key={i} style={{
                padding: '10px 12px', borderBottom: `1px solid ${T.color.border.light}`,
                display: 'flex', alignItems: 'center', gap: 10,
              }}>
                <span style={{ width: 28, height: 28, borderRadius: '50%', background: c.attorney.color, color: '#fff', fontSize: 10, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>{c.attorney.initials}</span>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 11.5, fontWeight: 600, color: T.color.text.primary }}>{c.attorney.name}</div>
                  <div style={{ fontSize: 10, color: '#C23030', marginTop: 2 }}>{c.desc}</div>
                </div>
                <button style={{ ...cal.filterBtn, fontSize: 10 }}>resolve</button>
              </div>
            ))}
          </Card>
          <Card title="Resolution playbook" dense>
            {[
              { step: '1', title: 'Reassign coverage',  body: 'Pick a non-conflicted attorney from the bench.' },
              { step: '2', title: 'Shift the deadline', body: 'Request extension or run cascade reschedule.' },
              { step: '3', title: 'Delegate to paralegal', body: 'For non-substantive appearances.' },
              { step: '4', title: 'Document the waiver', body: 'Client consent memo on file — Compliance required.' },
            ].map(s => (
              <div key={s.step} style={{ display: 'grid', gridTemplateColumns: '32px 1fr', gap: 10, padding: '10px 12px', borderBottom: `1px solid ${T.color.border.light}` }}>
                <span className="arb-num" style={{ fontSize: 18, fontWeight: 700, color: '#2563EB' }}>{s.step}</span>
                <div>
                  <div style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary }}>{s.title}</div>
                  <div style={{ fontSize: 10.5, color: T.color.text.tertiary, marginTop: 2 }}>{s.body}</div>
                </div>
              </div>
            ))}
          </Card>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #14 — Capacity Forecast (per-attorney 90d curve)
  // ═════════════════════════════════════════════════════════════════════════
  function CalCapacityForecast() {
    const attorneys = window.ATTORNEYS || [];
    A.useTrack?.('cal.resources.forecast', {}, []);
    // Synthesize 12-week capacity curve per attorney
    const weeks = 12;
    const curves = attorneys.map(a => {
      const base = 100 - a.capacity;
      const pts = Array.from({ length: weeks }, (_, i) => {
        const seed = (a.id.length * (i + 1)) % 7;
        return Math.min(140, Math.max(10, base + seed * 4 - (i % 3) * 6 + (i > 8 ? 8 : 0)));
      });
      const peak = Math.max(...pts);
      const overweeks = pts.filter(p => p > 100).length;
      return { a, pts, peak, overweeks };
    });
    const overUtilized = curves.filter(c => c.peak > 100).length;

    return (
      <div>
        <KpiRow>
          <Kpi label="Attorneys" value={attorneys.length} />
          <Kpi label="Over-utilized" value={overUtilized} color={overUtilized ? '#C23030' : '#059669'} hint="peak > 100%" />
          <Kpi label="Window" value="12w" />
          <Kpi label="Avg utilization" value={Math.round(curves.reduce((s, c) => s + c.pts.reduce((a, b) => a + b, 0) / weeks, 0) / curves.length) + '%'} />
        </KpiRow>
        <Card title="Capacity curve — next 12 weeks">
          <div style={{ display: 'grid', gap: 10 }}>
            {curves.map(({ a, pts, peak, overweeks }) => {
              const color = peak > 100 ? '#C23030' : peak > 85 ? '#D97706' : '#059669';
              return (
                <div key={a.id} style={{
                  display: 'grid', gridTemplateColumns: '180px 1fr 140px',
                  alignItems: 'center', gap: 12, padding: '10px 12px',
                  borderRadius: 8, background: T.color.bg.card,
                  border: `1px solid ${T.color.border.light}`,
                }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <span style={{ width: 24, height: 24, borderRadius: '50%', background: a.color, color: '#fff', fontSize: 10, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>{a.initials}</span>
                    <div>
                      <div style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary }}>{a.name}</div>
                      <div style={{ fontSize: 10, color: T.color.text.tertiary }}>{a.role}</div>
                    </div>
                  </div>
                  <div style={{ position: 'relative', height: 40 }}>
                    <svg width="100%" height="40" viewBox="0 0 240 40" preserveAspectRatio="none" aria-hidden="true">
                      {/* 100% threshold line */}
                      <line x1="0" y1={40 - (100 / 140) * 40} x2="240" y2={40 - (100 / 140) * 40} stroke="#C23030" strokeWidth="1" strokeDasharray="3 3" opacity="0.4" />
                      {/* area */}
                      <path d={`M0,40 ${pts.map((p, i) => `L${(i / (weeks - 1)) * 240},${40 - (p / 140) * 40}`).join(' ')} L240,40 Z`} fill={color} opacity="0.18" />
                      {/* line */}
                      <path d={`M${pts.map((p, i) => `${(i / (weeks - 1)) * 240},${40 - (p / 140) * 40}`).join(' L')}`} fill="none" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
                      {/* points */}
                      {pts.map((p, i) => (
                        <circle key={i} cx={(i / (weeks - 1)) * 240} cy={40 - (p / 140) * 40} r={p > 100 ? 2.5 : 1.5} fill={p > 100 ? '#C23030' : color} />
                      ))}
                    </svg>
                  </div>
                  <div style={{ textAlign: 'right' }}>
                    <div className="arb-num" style={{ fontSize: 16, fontWeight: 700, color }}>
                      {peak}%<span style={{ fontSize: 9, fontWeight: 500, color: T.color.text.tertiary, marginLeft: 4 }}>peak</span>
                    </div>
                    <div className="arb-num" style={{ fontSize: 10, color: overweeks ? '#C23030' : T.color.text.tertiary }}>
                      {overweeks} weeks over
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #15 — Defensibility Score
  // ═════════════════════════════════════════════════════════════════════════
  function CalDefensibilityAudit() {
    A.useTrack?.('cal.compliance.defensibility', {}, []);
    const factors = [
      { id: 'rule',  label: 'Rule-citation coverage',  score: 92, weight: 20, evidence: '42 of 46 deadlines cite FRCP/local rule' },
      { id: 'sync',  label: 'Docket-sync freshness',    score: 78, weight: 15, evidence: 'Last PACER sync: 11h ago' },
      { id: 'conf',  label: 'Conflicts resolved',       score: 100,weight: 15, evidence: 'No open conflicts' },
      { id: 'memo',  label: 'Bench memo on file',       score: 60, weight: 10, evidence: '3 of 5 hearings have memo' },
      { id: 'custd', label: 'Chain of custody',         score: 88, weight: 15, evidence: 'All productions logged' },
      { id: 'signs', label: 'Partner signoffs',         score: 75, weight: 15, evidence: '2 filings awaiting 2nd reviewer' },
      { id: 'audit', label: 'Audit trail integrity',    score: 95, weight: 10, evidence: 'Immutable log — hash verified' },
    ];
    const total = Math.round(factors.reduce((s, f) => s + f.score * f.weight / 100, 0));
    const tier = total >= 90 ? { label: 'AUDIT-READY', color: '#059669' } :
                 total >= 75 ? { label: 'ACCEPTABLE',  color: '#2563EB' } :
                 total >= 60 ? { label: 'ATTENTION',   color: '#D97706' } :
                               { label: 'CRITICAL',    color: '#C23030' };
    return (
      <div>
        <div style={{ display: 'grid', gridTemplateColumns: '280px 1fr', gap: 14 }}>
          <div style={{ ...CARD, padding: 20, textAlign: 'center', background: `linear-gradient(180deg, ${tier.color}0A 0%, transparent 100%)` }}>
            <div style={{ fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.1em' }}>Defensibility</div>
            <div className="arb-num" style={{ fontSize: 72, fontWeight: 700, color: tier.color, letterSpacing: '-0.04em', lineHeight: 1 }}>{total}</div>
            <div style={{ fontSize: 12, color: T.color.text.tertiary, marginTop: -2 }}>/ 100</div>
            <div style={{ marginTop: 16, padding: '6px 14px', display: 'inline-block', borderRadius: 20, background: tier.color, color: '#fff', fontSize: 11, fontWeight: 700, letterSpacing: '0.06em' }}>{tier.label}</div>
            <div style={{ fontSize: 10.5, color: T.color.text.tertiary, marginTop: 12, lineHeight: 1.5 }}>
              Weighted across 7 factors.<br/>
              Malpractice-post-mortem aligned.
            </div>
          </div>
          <Card title="Factor breakdown" dense
            right={<span style={{ fontSize: 10, color: T.color.text.tertiary }}>click to view evidence</span>}>
            {factors.map(f => {
              const c = f.score >= 90 ? '#059669' : f.score >= 75 ? '#2563EB' : f.score >= 60 ? '#D97706' : '#C23030';
              return (
                <div key={f.id} style={{
                  display: 'grid', gridTemplateColumns: '1fr 80px 80px 20px',
                  gap: 12, alignItems: 'center', padding: '12px 14px',
                  borderBottom: `1px solid ${T.color.border.light}`, cursor: 'pointer',
                }} className="arb-row">
                  <div>
                    <div style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary }}>{f.label}</div>
                    <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>{f.evidence}</div>
                  </div>
                  <div>
                    <BarMeter value={f.score} max={100} color={c} />
                  </div>
                  <div className="arb-num" style={{ textAlign: 'right', fontSize: 14, fontWeight: 700, color: c }}>{f.score}</div>
                  <div style={{ fontSize: 9, color: T.color.text.tertiary, textAlign: 'right' }}>×{f.weight}</div>
                </div>
              );
            })}
          </Card>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #16 — SOL Burn-down Timeline
  // ═════════════════════════════════════════════════════════════════════════
  function CalSOLDashboard() {
    const sol = (window.SOL_TRACKER || []).slice().sort((a, b) => a.daysRemaining - b.daysRemaining);
    A.useTrack?.('cal.compliance.sol', {}, []);
    const urgent = sol.filter(s => s.status === 'Urgent').length;
    const maxDays = Math.max(...sol.map(s => s.daysRemaining), 365);
    return (
      <div>
        <KpiRow>
          <Kpi label="Tracked claims" value={sol.length} />
          <Kpi label="Urgent" value={urgent} color={urgent ? '#C23030' : '#059669'} hint="< 365 days" />
          <Kpi label="Nearest expiry" value={sol[0] ? `${sol[0].daysRemaining}d` : '—'} color={sol[0] && sol[0].daysRemaining < 180 ? '#C23030' : '#D97706'} hint={sol[0]?.matter} />
          <Kpi label="Coverage horizon" value={`${Math.round(maxDays / 365 * 10) / 10}y`} />
        </KpiRow>
        <Card title="SOL burn-down — days remaining per claim"
          right={<span style={{ fontSize: 10, color: T.color.text.tertiary }}>red below 180d · amber below 365d</span>}>
          <div style={{ display: 'grid', gap: 8 }}>
            {sol.map(s => {
              const c = s.daysRemaining < 180 ? '#C23030' : s.daysRemaining < 365 ? '#D97706' : '#059669';
              const pct = 100 - Math.min(100, (s.daysRemaining / maxDays) * 100);
              return (
                <div key={s.id || s.matter} style={{
                  display: 'grid', gridTemplateColumns: '1fr 80px',
                  alignItems: 'center', gap: 12, padding: '8px 12px',
                  borderRadius: 6, border: `1px solid ${T.color.border.light}`,
                  background: T.color.bg.card,
                }}>
                  <div>
                    <div style={{ display: 'flex', gap: 8, alignItems: 'baseline', marginBottom: 4 }}>
                      <span style={{ fontSize: 12, fontWeight: 600, color: T.color.text.primary }}>{s.matter}</span>
                      <span style={{ fontSize: 10, color: T.color.text.tertiary }}>{s.claim}</span>
                      <span style={{ marginLeft: 'auto' }}><Pill color={c}>{s.status}</Pill></span>
                    </div>
                    <div style={{ position: 'relative', height: 10, background: T.color.bg.tertiary, borderRadius: 5, overflow: 'hidden' }}>
                      <div style={{
                        width: pct + '%', height: '100%',
                        background: `linear-gradient(90deg, ${c}99, ${c})`,
                        borderRadius: 5,
                        boxShadow: s.daysRemaining < 180 ? `0 0 8px ${c}88` : 'none',
                      }} />
                      {/* 365d marker */}
                      <div style={{ position: 'absolute', left: (1 - 365 / maxDays) * 100 + '%', top: -1, bottom: -1, width: 1, background: '#D97706', opacity: 0.6 }} />
                      {/* 180d marker */}
                      <div style={{ position: 'absolute', left: (1 - 180 / maxDays) * 100 + '%', top: -1, bottom: -1, width: 1, background: '#C23030', opacity: 0.6 }} />
                    </div>
                    <div className="arb-num" style={{ fontSize: 9.5, color: T.color.text.tertiary, marginTop: 4, display: 'flex', justifyContent: 'space-between' }}>
                      <span>{s.sol}</span>
                      <span>expires {s.expires}</span>
                    </div>
                  </div>
                  <div style={{ textAlign: 'right' }}>
                    <div className="arb-num" style={{ fontSize: 18, fontWeight: 700, color: c, letterSpacing: '-0.02em' }}>
                      {s.daysRemaining}<span style={{ fontSize: 10, fontWeight: 500 }}>d</span>
                    </div>
                    <div style={{ fontSize: 9, color: T.color.text.tertiary }}>remaining</div>
                  </div>
                </div>
              );
            })}
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #17 — Runbook Prep Checklists
  // ═════════════════════════════════════════════════════════════════════════
  function CalPrepChecklists() {
    const data = window.PREP_CHECKLISTS || [];
    const [selected, setSelected] = useState(data[0]?.id);
    const [done, setDone] = useState(new Set());
    const sel = data.find(p => p.id === selected) || data[0];
    A.useTrack?.('cal.prep.runbook', {}, []);
    const toggle = (k) => {
      setDone(prev => { const s = new Set(prev); s.has(k) ? s.delete(k) : s.add(k); return s; });
    };
    const completedCount = sel ? (sel.items || []).filter((_, i) => done.has(`${sel.id}-${i}`)).length : 0;
    const totalCount = sel ? (sel.items || []).length : 0;
    const pct = totalCount ? Math.round(completedCount / totalCount * 100) : 0;
    return (
      <div>
        <KpiRow>
          <Kpi label="Runbooks" value={data.length} />
          <Kpi label="Active" value={sel ? 1 : 0} hint={sel?.event} />
          <Kpi label="Progress" value={`${pct}%`} color={pct === 100 ? '#059669' : pct >= 50 ? '#2563EB' : '#D97706'} />
          <Kpi label="Items remaining" value={totalCount - completedCount} />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 14 }}>
          <Card title="Runbooks" dense>
            {data.map(p => (
              <div key={p.id} onClick={() => setSelected(p.id)}
                className="arb-row"
                style={{
                  padding: '10px 12px', borderRadius: 6, cursor: 'pointer',
                  background: selected === p.id ? '#2563EB11' : 'transparent',
                  border: `1px solid ${selected === p.id ? '#2563EB55' : T.color.border.light}`,
                  marginBottom: 4,
                }}>
                <div style={{ fontSize: 11.5, fontWeight: 600, color: T.color.text.primary }}>{p.event}</div>
                <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>{p.matter} · {(p.items || []).length} items</div>
              </div>
            ))}
          </Card>
          <Card title={sel ? `${sel.event} · ${sel.matter}` : 'Select a runbook'} dense
            right={<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
              <div style={{ width: 140 }}><BarMeter value={pct} max={100} color="#2563EB" /></div>
              <span className="arb-num" style={{ fontSize: 11, color: T.color.text.secondary }}>{pct}%</span>
              <button style={{ ...cal.filterBtn, fontSize: 10 }}>generate binder</button>
            </div>}>
            {sel && (sel.items || []).map((item, i) => {
              const k = `${sel.id}-${i}`;
              const isDone = done.has(k);
              return (
                <div key={i}
                  onClick={() => toggle(k)}
                  className="arb-row"
                  style={{
                    display: 'grid', gridTemplateColumns: '24px 1fr 100px',
                    gap: 12, alignItems: 'center',
                    padding: '10px 14px', borderBottom: `1px solid ${T.color.border.light}`,
                    cursor: 'pointer', opacity: isDone ? 0.55 : 1,
                  }}>
                  <span style={{
                    width: 18, height: 18, borderRadius: 4,
                    border: `2px solid ${isDone ? '#059669' : T.color.border.medium}`,
                    background: isDone ? '#059669' : 'transparent',
                    display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                    color: '#fff', fontSize: 10, fontWeight: 700,
                    transition: 'all 140ms',
                  }}>{isDone ? '✓' : ''}</span>
                  <div>
                    <div style={{ fontSize: 12, fontWeight: 500, color: T.color.text.primary, textDecoration: isDone ? 'line-through' : 'none' }}>
                      {typeof item === 'string' ? item : item.label}
                    </div>
                    {typeof item !== 'string' && item.owner && (
                      <div style={{ fontSize: 10, color: T.color.text.tertiary, marginTop: 2 }}>owner: {item.owner}</div>
                    )}
                  </div>
                  <div className="arb-num" style={{ fontSize: 10, color: T.color.text.tertiary, textAlign: 'right' }}>step {i + 1}/{sel.items.length}</div>
                </div>
              );
            })}
          </Card>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #18 — Hearing Binder (one-click artifact)
  // ═════════════════════════════════════════════════════════════════════════
  function CalHearingBinder() {
    A.useTrack?.('cal.prep.binder', {}, []);
    const [generating, setGenerating] = useState(false);
    const [generated, setGenerated] = useState(null);
    const sections = [
      { label: 'Caption & Appearance of counsel',         count: 1  },
      { label: 'Motion index with page-cites',            count: 12 },
      { label: 'Exhibit index (EXH-001 – EXH-049)',       count: 49 },
      { label: 'Witness scripts (direct + cross prep)',   count: 6  },
      { label: 'Key case cites — shepardized',            count: 18 },
      { label: 'Judge standing order — quick reference',  count: 1  },
      { label: 'CM/ECF filing checklist',                 count: 8  },
      { label: 'Timeline of relevant events',             count: 22 },
      { label: 'Proposed orders (draft)',                 count: 3  },
    ];
    const total = sections.reduce((s, x) => s + x.count, 0);
    const generate = () => {
      setGenerating(true);
      setTimeout(() => { setGenerating(false); setGenerated(new Date().toISOString()); A.toast?.({ kind:'active', title:'Binder generated', message:'Hearing binder · ' + total + ' pieces' }); }, 900);
    };
    return (
      <div>
        <KpiRow>
          <Kpi label="Sections" value={sections.length} />
          <Kpi label="Artifacts" value={total} />
          <Kpi label="Est. pages" value={total * 3} hint="avg 3pp/artifact" />
          <Kpi label="Last generated" value={generated ? new Date(generated).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) : '—'} />
        </KpiRow>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 280px', gap: 14 }}>
          <Card title="Binder contents — Redstone v. Meridian · Motion hearing 2026-05-12">
            <div style={{ display: 'grid', gap: 8 }}>
              {sections.map((s, i) => (
                <div key={i} style={{
                  display: 'grid', gridTemplateColumns: '32px 1fr 60px',
                  alignItems: 'center', gap: 12, padding: '10px 12px',
                  background: T.color.bg.card, borderRadius: 6,
                  border: `1px solid ${T.color.border.light}`,
                }}>
                  <span className="arb-num" style={{ fontSize: 14, fontWeight: 600, color: T.color.text.tertiary }}>{String(i + 1).padStart(2, '0')}</span>
                  <div style={{ fontSize: 12, color: T.color.text.primary, fontWeight: 500 }}>{s.label}</div>
                  <span className="arb-num" style={{ fontSize: 12, fontWeight: 700, color: '#2563EB', textAlign: 'right' }}>{s.count}</span>
                </div>
              ))}
            </div>
          </Card>
          <Card title="Generate">
            <button onClick={generate} disabled={generating}
              style={{
                width: '100%', padding: '12px',
                background: generating ? T.color.bg.tertiary :
                  `linear-gradient(180deg, #2563EB 0%, #1E40AF 100%)`,
                color: generating ? T.color.text.tertiary : '#fff',
                border: 'none', borderRadius: 8, cursor: generating ? 'wait' : 'pointer',
                fontSize: 13, fontWeight: 600, letterSpacing: '-0.005em',
                boxShadow: '0 1px 2px rgba(10,22,40,0.1), inset 0 1px 0 rgba(255,255,255,0.12)',
                fontFamily: T.font.family, transition: 'background 200ms',
              }}>
              {generating ? 'Generating…' : '✦ Generate binder'}
            </button>
            <div style={{ marginTop: 12, fontSize: 10.5, color: T.color.text.tertiary, lineHeight: 1.6 }}>
              Produces a single PDF with:
              <ul style={{ margin: '6px 0 0 16px', padding: 0 }}>
                <li>bookmarked sections</li>
                <li>hyperlinked cites</li>
                <li>sequential pagination</li>
                <li>cover sheet with matter KPIs</li>
              </ul>
            </div>
            {generated && (
              <div style={{ marginTop: 12, padding: '10px 12px', borderRadius: 6, background: '#05966910', border: '1px solid #05966944', fontSize: 11, color: '#059669' }}>
                ✓ Ready to download
                <div style={{ fontSize: 9.5, color: T.color.text.tertiary, marginTop: 4 }}>
                  <span className="arb-num">{new Date(generated).toLocaleTimeString()}</span> · v{Math.floor(Math.random() * 7) + 1}
                </div>
              </div>
            )}
          </Card>
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #19 — Analytics small multiples
  // ═════════════════════════════════════════════════════════════════════════
  function CalAnalytics() {
    const dl = window.DOCKET_DEADLINES || [];
    A.useTrack?.('cal.analytics.overview', {}, []);
    const multiples = [
      { label: 'Deadlines / week',     current: 23, delta: '+3',  points: [14, 16, 18, 15, 20, 22, 19, 23, 21, 24, 23, 23], color: '#2563EB' },
      { label: 'On-time %',            current: 94, delta: '+1',  points: [88, 89, 91, 90, 92, 93, 91, 93, 94, 93, 94, 94], color: '#059669' },
      { label: 'Missed',               current: 2,  delta: '0',   points: [3, 2, 4, 3, 2, 2, 3, 1, 2, 2, 2, 2], color: '#C23030' },
      { label: 'Extensions granted',   current: 6,  delta: '-2',  points: [10, 9, 8, 7, 9, 8, 7, 6, 6, 7, 6, 6], color: '#D97706' },
      { label: 'Avg attorney load',    current: 82, delta: '+4',  points: [74, 75, 76, 78, 77, 80, 79, 82, 81, 82, 82, 82], color: '#7C3AED' },
      { label: 'Budget burn %',        current: 68, delta: '+5',  points: [42, 48, 52, 55, 58, 60, 62, 64, 66, 67, 67, 68], color: '#EA580C' },
    ];
    return (
      <div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 14 }}>
          {multiples.map(m => (
            <div key={m.label} className="arb-elev-1"
              style={{
                padding: '14px 16px', borderRadius: 8, background: T.color.bg.card,
                transition: 'transform 160ms, box-shadow 160ms', cursor: 'pointer',
              }}
              onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-1px)'; e.currentTarget.style.boxShadow = '0 4px 12px rgba(10,22,40,0.10), 0 0 0 1px var(--color-border-medium)'; }}
              onMouseLeave={e => { e.currentTarget.style.transform = 'none'; e.currentTarget.style.boxShadow = ''; }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
                <span style={{ fontSize: 10, fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.1em' }}>{m.label}</span>
                <span className="arb-num" style={{ fontSize: 10, color: m.delta.startsWith('-') ? '#C23030' : m.delta.startsWith('+') ? '#059669' : T.color.text.tertiary, fontWeight: 600 }}>
                  {m.delta.startsWith('+') || m.delta.startsWith('-') ? m.delta : '±' + m.delta}
                </span>
              </div>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
                <span className="arb-num" style={{ fontSize: 28, fontWeight: 700, color: T.color.text.primary, letterSpacing: '-0.025em', lineHeight: 1 }}>{m.current}</span>
                <Sparkline points={m.points} color={m.color} w={120} h={32} />
              </div>
              <div className="arb-num" style={{ fontSize: 9.5, color: T.color.text.tertiary, marginTop: 6 }}>
                12-week trend · last 3mo
              </div>
            </div>
          ))}
        </div>
        <Card title="Distribution — priority × week"
          right={<span style={{ fontSize: 10, color: T.color.text.tertiary }}>stacked</span>}>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 4, height: 140, padding: '0 8px' }}>
            {Array.from({ length: 12 }, (_, i) => {
              const total = 12 + (i % 4) * 4 + (i % 7);
              const crit = Math.max(1, Math.round(total * 0.15));
              const hi   = Math.round(total * 0.25);
              const med  = Math.round(total * 0.4);
              const lo   = total - crit - hi - med;
              return (
                <div key={i} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2 }}>
                  <div style={{ width: '100%', display: 'flex', flexDirection: 'column-reverse', height: 110, borderRadius: 4, overflow: 'hidden' }}>
                    <div style={{ background: '#6E7D9E', flex: lo }} />
                    <div style={{ background: '#2563EB', flex: med }} />
                    <div style={{ background: '#D97706', flex: hi }} />
                    <div style={{ background: '#C23030', flex: crit }} />
                  </div>
                  <span className="arb-num" style={{ fontSize: 9, color: T.color.text.tertiary }}>W{i + 1}</span>
                </div>
              );
            })}
          </div>
          <div style={{ display: 'flex', gap: 16, marginTop: 10, fontSize: 10, color: T.color.text.tertiary }}>
            <span><span style={{ display: 'inline-block', width: 8, height: 8, background: '#C23030', borderRadius: 2, marginRight: 4 }} /> critical</span>
            <span><span style={{ display: 'inline-block', width: 8, height: 8, background: '#D97706', borderRadius: 2, marginRight: 4 }} /> high</span>
            <span><span style={{ display: 'inline-block', width: 8, height: 8, background: '#2563EB', borderRadius: 2, marginRight: 4 }} /> medium</span>
            <span><span style={{ display: 'inline-block', width: 8, height: 8, background: '#6E7D9E', borderRadius: 2, marginRight: 4 }} /> low</span>
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  #20 — Risk × Impact Matrix (partner view)
  // ═════════════════════════════════════════════════════════════════════════
  function CalRiskScore() {
    A.useTrack?.('cal.analytics.risk', {}, []);
    // Synthesize matter bubbles
    const matters = [
      { id: 'M1', name: 'Redstone v. Meridian',    daysToTrial: 120, riskScore: 78, ev: 14000000, phase: 'discovery' },
      { id: 'M2', name: 'Pacific Shipping',        daysToTrial: 240, riskScore: 42, ev: 5200000,  phase: 'pleadings' },
      { id: 'M3', name: 'Thornton Estate',         daysToTrial: 60,  riskScore: 62, ev: 2800000,  phase: 'trial-prep' },
      { id: 'M4', name: 'Blackwell IP',            daysToTrial: 180, riskScore: 55, ev: 8400000,  phase: 'discovery' },
      { id: 'M5', name: 'Chen v. Atlas',           daysToTrial: 90,  riskScore: 88, ev: 3100000,  phase: 'motions' },
      { id: 'M6', name: 'Sterling Pharma',         daysToTrial: 300, riskScore: 38, ev: 11200000, phase: 'discovery' },
      { id: 'M7', name: 'Harbor Point Dev',        daysToTrial: 30,  riskScore: 72, ev: 1800000,  phase: 'trial-prep' },
    ];
    const phaseColor = { pleadings: '#7C3AED', discovery: '#2563EB', motions: '#D97706', 'trial-prep': '#EA580C', trial: '#C23030' };
    const maxDays = 360;
    const maxEv = 15000000;
    const w = 560, h = 360, pad = 40;
    return (
      <div>
        <KpiRow>
          <Kpi label="Matters plotted" value={matters.length} />
          <Kpi label="Near trial (≤ 90d)" value={matters.filter(m => m.daysToTrial <= 90).length} color="#C23030" />
          <Kpi label="High risk (≥ 70)" value={matters.filter(m => m.riskScore >= 70).length} color="#D97706" />
          <Kpi label="Aggregate EV" value={'$' + (matters.reduce((s, m) => s + m.ev, 0) / 1e6).toFixed(1) + 'M'} />
        </KpiRow>
        <Card title="Risk × Time-to-trial · bubble = expected value"
          right={<div style={{ display: 'flex', gap: 8, fontSize: 10, color: T.color.text.tertiary }}>
            {Object.entries(phaseColor).map(([p, c]) => (
              <span key={p}><span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: '50%', background: c, marginRight: 4 }} />{p}</span>
            ))}
          </div>}>
          <div style={{ position: 'relative', width: w, height: h, margin: '0 auto' }}>
            <svg width={w} height={h} aria-label="Matter risk matrix">
              {/* Quadrant shading */}
              <rect x={pad} y={pad} width={(w - pad * 2) / 2} height={(h - pad * 2) / 2} fill="#C23030" opacity="0.03" />
              <rect x={pad + (w - pad * 2) / 2} y={pad} width={(w - pad * 2) / 2} height={(h - pad * 2) / 2} fill="#D97706" opacity="0.03" />
              {/* Axes */}
              <line x1={pad} y1={h - pad} x2={w - pad} y2={h - pad} stroke={T.color.border.medium} />
              <line x1={pad} y1={pad}     x2={pad}     y2={h - pad} stroke={T.color.border.medium} />
              {/* Gridlines */}
              {[25, 50, 75].map(v => (
                <line key={v} x1={pad} y1={h - pad - (v / 100) * (h - pad * 2)} x2={w - pad} y2={h - pad - (v / 100) * (h - pad * 2)} stroke={T.color.border.light} strokeDasharray="2 3" />
              ))}
              {/* Axis labels */}
              <text x={w / 2} y={h - 8} textAnchor="middle" fontSize="10" fill={T.color.text.tertiary}>days to trial →</text>
              <text x={12} y={h / 2} textAnchor="middle" fontSize="10" fill={T.color.text.tertiary} transform={`rotate(-90, 12, ${h / 2})`}>risk score →</text>
              {/* Axis ticks */}
              {[0, 90, 180, 270, 360].map(d => (
                <text key={d} x={pad + (d / maxDays) * (w - pad * 2)} y={h - pad + 14} textAnchor="middle" fontSize="9" fill={T.color.text.tertiary} fontFamily={T.font.mono}>{d}</text>
              ))}
              {[0, 25, 50, 75, 100].map(v => (
                <text key={v} x={pad - 6} y={h - pad - (v / 100) * (h - pad * 2) + 3} textAnchor="end" fontSize="9" fill={T.color.text.tertiary} fontFamily={T.font.mono}>{v}</text>
              ))}
              {/* Danger zone (near-term + high risk) label */}
              <text x={pad + 8} y={pad + 16} fontSize="10" fill="#C23030" fontWeight="700" letterSpacing="0.08em" style={{ textTransform: 'uppercase' }}>DANGER</text>
              {/* Bubbles */}
              {matters.map(m => {
                const cx = pad + (m.daysToTrial / maxDays) * (w - pad * 2);
                const cy = h - pad - (m.riskScore / 100) * (h - pad * 2);
                const r = 6 + Math.sqrt(m.ev / maxEv) * 20;
                const color = phaseColor[m.phase] || '#6E7D9E';
                return (
                  <g key={m.id}>
                    <circle cx={cx} cy={cy} r={r + 2} fill={color} opacity="0.15" />
                    <circle cx={cx} cy={cy} r={r} fill={color} opacity="0.5" />
                    <circle cx={cx} cy={cy} r={r} fill="none" stroke={color} strokeWidth="1.5" />
                    <text x={cx} y={cy + 3} textAnchor="middle" fontSize="9" fontWeight="700" fill="#fff" fontFamily={T.font.mono}>{m.id}</text>
                  </g>
                );
              })}
            </svg>
          </div>
          <div style={{ marginTop: 14, display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: 6 }}>
            {matters.map(m => (
              <div key={m.id} style={{
                padding: '8px 10px', borderRadius: 6, fontSize: 11,
                border: `1px solid ${T.color.border.light}`, background: T.color.bg.card,
                display: 'grid', gridTemplateColumns: '24px 1fr auto', gap: 8, alignItems: 'center',
              }}>
                <span className="arb-num" style={{ fontSize: 10, color: T.color.text.tertiary, fontWeight: 600 }}>{m.id}</span>
                <div>
                  <div style={{ fontSize: 11, fontWeight: 600, color: T.color.text.primary }}>{m.name}</div>
                  <div style={{ fontSize: 9.5, color: T.color.text.tertiary, marginTop: 2 }}>{m.phase} · {m.daysToTrial}d · risk {m.riskScore}</div>
                </div>
                <span className="arb-num" style={{ fontSize: 11, fontWeight: 700, color: T.color.text.primary }}>${(m.ev / 1e6).toFixed(1)}M</span>
              </div>
            ))}
          </div>
        </Card>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  Override hub composers with fresh sub-tab sets
  // ═════════════════════════════════════════════════════════════════════════
  function CalSubTabs({ tabs, active, onChange }) {
    return (
      <div style={{ display: 'flex', gap: 0, borderBottom: `1px solid ${T.color.border.light}`, marginBottom: 16, overflowX: 'auto' }}>
        {tabs.map(t => {
          const isActive = active === t.id;
          return (
            <button key={t.id} onClick={() => onChange(t.id)}
              className="arb-row"
              style={{
                padding: '9px 16px', fontSize: 11.5, fontWeight: isActive ? 600 : 500,
                color: isActive ? '#2563EB' : T.color.text.tertiary,
                cursor: 'pointer', border: 'none', background: 'none',
                borderBottom: isActive ? '2px solid #2563EB' : '2px solid transparent',
                fontFamily: T.font.family, whiteSpace: 'nowrap', marginBottom: -1,
                letterSpacing: '-0.005em',
              }}>
              {t.label}
              {t.count != null && <span className="arb-num" style={{ marginLeft: 6, fontSize: 10, color: T.color.text.tertiary, fontFamily: T.font.mono }}>{t.count}</span>}
            </button>
          );
        })}
      </div>
    );
  }
  window.CalSubTabs = CalSubTabs;

  function CalViewsHub() {
    const [sub, setSub] = useState('today');
    const tabs = [
      { id: 'today',    label: 'Today' },
      { id: 'unified',  label: 'Swimlanes' },
      { id: 'grid',     label: 'Calendar' },
      { id: 'gantt',    label: 'Gantt' },
      { id: 'chains',   label: 'Chains' },
    ];
    return (
      <div>
        <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
        {sub === 'today'   && <CalTodayMode />}
        {sub === 'unified' && <CalSwimlanes />}
        {sub === 'grid'    && window.CalGrid   && <window.CalGrid />}
        {sub === 'gantt'   && window.CalGantt  && <window.CalGantt />}
        {sub === 'chains'  && window.CalChains && <window.CalChains />}
      </div>
    );
  }

  function CalScheduleHub() {
    const [sub, setSub] = useState('assistant');
    const tabs = [
      { id: 'assistant', label: 'Scheduling Assistant' },
      { id: 'trials',    label: 'Trial Countdown' },
      { id: 'hearings',  label: 'Hearing Prep' },
      { id: 'witnesses', label: 'Witnesses' },
      { id: 'experts',   label: 'Expert Disclosures' },
    ];
    return (
      <div>
        <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
        {sub === 'assistant' && <CalSchedulingAssistant />}
        {sub === 'trials'    && window.CalTrialCountdown && <window.CalTrialCountdown />}
        {sub === 'hearings'  && window.CalHearingPrepTab && <window.CalHearingPrepTab />}
        {sub === 'witnesses' && window.CalWitnessMatrix && <window.CalWitnessMatrix />}
        {sub === 'experts'   && window.CalExpertDisclosureTab && <window.CalExpertDisclosureTab />}
      </div>
    );
  }

  function CalRulesHub() {
    const [sub, setSub] = useState('stack');
    const tabs = [
      { id: 'stack',    label: 'Active Stack' },
      { id: 'cascade',  label: 'Cascade Preview' },
      { id: 'diff',     label: 'Jurisdiction Diff' },
      { id: 'packs',    label: 'Rule Packs' },
      { id: 'holidays', label: 'Holidays' },
      { id: 'judges',   label: 'Judge Orders' },
    ];
    return (
      <div>
        <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
        {sub === 'stack'    && <CalRuleStack />}
        {sub === 'cascade'  && <CalCascadePreview />}
        {sub === 'diff'     && <CalRuleDiff />}
        {sub === 'packs'    && window.CalRulePackLibrary && <window.CalRulePackLibrary />}
        {sub === 'holidays' && window.CalHolidaysTab && <window.CalHolidaysTab />}
        {sub === 'judges'   && window.CalStandingOrdersTab && <window.CalStandingOrdersTab />}
      </div>
    );
  }

  function CalDocketHub({ onCascade }) {
    const [sub, setSub] = useState('motions');
    const tabs = [
      { id: 'motions',      label: 'Motion Pipeline' },
      { id: 'service',      label: 'Service' },
      { id: 'continuances', label: 'Continuances' },
      { id: 'pacer',        label: 'PACER Sync' },
      { id: 'cascade',      label: 'Cascade Runs' },
    ];
    return (
      <div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
          {sub === 'cascade' && <button onClick={onCascade} style={{ ...cal.filterBtn, ...cal.filterBtnActive, fontSize: 10 }}>+ Run cascade</button>}
        </div>
        {sub === 'motions'      && <CalMotionsTab />}
        {sub === 'service'      && <CalServiceTab />}
        {sub === 'continuances' && window.CalContinuancesTab && <window.CalContinuancesTab />}
        {sub === 'pacer'        && window.CalPacerTab && <window.CalPacerTab />}
        {sub === 'cascade'      && window.CalCascadeRunsTab && <window.CalCascadeRunsTab />}
      </div>
    );
  }

  function CalResourcesHub() {
    const [sub, setSub] = useState('heatmap');
    const tabs = [
      { id: 'heatmap',  label: 'Workload Heatmap' },
      { id: 'forecast', label: '90-day Forecast' },
      { id: 'roster',   label: 'Roster' },
      { id: 'conflicts',label: 'Conflicts' },
      { id: 'recurring',label: 'Recurring' },
    ];
    return (
      <div>
        <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
        {sub === 'heatmap'   && <CalWorkloadHeatmap />}
        {sub === 'forecast'  && <CalCapacityForecast />}
        {sub === 'roster'    && window.CalResources && <window.CalResources />}
        {sub === 'conflicts' && <CalConflicts />}
        {sub === 'recurring' && <CalRecurring />}
      </div>
    );
  }

  function CalComplianceHub() {
    const [sub, setSub] = useState('defensibility');
    const tabs = [
      { id: 'defensibility', label: 'Defensibility' },
      { id: 'sol',           label: 'SOL Burn-down' },
      { id: 'escalation',    label: 'Escalation' },
      { id: 'reports',       label: 'Client Reports' },
      { id: 'path',          label: 'Critical Path' },
    ];
    return (
      <div>
        <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
        {sub === 'defensibility' && <CalDefensibilityAudit />}
        {sub === 'sol'           && <CalSOLDashboard />}
        {sub === 'escalation'    && window.CalEscalationTab && <window.CalEscalationTab />}
        {sub === 'reports'       && window.CalClientReportsTab && <window.CalClientReportsTab />}
        {sub === 'path'          && window.CalCriticalPath && <window.CalCriticalPath />}
      </div>
    );
  }

  function CalPrepHub() {
    const [sub, setSub] = useState('binder');
    const tabs = [
      { id: 'binder',     label: 'Hearing Binder' },
      { id: 'checklists', label: 'Runbooks' },
      { id: 'calculator', label: 'Deadline Calc' },
      { id: 'alerts',     label: 'Alerts' },
    ];
    return (
      <div>
        <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
        {sub === 'binder'     && <CalHearingBinder />}
        {sub === 'checklists' && <CalPrepChecklists />}
        {sub === 'calculator' && window.CalCalculator && <window.CalCalculator />}
        {sub === 'alerts'     && window.CalNotifications && <window.CalNotifications />}
      </div>
    );
  }

  function CalAnalyticsHub() {
    const [sub, setSub] = useState('overview');
    const tabs = [
      { id: 'overview', label: 'Overview' },
      { id: 'matrix',   label: 'Risk Matrix' },
      { id: 'extras',   label: 'Milestones & Sync' },
    ];
    return (
      <div>
        <CalSubTabs tabs={tabs} active={sub} onChange={setSub} />
        {sub === 'overview' && <CalAnalytics />}
        {sub === 'matrix'   && <CalRiskScore />}
        {sub === 'extras'   && window.CalExtras && <window.CalExtras />}
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════════════
  //  Export
  // ═════════════════════════════════════════════════════════════════════════
  Object.assign(window, {
    // 20 enriched components
    CalSwimlanes, CalTodayMode, CalSchedulingAssistant, CalRecurring,
    CalRuleStack, CalRuleDiff, CalCascadePreview,
    CalMotionsTab, CalServiceTab, CalWorkloadHeatmap, CalConflicts, CalCapacityForecast,
    CalDefensibilityAudit, CalSOLDashboard, CalPrepChecklists, CalHearingBinder,
    CalAnalytics, CalRiskScore,
    // Hub overrides
    CalViewsHub, CalScheduleHub, CalRulesHub, CalDocketHub,
    CalResourcesHub, CalComplianceHub, CalPrepHub, CalAnalyticsHub,
  });
})();
