const { useState, useMemo, useEffect, useRef, useCallback } = React;
const T = window.ArbiterTokens;

// ── RULE BROWSER ──
const FAVORITES_KEY = 'arbiter.rb.favorites';
const RECENTS_KEY = 'arbiter.rb.recents';

function loadLS(key, fallback) {
  try { const v = JSON.parse(localStorage.getItem(key) || 'null'); return v || fallback; } catch { return fallback; }
}
function saveLS(key, v) { try { localStorage.setItem(key, JSON.stringify(v)); } catch {} }

function FRCPBrowser() {
  const db = window.FRCP_DATABASE;
  const rb = window.rb || {};
  const RD = window.RULEBOOK_DATA || {};
  const [search, setSearch] = useState('');
  const [titleFilter, setTitleFilter] = useState('All');
  const [deadlineOnly, setDeadlineOnly] = useState(false);
  const [expanded, setExpanded] = useState(null);
  const [categoryFilter, setCategoryFilter] = useState('All');
  const [favoritesOnly, setFavoritesOnly] = useState(false);
  const [favorites, setFavorites] = useState(() => loadLS(FAVORITES_KEY, []));
  const [recents, setRecents] = useState(() => loadLS(RECENTS_KEY, []));
  const [pinDialog, setPinDialog] = useState(null); // { ruleId }
  const [pinMatter, setPinMatter] = useState('M-2026-0042');
  const [pinReason, setPinReason] = useState('');
  const [flashMsg, setFlashMsg] = useState(null);
  const [compareId, setCompareId] = useState(null);
  const listRef = useRef(null);

  const categories = ['All', 'commencement', 'service', 'deadlines', 'pleadings', 'responsive', 'case-management', 'discovery', 'deposition', 'trial', 'motion', 'judgment', 'post-trial', 'remedies', 'settlement', 'general'];

  const toggleFavorite = (id) => {
    setFavorites(prev => {
      const next = prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id];
      saveLS(FAVORITES_KEY, next);
      return next;
    });
  };

  const pushRecent = (id) => {
    setRecents(prev => {
      const next = [id, ...prev.filter(x => x !== id)].slice(0, 8);
      saveLS(RECENTS_KEY, next);
      return next;
    });
  };

  const flash = (msg) => { setFlashMsg(msg); setTimeout(() => setFlashMsg(null), 1800); };

  const filtered = useMemo(() => {
    let rules = db.rules;
    if (titleFilter !== 'All') rules = rules.filter(r => r.titleNum === titleFilter);
    if (categoryFilter !== 'All') rules = rules.filter(r => r.category === categoryFilter);
    if (deadlineOnly) rules = rules.filter(r => r.hasDeadline);
    if (favoritesOnly) rules = rules.filter(r => favorites.includes(r.id));
    if (search) {
      const q = search.toLowerCase();
      rules = rules.filter(r => r.rule.toLowerCase().includes(q) || r.title.toLowerCase().includes(q) || r.summary.toLowerCase().includes(q) || (r.practiceNote && r.practiceNote.toLowerCase().includes(q)));
    }
    return rules;
  }, [search, titleFilter, deadlineOnly, categoryFilter, favoritesOnly, favorites]);

  // incidents + amendments + judge orders keyed by rule
  const incidentsFor = useCallback((rule) => {
    return (RD.deadlineIncidents || []).filter(i => i.rule && rule && i.rule.toLowerCase().startsWith(rule.rule.toLowerCase()));
  }, [RD]);
  const amendmentsFor = useCallback((rule) => {
    return (RD.amendments || []).filter(a => a.rule === rule.rule);
  }, [RD]);
  const judgeOrdersFor = useCallback((rule) => {
    const topicMap = { service: 'Service', deadlines: 'Motion Practice', motion: 'Motion Practice', discovery: 'Motion Practice', 'case-management': 'Motion Practice' };
    const topic = topicMap[rule.category];
    if (!topic) return [];
    const out = [];
    (RD.judgeOrders || []).forEach(j => {
      j.orders.forEach(o => { if (o.topic === topic || o.topic === 'Page Limits') out.push({ judge: j.judge, court: j.court, ...o }); });
    });
    return out.slice(0, 4);
  }, [RD]);

  const [focusIdx, setFocusIdx] = useState(-1);

  // Keyboard nav
  useEffect(() => {
    const handler = (e) => {
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT') return;
      if (e.key === 'ArrowDown') { e.preventDefault(); setFocusIdx(i => Math.min(i + 1, filtered.length - 1)); }
      if (e.key === 'ArrowUp') { e.preventDefault(); setFocusIdx(i => Math.max(i - 1, 0)); }
      if (e.key === 'Enter' && focusIdx >= 0) { setExpanded(prev => prev === filtered[focusIdx].id ? null : filtered[focusIdx].id); }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [focusIdx, filtered]);

  const navigateToRule = useCallback((ruleId) => {
    setSearch('');
    setTitleFilter('All');
    setCategoryFilter('All');
    setDeadlineOnly(false);
    setExpanded(ruleId);
    setTimeout(() => {
      const el = document.getElementById('rule-' + ruleId);
      if (el) el.scrollIntoView({ block: 'center' });
    }, 50);
  }, []);

  // Expose for cross-ref clicks
  window.__navigateToRule = navigateToRule;

  const deadlineRules = db.rules.filter(r => r.hasDeadline).length;
  const totalDeadlines = db.rules.reduce((s, r) => s + (r.deadlines?.length || 0), 0);

  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: '12px', marginBottom: '16px' }}>
        <div style={cal.stat}><span style={cal.statLabel}>Total Rules</span><span style={cal.statValue}>{db.rules.length}</span></div>
        <div style={cal.stat}><span style={cal.statLabel}>Rules with Deadlines</span><span style={{ ...cal.statValue, color: cal.amber }}>{deadlineRules}</span></div>
        <div style={cal.stat}><span style={cal.statLabel}>Deadline Provisions</span><span style={{ ...cal.statValue, color: '#C23030' }}>{totalDeadlines}</span></div>
        <div style={cal.stat}><span style={cal.statLabel}>Titles Covered</span><span style={cal.statValue}>{db.titles.length}</span></div>
      </div>

      <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', alignItems: 'center', flexWrap: 'wrap' }}>
        <input style={{ height: '32px', border: `1px solid ${T.color.border.light}`, borderRadius: T.radius.md, padding: '0 12px', fontSize: '12px', fontFamily: T.font.family, background: T.color.bg.card, color: T.color.text.primary, outline: 'none', width: '240px' }} placeholder="Search rules, titles, keywords… (↑↓ to navigate)" value={search} onChange={e => { setSearch(e.target.value); setFocusIdx(-1); }} />
        <input style={{ height: '32px', border: `1px solid ${T.color.border.light}`, borderRadius: T.radius.md, padding: '0 10px', fontSize: '12px', fontFamily: T.font.mono, background: T.color.bg.card, color: T.color.text.primary, outline: 'none', width: '110px' }} placeholder="Go to: 12(a)" onKeyDown={(e) => {
          if (e.key === 'Enter') {
            const q = e.target.value.trim().toLowerCase().replace(/^rule\s*/, '');
            const m = db.rules.find(r => r.rule.toLowerCase().replace('rule ', '') === q) || db.rules.find(r => r.rule.toLowerCase().includes(q));
            if (m) { navigateToRule(m.id); e.target.value = ''; }
          }
        }} />
        <select style={{ ...cal.filterBtn, padding: '4px 8px' }} value={titleFilter} onChange={e => setTitleFilter(e.target.value)}>
          <option value="All">All Titles</option>
          {db.titles.map(t => <option key={t.num} value={t.num}>Title {t.num}: {t.name}</option>)}
        </select>
        <select style={{ ...cal.filterBtn, padding: '4px 8px' }} value={categoryFilter} onChange={e => setCategoryFilter(e.target.value)}>
          {categories.map(c => <option key={c} value={c}>{c === 'All' ? 'All Categories' : c}</option>)}
        </select>
        <button onClick={() => setDeadlineOnly(!deadlineOnly)} style={{ ...cal.filterBtn, ...(deadlineOnly ? cal.filterBtnActive : {}) }}> Deadline Rules Only</button>
        <button onClick={() => setFavoritesOnly(!favoritesOnly)} style={{ ...cal.filterBtn, ...(favoritesOnly ? { background: '#D97706', color: '#fff', borderColor: '#D97706' } : {}) }}>Favorites ({favorites.length})</button>
        <span style={{ fontSize: '10px', color: T.color.text.tertiary, marginLeft: '8px' }}>{filtered.length} rules shown</span>
      </div>

      {/* Recents + Favorites strip */}
      {(recents.length > 0 || favorites.length > 0) && (
        <div style={{ display: 'flex', gap: '16px', marginBottom: '12px', alignItems: 'center', flexWrap: 'wrap', padding: '8px 12px', background: T.color.bg.secondary, borderRadius: '6px', border: `1px solid ${T.color.border.light}` }}>
          {recents.length > 0 && (
            <div style={{ display: 'flex', gap: '6px', alignItems: 'center', flexWrap: 'wrap' }}>
              <span style={{ fontSize: '9px', fontWeight: 700, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Recent</span>
              {recents.slice(0, 6).map(id => {
                const r = db.rules.find(x => x.id === id);
                if (!r) return null;
                return <button key={id} onClick={() => navigateToRule(id)} style={{ padding: '2px 8px', borderRadius: '10px', border: `1px solid ${T.color.border.light}`, background: T.color.bg.card, fontSize: '10px', fontWeight: 600, color: T.color.text.secondary, cursor: 'pointer', fontFamily: T.font.mono }}>{r.rule}</button>;
              })}
            </div>
          )}
          {favorites.length > 0 && (
            <div style={{ display: 'flex', gap: '6px', alignItems: 'center', flexWrap: 'wrap' }}>
              <span style={{ fontSize: '9px', fontWeight: 700, color: '#D97706', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Favorites</span>
              {favorites.slice(0, 6).map(id => {
                const r = db.rules.find(x => x.id === id);
                if (!r) return null;
                return <button key={id} onClick={() => navigateToRule(id)} style={{ padding: '2px 8px', borderRadius: '10px', border: `1px solid #D9770640`, background: 'rgba(217,119,6,0.06)', fontSize: '10px', fontWeight: 600, color: '#D97706', cursor: 'pointer', fontFamily: T.font.mono }}>{r.rule}</button>;
              })}
            </div>
          )}
        </div>
      )}

      {flashMsg && (
        <div style={{ padding: '8px 14px', marginBottom: '12px', background: '#1B7A4A10', border: '1px solid #1B7A4A40', borderRadius: '6px', fontSize: '11px', color: '#1B7A4A', fontWeight: 600 }}>{flashMsg}</div>
      )}

      {pinDialog && (() => {
        const r = db.rules.find(x => x.id === pinDialog.ruleId);
        if (!r) return null;
        return (
          <div style={{ padding: '12px 16px', marginBottom: '12px', background: T.color.bg.card, border: `1px solid ${rb.navy || '#1E3A5F'}`, borderRadius: '8px' }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '8px' }}>
              <div style={{ fontSize: '12px', fontWeight: 700, color: rb.navy || '#1E3A5F' }}>Pin {r.rule} to Matter</div>
              <button onClick={() => setPinDialog(null)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: T.color.text.tertiary, fontSize: '14px' }}><Icons.X size={11}/></button>
            </div>
            <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
              <input value={pinMatter} onChange={e => setPinMatter(e.target.value)} placeholder="Matter ID" style={{ height: '28px', border: `1px solid ${T.color.border.light}`, borderRadius: '6px', padding: '0 10px', fontSize: '11px', fontFamily: T.font.mono, width: '140px' }} />
              <input value={pinReason} onChange={e => setPinReason(e.target.value)} placeholder="Reason (e.g. 'RFA deadline controls')" style={{ flex: 1, height: '28px', border: `1px solid ${T.color.border.light}`, borderRadius: '6px', padding: '0 10px', fontSize: '11px' }} />
              <button onClick={() => {
                if (window.RulebookStore) {
                  window.RulebookStore.pinRule({ matterId: pinMatter, ruleId: r.rule, reason: pinReason, context: r.title, pinnedBy: 'M. Kirkland' });
                  flash(`Pinned ${r.rule} to ${pinMatter}`);
                }
                setPinDialog(null);
                setPinReason('');
              }} style={{ padding: '0 14px', height: '28px', borderRadius: '6px', background: rb.navy || '#1E3A5F', color: '#fff', border: 'none', fontSize: '11px', fontWeight: 700, cursor: 'pointer' }}>Pin</button>
            </div>
          </div>
        );
      })()}

      <div style={cal.card} ref={listRef}>
        {filtered.map((rule, i) => {
          const isOpen = expanded === rule.id;
          const isFocused = focusIdx === i;
          return (
            <div key={rule.id} id={'rule-' + rule.id} style={{ borderBottom: `1px solid ${T.color.border.light}`, outline: isFocused ? `2px solid ${cal.amber}` : 'none', outlineOffset: '-2px' }}>
              <div style={{ padding: '10px 16px', display: 'flex', alignItems: 'center', gap: '10px', cursor: 'pointer', transition: 'background 0.1s', background: isFocused ? cal.amberBg : 'transparent' }} onClick={() => { const next = isOpen ? null : rule.id; setExpanded(next); setFocusIdx(i); if (next) pushRecent(rule.id); }}>
                <button onClick={(e) => { e.stopPropagation(); toggleFavorite(rule.id); }} title={favorites.includes(rule.id) ? 'Remove from favorites' : 'Add to favorites'} style={{ width: '26px', height: '20px', borderRadius: '4px', border: `1px solid ${favorites.includes(rule.id) ? '#D97706' : T.color.border.light}`, background: favorites.includes(rule.id) ? '#D97706' : 'transparent', color: favorites.includes(rule.id) ? '#fff' : T.color.text.tertiary, cursor: 'pointer', fontSize: '9px', fontWeight: 700, padding: 0, letterSpacing: '0.06em' }}>
                  {favorites.includes(rule.id) ? 'FAV' : '+'}
                </button>
                <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: cal.amber, minWidth: '80px', fontSize: '12px' }}>{rule.rule}</span>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, fontSize: '13px', color: T.color.text.primary }}>{rule.title}</div>
                  <div style={{ fontSize: '11px', color: T.color.text.secondary, marginTop: '1px', lineHeight: 1.4 }}>{rule.summary.length > 120 ? rule.summary.slice(0, 120) + '…' : rule.summary}</div>
                </div>
                {(() => {
                  const inc = incidentsFor(rule);
                  if (inc.length > 0) return <span style={{ ...cal.tag, background: '#C2303010', color: '#C23030', fontWeight: 700 }} title="Recent missed-deadline incidents">{inc.length} Incident{inc.length > 1 ? 's' : ''}</span>;
                  return null;
                })()}
                <span style={{ ...cal.tag, background: T.color.bg.secondary, color: T.color.text.tertiary }}>{rule.category}</span>
                {rule.hasDeadline && <span style={{ ...cal.tag, background: 'rgba(194,48,48,0.06)', color: '#C23030' }}> {rule.deadlines?.length || 0}</span>}
                <span style={{ fontSize: '12px', color: T.color.text.tertiary }}>{isOpen ? '▴' : '▾'}</span>
              </div>
              {isOpen && (
                <div style={{ padding: '0 16px 12px 96px', background: T.color.bg.secondary }}>
                  {/* Action bar */}
                  <div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap', padding: '8px 0', marginBottom: '6px', borderBottom: `1px dashed ${T.color.border.light}` }}>
                    <button onClick={(e) => { e.stopPropagation(); setPinDialog({ ruleId: rule.id }); }} style={{ padding: '4px 10px', borderRadius: '6px', background: rb.navy || '#1E3A5F', color: '#fff', border: 'none', fontSize: '10px', fontWeight: 700, cursor: 'pointer', letterSpacing: '0.04em', textTransform: 'uppercase' }}>Pin to Matter</button>
                    <button onClick={(e) => {
                      e.stopPropagation();
                      if (window.RulebookStore) {
                        window.RulebookStore.subscribeRule({ ruleId: rule.rule, topic: 'amendments', user: 'M. Kirkland' });
                        flash(`Subscribed to ${rule.rule} amendments`);
                      }
                    }} style={{ padding: '4px 10px', borderRadius: '6px', background: T.color.bg.card, color: rb.navy || '#1E3A5F', border: `1px solid ${rb.navy || '#1E3A5F'}`, fontSize: '10px', fontWeight: 700, cursor: 'pointer', letterSpacing: '0.04em', textTransform: 'uppercase' }}>Subscribe</button>
                    {rule.hasDeadline && rule.deadlines?.length > 0 && (
                      <button onClick={(e) => {
                        e.stopPropagation();
                        if (window.RulebookStore) {
                          const today = new Date().toISOString().slice(0, 10);
                          rule.deadlines.forEach(dl => {
                            const d = new Date(); d.setDate(d.getDate() + dl.days);
                            window.RulebookStore.pushToCalendar({
                              ruleId: rule.rule,
                              ruleLabel: `${rule.rule}${dl.sub} — ${dl.desc}`,
                              date: d.toISOString().slice(0, 10),
                              matter: 'M-2026-0042',
                              assignee: 'M. Kirkland',
                              priority: dl.critical ? 'critical' : 'high',
                              notes: `Trigger: ${dl.trigger}`,
                            });
                          });
                          flash(`${rule.deadlines.length} deadline(s) → Calendar`);
                        }
                      }} style={{ padding: '4px 10px', borderRadius: '6px', background: '#C23030', color: '#fff', border: 'none', fontSize: '10px', fontWeight: 700, cursor: 'pointer', letterSpacing: '0.04em', textTransform: 'uppercase' }}>Send to Calendar</button>
                    )}
                  </div>
                  <div style={{ fontSize: '12px', color: T.color.text.secondary, lineHeight: 1.5, marginBottom: '10px' }}>{rule.summary}</div>
                  {rule.practiceNote && (
                    <div style={{ padding: '8px 12px', background: cal.amberBg, borderRadius: '6px', borderLeft: `3px solid ${cal.amber}`, fontSize: '11px', color: T.color.text.secondary, lineHeight: 1.5, marginBottom: '10px' }}>
                      <span style={{ fontWeight: 700, color: cal.amber }}>Practice Note: </span>{rule.practiceNote}
                    </div>
                  )}
                  {/* Cross-references */}
                  {rule.crossRefs && rule.crossRefs.length > 0 && (
                    <div style={{ display: 'flex', gap: '6px', alignItems: 'center', marginBottom: '10px', flexWrap: 'wrap' }}>
                      <span style={{ fontSize: '10px', fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em' }}>See Also:</span>
                      {rule.crossRefs.map(ref => {
                        const refRule = db.rules.find(r => r.id === ref);
                        return (
                          <button key={ref} onClick={(e) => { e.stopPropagation(); navigateToRule(ref); }}
                            style={{ padding: '2px 8px', borderRadius: '10px', border: `1px solid ${T.color.border.light}`, background: T.color.bg.card, fontSize: '10px', fontWeight: 600, color: cal.amber, cursor: 'pointer', fontFamily: T.font.mono, transition: 'all 0.15s' }}
                            onMouseEnter={e => { e.target.style.background = cal.amberBg; e.target.style.borderColor = cal.amber; }}
                            onMouseLeave={e => { e.target.style.background = T.color.bg.card; e.target.style.borderColor = T.color.border.light; }}
                          >{refRule ? refRule.rule : ref}</button>
                        );
                      })}
                    </div>
                  )}
                  {rule.deadlines && rule.deadlines.length > 0 && (
                    <div>
                      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' }}>
                        <span style={{ fontSize: '10px', fontWeight: 600, color: '#C23030', textTransform: 'uppercase', letterSpacing: '0.06em' }}> Deadline Provisions</span>
                      </div>
                      {rule.deadlines.map((dl, j) => (
                        <div key={j} style={{ display: 'flex', gap: '10px', padding: '6px 0', borderBottom: j < rule.deadlines.length - 1 ? `1px solid ${T.color.border.light}` : 'none', fontSize: '11px', alignItems: 'flex-start' }}>
                          <span style={{ fontFamily: T.font.mono, fontWeight: 600, color: cal.amber, minWidth: '50px' }}>{dl.sub}</span>
                          <div style={{ flex: 1 }}>
                            <div style={{ color: T.color.text.primary, fontWeight: 500 }}>{dl.desc}</div>
                            <div style={{ color: T.color.text.tertiary, marginTop: '2px', fontSize: '10px' }}>Trigger: {dl.trigger} · Type: {dl.type}</div>
                          </div>
                          <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: dl.critical ? '#C23030' : T.color.text.secondary, minWidth: '50px', textAlign: 'right' }}>
                            {dl.days > 0 ? `+${dl.days}d` : dl.days < 0 ? `${dl.days}d` : '—'}
                          </span>
                          {dl.critical && <span style={{ ...cal.tag, background: 'rgba(194,48,48,0.06)', color: '#C23030' }}>Critical</span>}
                          <CopyDeadlineBtn deadline={dl} rule={rule} />
                        </div>
                      ))}
                    </div>
                  )}
                  {/* Incidents / Amendments / Judge orders intel */}
                  {(() => {
                    const inc = incidentsFor(rule);
                    const amd = amendmentsFor(rule);
                    const ord = judgeOrdersFor(rule);
                    if (inc.length === 0 && amd.length === 0 && ord.length === 0) return null;
                    return (
                      <div style={{ marginTop: '12px', display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '8px' }}>
                        <div style={{ padding: '8px 10px', background: T.color.bg.card, border: `1px solid ${T.color.border.light}`, borderRadius: '6px', minWidth: 0 }}>
                          <div style={{ fontSize: '9px', fontWeight: 700, color: '#C23030', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>Incidents ({inc.length})</div>
                          {inc.length === 0 ? <div style={{ fontSize: '10px', color: T.color.text.tertiary, fontStyle: 'italic' }}>No incidents on file.</div> : inc.slice(0, 4).map(i => (
                            <div key={i.id} style={{ fontSize: '10px', color: T.color.text.secondary, padding: '3px 0', borderBottom: `1px dotted ${T.color.border.light}` }}>
                              <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: i.severity === 'critical' ? '#C23030' : '#D97706' }}>{i.court}</span> · {i.outcome.slice(0, 40)}
                            </div>
                          ))}
                        </div>
                        <div style={{ padding: '8px 10px', background: T.color.bg.card, border: `1px solid ${T.color.border.light}`, borderRadius: '6px', minWidth: 0 }}>
                          <div style={{ fontSize: '9px', fontWeight: 700, color: rb.navy || '#1E3A5F', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>Amendments ({amd.length})</div>
                          {amd.length === 0 ? <div style={{ fontSize: '10px', color: T.color.text.tertiary, fontStyle: 'italic' }}>No recent amendments.</div> : amd.slice(0, 3).map((a, k) => (
                            <div key={k} style={{ fontSize: '10px', color: T.color.text.secondary, padding: '3px 0', borderBottom: `1px dotted ${T.color.border.light}` }}>
                              <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: rb.navy || '#1E3A5F' }}>{a.year}</span> · {a.change.slice(0, 50)}{a.change.length > 50 ? '…' : ''}
                            </div>
                          ))}
                        </div>
                        <div style={{ padding: '8px 10px', background: T.color.bg.card, border: `1px solid ${T.color.border.light}`, borderRadius: '6px', minWidth: 0 }}>
                          <div style={{ fontSize: '9px', fontWeight: 700, color: '#0D9488', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>Judge Orders ({ord.length})</div>
                          {ord.length === 0 ? <div style={{ fontSize: '10px', color: T.color.text.tertiary, fontStyle: 'italic' }}>No judge-specific orders.</div> : ord.slice(0, 3).map((o, k) => (
                            <div key={k} style={{ fontSize: '10px', color: T.color.text.secondary, padding: '3px 0', borderBottom: `1px dotted ${T.color.border.light}` }}>
                              <span style={{ fontWeight: 700, color: '#0D9488' }}>{o.judge.split(' ').slice(-1)[0]}</span> · {o.text.slice(0, 45)}{o.text.length > 45 ? '…' : ''}
                            </div>
                          ))}
                        </div>
                      </div>
                    );
                  })()}
                </div>
              )}
            </div>
          );
        })}
        {filtered.length === 0 && (
          <div style={{ padding: '32px', textAlign: 'center', color: T.color.text.tertiary, fontSize: '13px' }}>No rules match your filters.</div>
        )}
      </div>
    </div>
  );
}

// Copy deadline to clipboard button
function CopyDeadlineBtn({ deadline, rule }) {
  const [copied, setCopied] = useState(false);
  const handleCopy = (e) => {
    e.stopPropagation();
    const text = `${rule.rule} ${deadline.sub} — ${deadline.desc}\nTrigger: ${deadline.trigger} | Days: ${deadline.days > 0 ? '+' : ''}${deadline.days} | ${deadline.critical ? 'CRITICAL' : 'Standard'}`;
    navigator.clipboard.writeText(text).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    });
  };
  return (
    <button onClick={handleCopy} title="Copy to clipboard" style={{ ...cal.filterBtn, fontSize: '9px', padding: '2px 8px', minWidth: '44px', color: copied ? '#1B7A4A' : T.color.text.tertiary, borderColor: copied ? '#1B7A4A' : T.color.border.light }}>
      {copied ? 'ok Copied' : ' Copy'}
    </button>
  );
}

// ── CHAIN CALCULATOR ──
// Federal holidays per 5 U.S.C. § 6103 (Rule 6(a)(6)) — 2026 dates
const FED_HOLIDAYS_2026 = {
  '2026-01-01': "New Year's Day",
  '2026-01-19': 'MLK Day',
  '2026-02-16': "Washington's Birthday",
  '2026-05-25': 'Memorial Day',
  '2026-06-19': 'Juneteenth',
  '2026-07-03': 'Independence Day (observed)',
  '2026-09-07': 'Labor Day',
  '2026-10-12': 'Columbus Day',
  '2026-11-11': 'Veterans Day',
  '2026-11-26': 'Thanksgiving',
  '2026-12-25': 'Christmas',
};
const FED_HOLIDAYS_2027 = {
  '2027-01-01': "New Year's Day",
  '2027-01-18': 'MLK Day',
  '2027-02-15': "Washington's Birthday",
  '2027-05-31': 'Memorial Day',
  '2027-06-18': 'Juneteenth (observed)',
  '2027-07-05': 'Independence Day (observed)',
  '2027-09-06': 'Labor Day',
  '2027-10-11': 'Columbus Day',
  '2027-11-11': 'Veterans Day',
  '2027-11-25': 'Thanksgiving',
  '2027-12-24': 'Christmas (observed)',
};
const ALL_HOLIDAYS = { ...FED_HOLIDAYS_2026, ...FED_HOLIDAYS_2027 };

function FRCPChainCalc() {
  const db = window.FRCP_DATABASE;
  const rb = window.rb || {};
  const [triggerEvent, setTriggerEvent] = useState('filing');
  const [triggerDate, setTriggerDate] = useState('2026-05-01');
  const [matterId, setMatterId] = useState('M-2026-0042');
  const [assignee, setAssignee] = useState('M. Kirkland');
  const [customRules, setCustomRules] = useState([]);
  const [showCustom, setShowCustom] = useState(false);
  const [skipHolidays, setSkipHolidays] = useState(true);
  const [flashMsg, setFlashMsg] = useState(null);
  const flash = (m) => { setFlashMsg(m); setTimeout(() => setFlashMsg(null), 2000); };

  const SCENARIOS = {
    filing: { label: 'New Case Filed', trigger: 'Complaint Filed', chains: [
      { rule: 'Rule 4(m)', desc: 'Serve defendant within 90 days', days: 90, critical: true },
      { rule: 'Rule 12(a)(1)', desc: 'Answer due 21 days after service', days: 111, critical: true, note: '(90 + 21)' },
      { rule: 'Rule 26(f)', desc: 'Parties confer (≈120 days after filing)', days: 120, critical: true },
      { rule: 'Rule 26(a)(1)', desc: 'Initial disclosures 14 days after 26(f)', days: 134, critical: true },
      { rule: 'Rule 16(b)', desc: 'Scheduling order issued', days: 150, critical: false },
    ]},
    served: { label: 'Defendant Served', trigger: 'Service of Process', chains: [
      { rule: 'Rule 12(a)(1)', desc: 'Answer due 21 days', days: 21, critical: true },
      { rule: 'Rule 12(b)', desc: 'Pre-answer motion deadline (21 days)', days: 21, critical: true },
      { rule: 'Rule 38(b)', desc: 'Jury demand 14 days after last pleading', days: 35, critical: true, note: '(21 + 14)' },
      { rule: 'Rule 13', desc: 'Compulsory counterclaims with answer', days: 21, critical: false },
      { rule: 'Rule 14(a)', desc: 'Third-party complaint 14 days after answer', days: 35, critical: false },
    ]},
    discovery: { label: 'Discovery Opens', trigger: 'Rule 26(f) Conference', chains: [
      { rule: 'Rule 26(a)(1)', desc: 'Initial disclosures within 14 days', days: 14, critical: true },
      { rule: 'Rule 33', desc: 'Interrogatories — responses 30 days after service', days: 44, critical: true, note: '(14 + 30)' },
      { rule: 'Rule 34', desc: 'RFP — responses 30 days after service', days: 44, critical: true },
      { rule: 'Rule 36', desc: 'RFA — responses 30 days (DEEMED ADMITTED if missed)', days: 44, critical: true },
      { rule: 'Rule 30', desc: 'Depositions — reasonable notice (≈14 days)', days: 28, critical: false },
    ]},
    trial: { label: 'Trial Date Set', trigger: 'Trial Date', chains: [
      { rule: 'Rule 26(a)(2)(D)', desc: 'Expert disclosure 90 days before trial', days: -90, critical: true },
      { rule: 'Rule 26(a)(2)(D)(ii)', desc: 'Rebuttal expert 60 days before trial', days: -60, critical: true },
      { rule: 'Rule 26(a)(3)', desc: 'Pretrial disclosures 30 days before', days: -30, critical: true },
      { rule: 'Rule 68(a)', desc: 'Offer of judgment 14 days before', days: -14, critical: false },
      { rule: 'Rule 51', desc: 'Proposed jury instructions (court-set)', days: -7, critical: true },
    ]},
    judgment: { label: 'Judgment Entered', trigger: 'Judgment Entered', chains: [
      { rule: 'Rule 54(d)', desc: 'Attorney fees motion — 14 days', days: 14, critical: true },
      { rule: 'Rule 50(b)', desc: 'Renewed JMOL — 28 days', days: 28, critical: true },
      { rule: 'Rule 52(b)', desc: 'Amend findings — 28 days', days: 28, critical: true },
      { rule: 'Rule 59(b)', desc: 'New trial motion — 28 days', days: 28, critical: true },
      { rule: 'Rule 59(e)', desc: 'Alter/amend judgment — 28 days', days: 28, critical: true },
      { rule: 'FRAP 4(a)', desc: 'Notice of appeal — 30 days', days: 30, critical: true },
      { rule: 'Rule 62(a)', desc: 'Automatic stay expires — 30 days', days: 30, critical: false },
      { rule: 'Rule 60(b)', desc: 'Relief from judgment — up to 1 year', days: 365, critical: false },
    ]},
  };

  const scenario = SCENARIOS[triggerEvent];
  const activeChains = showCustom && customRules.length > 0 ? customRules : scenario.chains;

  // Add a custom rule from the database
  const addCustomRule = (ruleId) => {
    const rule = db.rules.find(r => r.id === ruleId);
    if (!rule || !rule.deadlines) return;
    const newItems = rule.deadlines.map(dl => ({
      rule: `${rule.rule} ${dl.sub}`, desc: dl.desc, days: dl.days, critical: dl.critical
    }));
    setCustomRules(prev => [...prev, ...newItems]);
  };

  const removeCustomRule = (idx) => setCustomRules(prev => prev.filter((_, i) => i !== idx));

  // Calculate date per Rule 6 — calendar days, then roll off weekend/holiday
  const isHoliday = (d) => skipHolidays && !!ALL_HOLIDAYS[d.toISOString().slice(0, 10)];
  const rawDate = (baseDateStr, days) => {
    const d = new Date(baseDateStr + 'T12:00:00');
    d.setDate(d.getDate() + days);
    return d;
  };
  const calcDate = (baseDateStr, days) => {
    if (days === 0) return new Date(baseDateStr + 'T12:00:00');
    const dir = days > 0 ? 1 : -1;
    const d = rawDate(baseDateStr, days);
    // Rule 6(a)(1)(C) + 6(a)(6): extend/contract past Sat/Sun/holiday
    let guard = 0;
    while (guard++ < 14) {
      const dow = d.getDay();
      if (dow !== 0 && dow !== 6 && !isHoliday(d)) break;
      d.setDate(d.getDate() + dir);
    }
    return d;
  };
  // Returns { date, adjusted, hitType } — true if rolled off weekend/holiday
  const calcDateMeta = (baseDateStr, days) => {
    const raw = rawDate(baseDateStr, days);
    const adj = calcDate(baseDateStr, days);
    const rawKey = raw.toISOString().slice(0, 10);
    const adjusted = raw.getTime() !== adj.getTime();
    let hitType = null;
    if (adjusted) {
      const dow = raw.getDay();
      if (ALL_HOLIDAYS[rawKey]) hitType = ALL_HOLIDAYS[rawKey];
      else if (dow === 0 || dow === 6) hitType = dow === 0 ? 'Sunday' : 'Saturday';
    }
    return { date: adj, adjusted, hitType };
  };

  // Timeline visualization
  const allDates = activeChains.map(c => calcDate(triggerDate, c.days).getTime());
  const triggerTime = new Date(triggerDate + 'T12:00:00').getTime();
  const minTime = Math.min(triggerTime, ...allDates);
  const maxTime = Math.max(triggerTime, ...allDates);
  const timeSpan = maxTime - minTime || 1;

  const handleCopyAll = () => {
    const lines = activeChains.map(c => {
      const d = calcDate(triggerDate, c.days);
      return `${d.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric' })}  ${c.rule} — ${c.desc}${c.critical ? ' [CRITICAL]' : ''}`;
    });
    const header = `Deadline Chain: ${showCustom ? 'Custom' : scenario.label}\nTrigger: ${triggerDate}\n${'─'.repeat(60)}`;
    navigator.clipboard.writeText(header + '\n' + lines.join('\n'));
  };

  const handlePushAll = () => {
    if (!window.RulebookStore) return;
    activeChains.forEach(c => {
      const d = calcDate(triggerDate, c.days);
      window.RulebookStore.pushToCalendar({
        ruleId: c.rule,
        ruleLabel: `${c.rule} — ${c.desc}`,
        date: d.toISOString().slice(0, 10),
        matter: matterId,
        assignee,
        priority: c.critical ? 'critical' : 'high',
        notes: c.note || '',
      });
    });
    flash(`${activeChains.length} deadline(s) pushed to Calendar for ${matterId}`);
  };

  const handleICS = () => {
    const pad = n => String(n).padStart(2, '0');
    const fmtICS = d => `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}T${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}00Z`;
    const now = fmtICS(new Date());
    const events = activeChains.map((c, i) => {
      const d = calcDate(triggerDate, c.days);
      const dt = fmtICS(d);
      const end = fmtICS(new Date(d.getTime() + 60 * 60 * 1000));
      return [
        'BEGIN:VEVENT',
        `UID:${matterId}-${c.rule.replace(/\s+/g, '')}-${i}@arbiter`,
        `DTSTAMP:${now}`,
        `DTSTART:${dt}`,
        `DTEND:${end}`,
        `SUMMARY:${c.rule} — ${c.desc}${c.critical ? ' [CRITICAL]' : ''}`,
        `DESCRIPTION:Matter ${matterId} | Assignee: ${assignee}${c.note ? ' | ' + c.note : ''}`,
        `PRIORITY:${c.critical ? '1' : '5'}`,
        'END:VEVENT',
      ].join('\r\n');
    }).join('\r\n');
    const ics = ['BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//Arbiter//Rulebook Chain//EN', events, 'END:VCALENDAR'].join('\r\n');
    const blob = new Blob([ics], { type: 'text/calendar' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${matterId}-${triggerEvent}-deadlines.ics`;
    a.click();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
    flash('ICS downloaded');
  };

  const handlePrint = () => {
    const w = window.open('', '_blank');
    const rows = activeChains.map(c => {
      const d = calcDate(triggerDate, c.days);
      return `<tr style="border-bottom:1px solid #eee"><td style="padding:6px;font-family:monospace;font-weight:700;color:#D97706">${c.rule}</td><td style="padding:6px">${c.desc}</td><td style="padding:6px;font-family:monospace;font-weight:700">${d.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric' })}</td><td style="padding:6px;color:${c.critical ? '#C23030' : '#666'}">${c.critical ? 'CRITICAL' : '—'}</td></tr>`;
    }).join('');
    w.document.write(`<html><head><title>Deadline Chain</title></head><body style="font-family:system-ui;padding:40px;max-width:900px;margin:0 auto"><h2 style="margin-bottom:4px">Deadline Chain — ${showCustom ? 'Custom' : scenario.label}</h2><p style="color:#666;margin-bottom:24px">Trigger: ${triggerDate} · Generated by Arbiter</p><table style="width:100%;border-collapse:collapse"><thead><tr style="background:#f5f2ed;text-align:left"><th style="padding:8px;font-size:12px">Rule</th><th style="padding:8px;font-size:12px">Description</th><th style="padding:8px;font-size:12px">Date</th><th style="padding:8px;font-size:12px">Severity</th></tr></thead><tbody>${rows}</tbody></table><p style="color:#999;font-size:11px;margin-top:32px">Dates calculated per Rule 6 (weekends adjusted to next business day). Verify against local rules.</p></body></html>`);
    w.document.close();
    setTimeout(() => w.print(), 300);
  };

  return (
    <div>
      <div style={{ display: 'flex', gap: '12px', marginBottom: '16px', alignItems: 'flex-end', flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontSize: '10px', fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>Trigger Event</div>
          <select value={triggerEvent} onChange={e => { setTriggerEvent(e.target.value); setShowCustom(false); }} style={{ width: '200px', height: '32px', border: `1px solid ${T.color.border.light}`, borderRadius: T.radius.md, padding: '0 8px', fontSize: '12px', fontFamily: T.font.family, background: T.color.bg.card, color: T.color.text.primary }}>
            {Object.entries(SCENARIOS).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
          </select>
        </div>
        <div>
          <div style={{ fontSize: '10px', fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>Trigger Date</div>
          <input type="date" value={triggerDate} onChange={e => setTriggerDate(e.target.value)} style={{ width: '160px', height: '32px', border: `1px solid ${T.color.border.light}`, borderRadius: T.radius.md, padding: '0 8px', fontSize: '12px', fontFamily: T.font.family, background: T.color.bg.card, color: T.color.text.primary }} />
        </div>
        <div>
          <div style={{ fontSize: '10px', fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>Matter</div>
          <input value={matterId} onChange={e => setMatterId(e.target.value)} style={{ width: '140px', height: '32px', border: `1px solid ${T.color.border.light}`, borderRadius: T.radius.md, padding: '0 8px', fontSize: '12px', fontFamily: T.font.mono, background: T.color.bg.card, color: T.color.text.primary }} />
        </div>
        <div>
          <div style={{ fontSize: '10px', fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>Assignee</div>
          <input value={assignee} onChange={e => setAssignee(e.target.value)} style={{ width: '140px', height: '32px', border: `1px solid ${T.color.border.light}`, borderRadius: T.radius.md, padding: '0 8px', fontSize: '12px', fontFamily: T.font.family, background: T.color.bg.card, color: T.color.text.primary }} />
        </div>
        <button onClick={() => setShowCustom(!showCustom)} style={{ ...cal.filterBtn, ...(showCustom ? cal.filterBtnActive : {}), height: '32px' }}>
          {showCustom ? '← Back to Presets' : '+ Custom Chain'}
        </button>
        <button onClick={() => setSkipHolidays(!skipHolidays)} style={{ ...cal.filterBtn, ...(skipHolidays ? cal.filterBtnActive : {}), height: '32px' }} title="Rule 6(a)(1)(C) + 6(a)(6)">Skip Holidays: {skipHolidays ? 'On' : 'Off'}</button>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: '6px' }}>
          <button onClick={handlePushAll} style={{ height: '32px', padding: '0 14px', borderRadius: '6px', background: '#C23030', color: '#fff', border: 'none', fontSize: '11px', fontWeight: 700, cursor: 'pointer', letterSpacing: '0.04em', textTransform: 'uppercase' }}>Send to Calendar</button>
          <button onClick={handleICS} style={{ height: '32px', padding: '0 14px', borderRadius: '6px', background: rb.navy || '#1E3A5F', color: '#fff', border: 'none', fontSize: '11px', fontWeight: 700, cursor: 'pointer', letterSpacing: '0.04em', textTransform: 'uppercase' }}>Export .ics</button>
          <button onClick={handleCopyAll} style={{ ...cal.filterBtn, height: '32px' }}>Copy All</button>
          <button onClick={handlePrint} style={{ ...cal.filterBtn, height: '32px' }}>Print</button>
        </div>
      </div>

      {flashMsg && (
        <div style={{ padding: '8px 14px', marginBottom: '12px', background: '#1B7A4A10', border: '1px solid #1B7A4A40', borderRadius: '6px', fontSize: '11px', color: '#1B7A4A', fontWeight: 600 }}>{flashMsg}</div>
      )}

      {/* Custom rule adder */}
      {showCustom && (
        <div style={{ padding: '12px 16px', background: cal.amberBg, borderRadius: '8px', marginBottom: '16px', border: `1px solid ${cal.amber}30` }}>
          <div style={{ fontSize: '11px', fontWeight: 600, color: cal.amber, marginBottom: '8px' }}>Build Custom Chain — Select rules with deadlines:</div>
          <div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap' }}>
            {db.rules.filter(r => r.hasDeadline && r.deadlines?.length > 0).map(r => (
              <button key={r.id} onClick={() => addCustomRule(r.id)} style={{ ...cal.filterBtn, fontSize: '10px', padding: '2px 8px' }}>{r.rule}</button>
            ))}
          </div>
          {customRules.length > 0 && (
            <div style={{ marginTop: '8px', fontSize: '10px', color: T.color.text.tertiary }}>
              {customRules.length} deadline(s) in chain. <button onClick={() => setCustomRules([])} style={{ ...cal.filterBtn, fontSize: '9px', padding: '1px 6px', color: '#C23030', borderColor: '#C23030' }}>Clear All</button>
            </div>
          )}
        </div>
      )}

      {/* Visual timeline */}
      {activeChains.length > 0 && timeSpan > 0 && (
        <div style={{ ...cal.card, padding: '16px', marginBottom: '16px' }}>
          <div style={{ fontSize: '10px', fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '12px' }}>Timeline</div>
          <div style={{ position: 'relative', height: Math.max(activeChains.length * 24 + 16, 60), background: T.color.bg.secondary, borderRadius: '6px', padding: '8px 12px' }}>
            {/* Trigger marker */}
            <div style={{ position: 'absolute', left: `${((triggerTime - minTime) / timeSpan) * 90 + 5}%`, top: 0, bottom: 0, width: '2px', background: cal.amber, zIndex: 1 }} />
            <div style={{ position: 'absolute', left: `${((triggerTime - minTime) / timeSpan) * 90 + 5}%`, top: '-2px', transform: 'translateX(-50%)', fontSize: '8px', fontWeight: 700, color: cal.amber, background: T.color.bg.secondary, padding: '0 4px', zIndex: 2, whiteSpace: 'nowrap' }}>TRIGGER</div>
            {activeChains.map((c, i) => {
              const dateTime = calcDate(triggerDate, c.days).getTime();
              const pos = ((dateTime - minTime) / timeSpan) * 90 + 5;
              return (
                <div key={i} style={{ position: 'absolute', left: `${Math.min(pos, 95)}%`, top: `${12 + i * 24}px`, display: 'flex', alignItems: 'center', gap: '4px', transform: 'translateX(-50%)' }}>
                  <div style={{ width: '8px', height: '8px', borderRadius: '50%', background: c.critical ? '#C23030' : cal.amber, border: '2px solid ' + T.color.bg.secondary, flexShrink: 0 }} />
                  <span style={{ fontSize: '9px', fontFamily: T.font.mono, color: T.color.text.tertiary, whiteSpace: 'nowrap' }}>{c.rule}</span>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* KPI strip */}
      {(() => {
        const metas = activeChains.map(c => calcDateMeta(triggerDate, c.days));
        const criticals = activeChains.filter(c => c.critical).length;
        const adjusted = metas.filter(m => m.adjusted).length;
        const holidays = metas.filter(m => m.hitType && !['Saturday', 'Sunday'].includes(m.hitType)).length;
        return (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: '12px', marginBottom: '12px' }}>
            <div style={cal.stat}><span style={cal.statLabel}>Deadlines</span><span style={cal.statValue}>{activeChains.length}</span></div>
            <div style={cal.stat}><span style={cal.statLabel}>Critical</span><span style={{ ...cal.statValue, color: '#C23030' }}>{criticals}</span></div>
            <div style={cal.stat}><span style={cal.statLabel}>Rolled (Rule 6)</span><span style={{ ...cal.statValue, color: cal.amber }}>{adjusted}</span></div>
            <div style={cal.stat}><span style={cal.statLabel}>Holiday Hits</span><span style={{ ...cal.statValue, color: rb.navy || '#1E3A5F' }}>{holidays}</span></div>
          </div>
        );
      })()}

      {/* Chain table */}
      <div style={cal.card}>
        <div style={{ ...cal.cardH, background: cal.amberBg }}>
          <span style={{ color: cal.amber }}>Deadline Chain — {showCustom ? 'Custom' : scenario.label}</span>
          <span style={{ fontSize: '10px', color: T.color.text.tertiary }}>{activeChains.length} deadlines · Matter {matterId} · {assignee}</span>
        </div>
        {activeChains.map((c, i) => {
          const meta = calcDateMeta(triggerDate, c.days);
          const dateObj = meta.date;
          return (
            <div key={i} style={{ padding: '10px 16px', borderBottom: `1px solid ${T.color.border.light}`, display: 'flex', alignItems: 'center', gap: '10px', fontSize: '12px', borderLeft: c.critical ? '3px solid #C23030' : '3px solid transparent' }}>
              <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: cal.amber, minWidth: '90px', fontSize: '11px' }}>{c.rule}</span>
              <div style={{ flex: 1 }}>
                <div style={{ fontWeight: 500, color: T.color.text.primary }}>{c.desc}</div>
                {c.note && <div style={{ fontSize: '10px', color: T.color.text.tertiary }}>{c.note}</div>}
              </div>
              <span style={{ fontFamily: T.font.mono, fontSize: '11px', color: T.color.text.tertiary }}>{c.days > 0 ? '+' : ''}{c.days}d</span>
              <div style={{ textAlign: 'right', minWidth: '120px' }}>
                <div style={{ fontFamily: T.font.mono, fontWeight: 600, color: T.color.text.primary }}>{dateObj.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' })}</div>
                {meta.adjusted && <div style={{ fontSize: '9px', color: cal.amber, fontWeight: 600 }}>rolled off {meta.hitType}</div>}
              </div>
              {c.critical && <span style={{ ...cal.tag, background: 'rgba(194,48,48,0.06)', color: '#C23030' }}>Critical</span>}
              {meta.adjusted && <span style={{ ...cal.tag, background: `${cal.amber}10`, color: cal.amber, fontWeight: 700 }} title={`Rule 6(a) adjusted off ${meta.hitType}`}>Rule 6 Adjusted</span>}
              {showCustom && <button onClick={() => removeCustomRule(i)} style={{ ...cal.filterBtn, fontSize: '9px', padding: '2px 6px', color: '#C23030' }}><Icons.X size={11}/></button>}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── JURISDICTIONS ──
function FRCPJurisdictions() {
  const LOCAL_RULES = [
    { court: 'S.D.N.Y.', deviations: [
      { frcp: 'Rule 56', local: 'Local Rule 56.1', desc: 'Requires separate Statement of Undisputed Material Facts with MSJ. Opposing party must submit counterstatement.', impact: 'Additional filing requirement' },
      { frcp: 'Rule 7.1', local: 'Local Rule 7.1', desc: 'All motions must include a memorandum of law not exceeding 25 pages.', impact: 'Page limit' },
      { frcp: 'Rule 16', local: 'Local Rule 16.2', desc: 'Initial pretrial conference within 120 days of filing. Joint Case Management Plan required.', impact: 'Timing' },
      { frcp: 'Rule 37', local: 'Local Rule 37.2', desc: 'Discovery disputes require a pre-motion conference letter to the court before filing any motion.', impact: 'Pre-filing requirement' },
      { frcp: 'Rule 26', local: 'Individual Practice Rules', desc: 'Many judges have individual rules on discovery limits, page lengths, and scheduling. Always check.', impact: 'Judge-specific' },
    ]},
    { court: 'E.D.N.Y.', deviations: [
      { frcp: 'Rule 56', local: 'Local Rule 56.1', desc: 'Similar to S.D.N.Y. — separate statement of facts required.', impact: 'Additional filing' },
      { frcp: 'Rule 7', local: 'Local Rule 7.1(b)', desc: 'Memoranda in support of motions limited to 25 pages.', impact: 'Page limit' },
    ]},
    { court: 'D. Del.', deviations: [
      { frcp: 'Rule 56', local: 'Local Rule 56.1', desc: 'Opening brief limited to 30 pages. Appendix required.', impact: 'Page limit + appendix' },
      { frcp: 'Rule 26', local: 'Default Standard', desc: 'Delaware Chancery has separate discovery rules for corporate cases. Expedited proceedings common.', impact: 'Expedited timelines' },
    ]},
    { court: 'N.D. Cal.', deviations: [
      { frcp: 'Rule 56', local: 'Civil L.R. 56-2', desc: 'Joint statement of undisputed facts. 25-page brief limit.', impact: 'Joint statement required' },
      { frcp: 'Rule 26', local: 'Patent L.R. 3', desc: 'Patent cases have mandatory claim construction procedures and Markman hearing schedule.', impact: 'Patent-specific procedures' },
      { frcp: 'Rule 16', local: 'Civil L.R. 16-10', desc: 'ADR referral mandatory in most civil cases within 150 days of filing.', impact: 'Mandatory ADR' },
    ]},
    { court: 'C.D. Cal.', deviations: [
      { frcp: 'Rule 7', local: 'L.R. 11-6', desc: 'All motions require a notice of motion separate from the memorandum.', impact: 'Formatting requirement' },
      { frcp: 'Rule 56', local: 'L.R. 56-1', desc: 'Statement of uncontroverted facts required.', impact: 'Additional filing' },
    ]},
    { court: 'D.N.J.', deviations: [
      { frcp: 'Rule 56', local: 'L.Civ.R. 56.1', desc: 'Statement of material facts required. Each fact in separately numbered paragraph with citation.', impact: 'Additional filing' },
      { frcp: 'Rule 7', local: 'L.Civ.R. 7.2(b)', desc: 'Brief in support of dispositive motion limited to 40 pages; non-dispositive limited to 15 pages.', impact: 'Page limits' },
      { frcp: 'Rule 37', local: 'L.Civ.R. 37.1', desc: 'Certification of good-faith conference required with all discovery motions; meet-and-confer letter mandatory.', impact: 'Pre-filing conference' },
    ]},
    { court: 'E.D. Tex.', deviations: [
      { frcp: 'Rule 16', local: 'Local Rule CV-16', desc: 'Docket control order issued early. Case set on firm trial date. Continuances disfavored.', impact: 'Firm deadlines' },
      { frcp: 'Rule 26', local: 'Patent Rules', desc: 'Mandatory infringement/invalidity contentions with specific deadlines. Early Markman hearing.', impact: 'Patent-specific' },
      { frcp: 'Rule 56', local: 'Local Rule CV-56', desc: 'MSJ must include appendix with evidence. Strict summary-judgment page limits.', impact: 'Appendix required' },
    ]},
    { court: 'E.D. Va.', deviations: [
      { frcp: 'Rule 16', local: 'Local Rule 16(B)', desc: '"Rocket Docket" — extremely compressed schedule. Trial typically within 6-9 months of filing.', impact: 'Rocket docket' },
      { frcp: 'Rule 12', local: 'Local Rule 7(F)', desc: 'Failure to file timely responsive memo = motion treated as conceded.', impact: 'Auto-concession' },
      { frcp: 'Rule 56', local: 'Local Rule 56(B)', desc: 'MSJ opposition due 21 days; brief limit 30 pages. Strict schedule enforcement.', impact: 'Tight deadlines' },
      { frcp: 'Rule 26', local: 'Local Rule 26(C)', desc: 'Discovery limited to 120 days in many cases. Extensions very rare.', impact: 'Compressed discovery' },
    ]},
  ];

  const [activeCourt, setActiveCourt] = useState('S.D.N.Y.');
  const [compareCourt, setCompareCourt] = useState(null);
  const court = LOCAL_RULES.find(c => c.court === activeCourt);
  const court2 = compareCourt ? LOCAL_RULES.find(c => c.court === compareCourt) : null;

  return (
    <div>
      <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', flexWrap: 'wrap', alignItems: 'center' }}>
        {LOCAL_RULES.map(c => (
          <button key={c.court} onClick={() => { setActiveCourt(c.court); setCompareCourt(null); }} style={{ ...cal.filterBtn, ...(activeCourt === c.court ? cal.filterBtnActive : {}) }}>{c.court}</button>
        ))}
        <span style={{ fontSize: '10px', color: T.color.text.tertiary, marginLeft: '8px' }}>|</span>
        <select value={compareCourt || ''} onChange={e => setCompareCourt(e.target.value || null)} style={{ ...cal.filterBtn, padding: '4px 8px' }}>
          <option value="">Compare with…</option>
          {LOCAL_RULES.filter(c => c.court !== activeCourt).map(c => <option key={c.court} value={c.court}>{c.court}</option>)}
        </select>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: compareCourt ? '1fr 1fr' : '1fr', gap: '16px' }}>
        <div style={cal.card}>
          <div style={{ ...cal.cardH, background: cal.amberBg }}>
            <span style={{ color: cal.amber }}>{activeCourt} — Local Rule Deviations</span>
            <span style={{ fontSize: '10px', color: T.color.text.tertiary }}>{court?.deviations.length} deviations</span>
          </div>
          {court?.deviations.map((d, i) => (
            <div key={i} style={{ padding: '10px 16px', borderBottom: `1px solid ${T.color.border.light}` }}>
              <div style={{ display: 'flex', gap: '8px', alignItems: 'baseline', marginBottom: '4px' }}>
                <span style={{ fontFamily: T.font.mono, fontWeight: 600, color: T.color.text.tertiary, fontSize: '11px' }}>{d.frcp}</span>
                <span style={{ fontSize: '11px', color: T.color.text.tertiary }}>→</span>
                <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: cal.amber, fontSize: '11px' }}>{d.local}</span>
                <span style={{ ...cal.tag, background: cal.amberBg, color: cal.amber }}>{d.impact}</span>
              </div>
              <div style={{ fontSize: '11px', color: T.color.text.secondary, lineHeight: 1.4 }}>{d.desc}</div>
            </div>
          ))}
        </div>
        {court2 && (
          <div style={cal.card}>
            <div style={{ ...cal.cardH, background: 'rgba(37,99,235,0.06)' }}>
              <span style={{ color: '#2563EB' }}>{compareCourt} — Local Rule Deviations</span>
              <span style={{ fontSize: '10px', color: T.color.text.tertiary }}>{court2.deviations.length} deviations</span>
            </div>
            {court2.deviations.map((d, i) => (
              <div key={i} style={{ padding: '10px 16px', borderBottom: `1px solid ${T.color.border.light}` }}>
                <div style={{ display: 'flex', gap: '8px', alignItems: 'baseline', marginBottom: '4px' }}>
                  <span style={{ fontFamily: T.font.mono, fontWeight: 600, color: T.color.text.tertiary, fontSize: '11px' }}>{d.frcp}</span>
                  <span style={{ fontSize: '11px', color: T.color.text.tertiary }}>→</span>
                  <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: '#2563EB', fontSize: '11px' }}>{d.local}</span>
                  <span style={{ ...cal.tag, background: 'rgba(37,99,235,0.06)', color: '#2563EB' }}>{d.impact}</span>
                </div>
                <div style={{ fontSize: '11px', color: T.color.text.secondary, lineHeight: 1.4 }}>{d.desc}</div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

// ── CHEAT SHEET ──
function FRCPCheatSheet() {
  const [severityFilter, setSeverityFilter] = useState('all');
  const [csSearch, setCsSearch] = useState('');

  const CRITICAL_DEADLINES = [
    { rule: 'Rule 4(m)', deadline: '90 days', event: 'Serve complaint', consequence: 'Dismissal without prejudice', severity: 'critical' },
    { rule: 'Rule 12(a)', deadline: '21 days', event: 'File answer', consequence: 'Default judgment risk', severity: 'critical' },
    { rule: 'Rule 15(a)', deadline: '21 days', event: 'Amend as of right', consequence: 'Need court leave', severity: 'high' },
    { rule: 'Rule 26(a)(1)', deadline: '14 days after 26(f)', event: 'Initial disclosures', consequence: 'Sanctions under Rule 37', severity: 'critical' },
    { rule: 'Rule 33(b)(2)', deadline: '30 days', event: 'Interrogatory responses', consequence: 'Waiver of objections', severity: 'high' },
    { rule: 'Rule 34(b)(2)', deadline: '30 days', event: 'Production responses', consequence: 'Waiver of objections', severity: 'high' },
    { rule: 'Rule 36(a)(3)', deadline: '30 days', event: 'RFA responses', consequence: 'DEEMED ADMITTED', severity: 'critical' },
    { rule: 'Rule 38(b)', deadline: '14 days', event: 'Jury demand', consequence: 'WAIVER of jury right', severity: 'critical' },
    { rule: 'Rule 45(d)(2)(B)', deadline: '14 days', event: 'Subpoena objection', consequence: 'Waiver of objections', severity: 'high' },
    { rule: 'Rule 50(b)', deadline: '28 days', event: 'Renewed JMOL', consequence: 'Cannot challenge sufficiency on appeal', severity: 'critical' },
    { rule: 'Rule 52(b)', deadline: '28 days', event: 'Amend findings (bench trial)', consequence: 'Waived', severity: 'high' },
    { rule: 'Rule 56(b)', deadline: '30 days after discovery', event: 'File MSJ', consequence: 'Lost right to file', severity: 'high' },
    { rule: 'Rule 59(b)', deadline: '28 days', event: 'New trial motion', consequence: 'Waived', severity: 'critical' },
    { rule: 'Rule 59(e)', deadline: '28 days', event: 'Alter/amend judgment', consequence: 'Waived', severity: 'critical' },
    { rule: 'FRAP 4(a)(1)', deadline: '30 days', event: 'Notice of appeal', consequence: 'LOSS of appellate rights', severity: 'critical' },
  ];

  const sevColor = { critical: '#C23030', high: '#D97706' };

  const filtered = CRITICAL_DEADLINES.filter(d => {
    if (severityFilter !== 'all' && d.severity !== severityFilter) return false;
    if (csSearch) {
      const q = csSearch.toLowerCase();
      return d.rule.toLowerCase().includes(q) || d.event.toLowerCase().includes(q) || d.consequence.toLowerCase().includes(q);
    }
    return true;
  });

  return (
    <div>
      <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', alignItems: 'center' }}>
        <input style={{ height: '32px', border: `1px solid ${T.color.border.light}`, borderRadius: T.radius.md, padding: '0 12px', fontSize: '12px', fontFamily: T.font.family, background: T.color.bg.card, color: T.color.text.primary, outline: 'none', width: '200px' }} placeholder="Search deadlines…" value={csSearch} onChange={e => setCsSearch(e.target.value)} />
        <button onClick={() => setSeverityFilter('all')} style={{ ...cal.filterBtn, ...(severityFilter === 'all' ? cal.filterBtnActive : {}) }}>All</button>
        <button onClick={() => setSeverityFilter('critical')} style={{ ...cal.filterBtn, ...(severityFilter === 'critical' ? { background: '#C23030', color: '#fff', borderColor: '#C23030' } : {}) }}>Critical Only</button>
        <button onClick={() => setSeverityFilter('high')} style={{ ...cal.filterBtn, ...(severityFilter === 'high' ? { background: '#D97706', color: '#fff', borderColor: '#D97706' } : {}) }}>High Only</button>
        <span style={{ fontSize: '10px', color: T.color.text.tertiary, marginLeft: '8px' }}>{filtered.length} deadlines</span>
      </div>

      <div style={{ ...cal.card, borderColor: '#C2303020' }}>
        <div style={{ ...cal.cardH, background: 'rgba(194,48,48,0.03)' }}>
          <span style={{ color: '#C23030', fontWeight: 700 }}>! Critical FRCP Deadlines — Malpractice Prevention Quick Reference</span>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '90px 100px 1fr 1fr 70px', padding: '6px 16px', background: T.color.bg.secondary, borderBottom: `1px solid ${T.color.border.light}`, fontSize: '9px', fontWeight: 600, color: T.color.text.tertiary, textTransform: 'uppercase', letterSpacing: '0.06em', gap: '8px' }}>
          <span>Rule</span><span>Deadline</span><span>Event</span><span>Consequence of Missing</span><span>Severity</span>
        </div>
        {filtered.map((d, i) => (
          <div key={i} style={{ display: 'grid', gridTemplateColumns: '90px 100px 1fr 1fr 70px', padding: '8px 16px', borderBottom: `1px solid ${T.color.border.light}`, fontSize: '11px', alignItems: 'center', gap: '8px', borderLeft: `3px solid ${sevColor[d.severity]}` }}>
            <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: cal.amber, cursor: 'pointer' }} onClick={() => {
              const ruleId = d.rule.replace('Rule ', 'R').replace('(a)', '').replace('(b)', '').replace('(e)', '').replace(/\(.*\)/, '').trim();
              if (window.__navigateToRule) window.__navigateToRule(ruleId);
            }}>{d.rule}</span>
            <span style={{ fontFamily: T.font.mono, fontWeight: 700, color: T.color.text.primary }}>{d.deadline}</span>
            <span style={{ color: T.color.text.primary }}>{d.event}</span>
            <span style={{ color: sevColor[d.severity], fontWeight: 600 }}>{d.consequence}</span>
            <span style={{ ...cal.tag, background: `${sevColor[d.severity]}10`, color: sevColor[d.severity] }}>{d.severity}</span>
          </div>
        ))}
      </div>

      <div style={{ ...cal.card, marginTop: '16px' }}>
        <div style={{ padding: '12px 16px', background: cal.amberBg, fontSize: '12px', color: T.color.text.secondary, lineHeight: 1.5 }}>
          <div style={{ fontSize: '10px', fontWeight: 600, color: cal.amber, textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '4px' }}>◆ Malpractice Alert</div>
          The top 3 missed deadlines leading to malpractice claims: (1) Statute of limitations, (2) Appeal deadlines under FRAP 4, (3) RFA deemed admissions under Rule 36. Arbiter's Calendar Platform auto-calculates and alerts on all three. Never rely on memory alone.
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { FRCPBrowser, FRCPChainCalc, FRCPJurisdictions, FRCPCheatSheet });
