/* ============================================================
   Inbox Triage & Route — desk app (React + live Claude)
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;

/* ---------- tiny inline icon set (RMAI: light line, 1.8 stroke) ---------- */
const Ico = ({ d, paths, w = 16, fill = false, style }) => (
  <svg width={w} height={w} viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" style={style}>
    {d && <path d={d} />}
    {paths}
  </svg>
);
const IconCheck = (p) => <Ico {...p} d="M20 6 9 17l-5-5" />;
const IconSend = (p) => <Ico {...p} paths={<><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></>} />;
const IconEdit = (p) => <Ico {...p} paths={<><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/></>} />;
const IconRoute = (p) => <Ico {...p} paths={<><circle cx="6" cy="19" r="2.5"/><circle cx="18" cy="5" r="2.5"/><path d="M8.5 19H14a3.5 3.5 0 0 0 0-7H9a3.5 3.5 0 0 1 0-7h6.5"/></>} />;
const IconAlert = (p) => <Ico {...p} paths={<><path d="M10.3 3.3 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.3a2 2 0 0 0-3.4 0Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></>} />;
const IconShield = (p) => <Ico {...p} paths={<><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z"/></>} />;
const IconLock = (p) => <Ico {...p} paths={<><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></>} />;
const IconBook = (p) => <Ico {...p} paths={<><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z"/></>} />;
const IconInbox = (p) => <Ico {...p} paths={<><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.5 5.5 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.5-6.5A2 2 0 0 0 16.8 4H7.2a2 2 0 0 0-1.7 1.5Z"/></>} />;
const IconBolt = (p) => <Ico {...p} d="M13 2 3 14h9l-1 8 10-12h-9l1-8Z" />;
const IconArrow = (p) => <Ico {...p} d="M5 12h14M13 6l6 6-6 6" />;

/* ---------- Claude classification ----------
   The pure prompt build / JSON parse / normalise live in triage-core.js (UMD,
   node-tested). This async wrapper just calls the live proxy (window.claude.complete,
   from claude-shim.js) and hands the raw text to the core. On any failure the caller
   (runClassify) catches and degrades to msg.seed. */
async function classify(msg) {
  if (!window.claude || !window.claude.complete) throw new Error('no-claude');
  const content = TriageCore.buildPrompt(msg, {
    taxonomy: TAXONOMY, routes: ROUTES, allQueues: ALL_QUEUES,
    escalationCategories: ESCALATION_CATEGORIES, knowledge: KNOWLEDGE,
  });
  // Canonical inbox messages are served from committed fixtures (0 tokens); the
  // simulated new arrival (INBOUND_NEW) is the live "watch it classify" moment.
  const scenarioId = (msg.id === INBOUND_NEW.id) ? undefined : msg.id;
  const { completion, source } = await window.claude.complete({ messages: [{ role: 'user', content }], scenarioId });
  if (source === 'fallback') return { ...msg.seed, live: false, source: 'fallback' };
  const data = TriageCore.normalizeClassification(TriageCore.parseJSON(completion), msg.seed);
  return { ...data, source: source || 'live' };
}

/* ---------- small presentational bits ---------- */
const URGENCY_LABEL = { high: 'Urgent', medium: 'Medium', low: 'Routine' };

function UrgencyPill({ u }) {
  return <span className="upill" data-u={u}><span className="d" />{URGENCY_LABEL[u]}</span>;
}

function Shim({ w, style }) {
  return <div className="shim shim-line" style={{ width: w, ...style }} />;
}

/* ---------- Queue row ---------- */
function QueueRow({ msg, cls, selected, sent, flash, appear, onClick }) {
  const u = cls.urgency;
  return (
    <li className={`q-row${selected ? ' sel' : ''}${flash ? ' flash' : ''}${appear ? ' appear' : ''}`}
        data-u={u} onClick={onClick} style={sent ? { opacity: 0.5 } : null}>
      <div className="q-stripe" />
      <div className="q-main">
        <div className="q-line1">
          <span className="q-name">{msg.name}</span>
          <span className="q-time">{msg.t}</span>
        </div>
        <p className="q-prev">{msg.subject}</p>
        <div className="q-line3">
          <span className="tag">{cls.intent}</span>
          <span className="route"><span className="arr">→</span>{cls.route}</span>
          {cls.escalate && <span className="q-esc"><IconAlert w={11} />escalate</span>}
        </div>
      </div>
      <div className="q-side">
        {sent
          ? <span className="badge-status ready"><span className="d" />Sent</span>
          : <UrgencyPill u={u} />}
      </div>
    </li>
  );
}

/* ---------- Center: classification ---------- */
function ClassificationCard({ cls }) {
  const [w, setW] = useState(0);
  useEffect(() => { const t = setTimeout(() => setW(cls.confidence), 80); return () => clearTimeout(t); }, [cls.confidence]);
  return (
    <div className="cls">
      <div className="cls-row">
        <div className="cls-k">Intent</div>
        <div className="cls-v">
          <div className="cls-intent">{cls.intent}</div>
          <div className="conf">
            <span className="eyebrow" style={{ color: 'var(--rmai-fg-mut)' }}>Confidence</span>
            <span className="conf-bar"><i style={{ width: w + '%' }} /></span>
            <span className="conf-n">{cls.confidence}%</span>
          </div>
        </div>
      </div>
      <div className="cls-row">
        <div className="cls-k">Urgency</div>
        <div className="cls-v"><UrgencyPill u={cls.urgency} /></div>
      </div>
      <div className="cls-row">
        <div className="cls-k">Why</div>
        <div className="cls-v cls-why">{cls.reason}</div>
      </div>
      <div className="cls-row">
        <div className="cls-k">Route</div>
        <div className="cls-v">
          <span className="cls-route"><span className="arr">→</span><b>{cls.route}</b></span>
        </div>
      </div>
      {cls.escalate && (
        <div className="cls-row">
          <div className="cls-k" style={{ color: 'var(--u-high)' }}>Flag</div>
          <div className="cls-v">
            <div className="esc-flag">
              <IconAlert w={17} />
              <div className="et"><b>Escalate — do not auto-reply.</b> {cls.escalate_reason}</div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function MessagePanel({ msg, cls, status }) {
  if (!msg) return (
    <div className="empty">
      <IconInbox w={30} />
      <div className="t">Select a message</div>
      <div className="s">Pick an item from the queue to see the original, the AI's classification, and a drafted reply.</div>
    </div>
  );
  const initials = msg.name.split(' ').map(p => p[0]).slice(0, 2).join('').toUpperCase();
  return (
    <div className="msg-wrap">
      <div className="msg-from">
        <div className="avatar">{initials}</div>
        <div className="msg-id">
          <div className="nm">{msg.name}</div>
          <div className="em">{msg.email}</div>
        </div>
        <div className="msg-meta">
          <div className="ch"><span className="mono">{msg.channel}</span></div>
          <div>{msg.t === 'now' ? 'just now' : msg.t}</div>
        </div>
      </div>
      <div className="msg-subject">{msg.subject}</div>
      <div className="msg-body">{msg.body}</div>

      <div className="sec-label">
        <span className="eyebrow" style={{ color: 'var(--rmai-purple)' }}>Classification</span>
        <span className="ln" />
        {status === 'done' && cls.live && <span className="eyebrow" style={{ color: 'var(--rmai-fg-mut)' }}>{cls.source === 'canned' ? 'cached · claude' : 'live · claude'}</span>}
      </div>

      {status === 'processing' ? (
        <div className="shim-card">
          <div className="proc-note"><span className="spin" />Reading message · classifying intent &amp; urgency · checking routing &amp; escalation rules…</div>
          <Shim w="38%" /><Shim w="62%" /><Shim w="48%" style={{ marginBottom: 0 }} />
        </div>
      ) : status === 'done' ? (
        <ClassificationCard cls={cls} />
      ) : null}
    </div>
  );
}

/* ---------- Right: draft / escalation + actions ---------- */
function DraftPanel({ msg, cls, status, sent, onApprove, onReassign, onEscalate, onEditSave }) {
  const [typed, setTyped] = useState('');
  const [editing, setEditing] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const typedIds = useRef(new Set());
  const editRef = useRef(null);

  const draft = cls && cls.draft_reply ? cls.draft_reply : '';
  const escalated = cls && cls.escalate;
  const doneRoutine = status === 'done' && !escalated && !!draft;

  // typewriter — only the first time a routine draft is shown
  useEffect(() => {
    if (!doneRoutine || !msg) return;
    if (typedIds.current.has(msg.id)) { setTyped(draft); return; }
    setTyped('');
    let i = 0;
    const step = () => {
      i += Math.max(1, Math.round(draft.length / 90));
      setTyped(draft.slice(0, i));
      if (i < draft.length) { timer = setTimeout(step, 14); }
      else { typedIds.current.add(msg.id); }
    };
    let timer = setTimeout(step, 220);
    return () => clearTimeout(timer);
  }, [doneRoutine, msg && msg.id, draft]);

  useEffect(() => { setEditing(false); setMenuOpen(false); }, [msg && msg.id]);

  if (!msg) return (
    <div className="empty"><IconSend w={28} /><div className="t">No draft yet</div>
      <div className="s">Once a message is selected and classified, the suggested reply appears here for your approval.</div></div>
  );

  if (sent) return (
    <div className="empty">
      <div className="tick" style={{ width: 40, height: 40, borderRadius: 999, background: 'var(--rmai-green)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <IconCheck w={20} style={{ color: '#fff' }} />
      </div>
      <div className="t" style={{ marginTop: 4 }}>Reply sent to {msg.name.split(' ')[0]}</div>
      <div className="s">Approved and sent by you. The agent drafted it but never sends on its own.</div>
    </div>
  );

  const typingDone = typed.length >= draft.length;

  return (
    <div className="draft-wrap">
      <div className="draft-scroll">
        {status === 'processing' ? (
          <>
            <div className="proc-note"><span className="spin" />Drafting a grounded reply…</div>
            <div className="shim-card"><Shim w="90%" /><Shim w="80%" /><Shim w="86%" /><Shim w="40%" style={{ marginBottom: 0 }} /></div>
          </>
        ) : escalated ? (
          <>
            <div className="draft-meta">
              <span className="badge-status hold"><IconAlert w={12} style={{ marginRight: 2 }} />Held for a person</span>
            </div>
            <div className="esc-panel">
              <div className="esc-head"><IconShield w={19} /><span className="h">Escalated — no auto-reply</span></div>
              <div className="esc-body">
                <p className="reason"><b>Why:</b> {cls.escalate_reason}</p>
                <div className="esc-rule">
                  <IconAlert w={15} />
                  <span>Sensitive categories are never auto-answered. This message is routed to <b>{cls.route}</b> for a person to handle directly.</span>
                </div>
                <p className="no-draft">No send-ready draft is offered for escalated messages — by design. Use <b>Reassign</b> if it belongs with a different person.</p>
              </div>
            </div>
          </>
        ) : doneRoutine ? (
          <>
            <div className="draft-meta">
              <span className="badge-status ready"><span className="d" />Send-ready</span>
              <span className="who">drafted for <b>{msg.name.split(' ')[0]}</b></span>
            </div>
            <div className="draft-box">
              <div
                className={`draft-text${editing ? ' editing' : ''}`}
                ref={editRef}
                contentEditable={editing}
                suppressContentEditableWarning
                onBlur={(e) => { if (editing) { onEditSave(msg.id, e.target.innerText); setEditing(false); } }}
              >
                {editing ? draft : typed}
                {!editing && !typingDone && <span className="cursor" />}
              </div>
              {cls.citation && (
                <div className="cite">
                  <IconBook w={14} className="ic" />
                  <span className="lbl">Grounded in</span>
                  <span className="src">{cls.citation}</span>
                </div>
              )}
            </div>
            <div className="ground-note">
              <IconShield w={14} />
              <span>Drafted only from approved reply knowledge{cls.citation ? '' : ' — nothing matched, so this is a holding reply that routes to the team'}. Edit before sending if needed.</span>
            </div>
          </>
        ) : null}
      </div>

      {status === 'done' && (
        <div className="actions">
          {escalated ? (
            <>
              <div className="actions-row">
                <button className="btn btn--danger" style={{ background: 'var(--u-high)', color: '#fff', borderColor: 'var(--u-high)' }} onClick={() => onApprove(msg.id, true)}>
                  <IconArrow w={15} />Escalate to {cls.route}
                </button>
              </div>
              <div className="actions-sub">
                <ReassignButton cls={cls} open={menuOpen} setOpen={setMenuOpen} onPick={(q) => { onReassign(msg.id, q); setMenuOpen(false); }} />
              </div>
            </>
          ) : (
            <>
              <div className="actions-row">
                <button className="btn btn--cta" disabled={!typingDone} onClick={() => onApprove(msg.id, false)}>
                  <IconSend w={15} />Approve &amp; Send
                </button>
              </div>
              <div className="actions-sub">
                <button className="btn btn--secondary" onClick={() => {
                  setEditing(true); setTimeout(() => editRef.current && editRef.current.focus(), 10);
                }}><IconEdit w={14} />Edit</button>
                <ReassignButton cls={cls} open={menuOpen} setOpen={setMenuOpen} onPick={(q) => { onReassign(msg.id, q); setMenuOpen(false); }} />
                <button className="btn btn--danger" onClick={() => onEscalate(msg.id)}><IconAlert w={14} />Escalate</button>
              </div>
            </>
          )}
          <div className="safety"><IconLock w={12} />Nothing is sent without your approval</div>
        </div>
      )}
    </div>
  );
}

function ReassignButton({ cls, open, setOpen, onPick }) {
  return (
    <div className="reassign" style={{ flex: '1 1 auto' }}>
      {open && (
        <div className="menu">
          <div className="mh">Reassign queue</div>
          {ALL_QUEUES.map(q => (
            <button key={q} className={q === cls.route ? 'cur' : ''} onClick={() => onPick(q)}>
              <IconRoute w={14} />{q}
              {q === cls.route && <span className="rt">current</span>}
            </button>
          ))}
        </div>
      )}
      <button className="btn btn--secondary" style={{ width: '100%', justifyContent: 'center' }} onClick={() => setOpen(o => !o)}>
        <IconRoute w={14} />Reassign
      </button>
    </div>
  );
}

/* ---------- Toasts ---------- */
function Toasts({ items, onDone }) {
  return (
    <div className="toast-wrap">
      {items.map(t => <Toast key={t.id} t={t} onDone={onDone} />)}
    </div>
  );
}
function Toast({ t, onDone }) {
  const [out, setOut] = useState(false);
  useEffect(() => {
    const a = setTimeout(() => setOut(true), 3400);
    const b = setTimeout(() => onDone(t.id), 3650);
    return () => { clearTimeout(a); clearTimeout(b); };
  }, []);
  return (
    <div className={`toast${out ? ' out' : ''}`}>
      <span className="tick"><IconCheck w={13} style={{ color: '#fff' }} /></span>
      <span><b>{t.title}</b>{t.sub && <span className="sub"> · {t.sub}</span>}</span>
    </div>
  );
}

/* ---------- urgency sort ----------
   The pure sorter lives in triage-core.js (node-tested); used via TriageCore.sortByUrgency. */

/* ============================================================
   App
   ============================================================ */
function App() {
  const clsOf = useCallback((m, classifications) => {
    const c = classifications && classifications[m.id];
    return (c && c.data) ? c.data : { ...m.seed, live: false };
  }, []);

  const [classifications, setClassifications] = useState(() => {
    // seed everything as 'done' from seed data so the queue is instantly tagged & sorted
    const o = {};
    [...MESSAGES, INBOUND_NEW].forEach(m => { o[m.id] = { status: 'done', data: { ...m.seed, live: false } }; });
    return o;
  });
  const clsMap = useRef(classifications); clsMap.current = classifications;
  const getCls = (m) => clsOf(m, clsMap.current);

  const [order, setOrder] = useState(() => TriageCore.sortByUrgency(MESSAGES, m => ({ urgency: m.seed.urgency })));
  const [selectedId, setSelectedId] = useState(DEFAULT_SELECTED);
  const [sentIds, setSentIds] = useState(new Set());
  const [toasts, setToasts] = useState([]);
  const [flashId, setFlashId] = useState(null);
  const [showIntro, setShowIntro] = useState(true);
  const [simulating, setSimulating] = useState(false);
  const queueBodyRef = useRef(null);
  const liveRequested = useRef(new Set());

  const pushToast = (title, sub) => {
    const id = 'to-' + Date.now() + Math.random();
    setToasts(t => [...t, { id, title, sub }]);
  };

  // run a real Claude classification for one message, falling back to seed
  const runClassify = useCallback(async (msg, { reorder = false } = {}) => {
    setClassifications(c => ({ ...c, [msg.id]: { status: 'processing', data: c[msg.id] && c[msg.id].data } }));
    let data;
    try { data = await classify(msg); }
    catch (e) { data = { ...msg.seed, live: false }; }
    setClassifications(c => ({ ...c, [msg.id]: { status: 'done', data } }));
    if (reorder) {
      setTimeout(() => {
        setOrder(prev => {
          const map = { ...clsMap.current, [msg.id]: { status: 'done', data } };
          return TriageCore.sortByUrgency(prev, m => clsOf(m, map));
        });
        setFlashId(msg.id);
        if (queueBodyRef.current) queueBodyRef.current.scrollTo({ top: 0, behavior: 'smooth' });
        setTimeout(() => setFlashId(null), 1700);
      }, 60);
    }
  }, [clsOf]);

  // classify the default selection live on first load
  useEffect(() => {
    const m = MESSAGES.find(x => x.id === DEFAULT_SELECTED);
    if (m && !liveRequested.current.has(m.id)) {
      liveRequested.current.add(m.id);
      runClassify(m);
    }
  }, []);

  const allById = {};
  [...MESSAGES, INBOUND_NEW].forEach(m => { allById[m.id] = m; });
  const selectedMsg = allById[selectedId];
  const selCls = selectedMsg ? getCls(selectedMsg) : null;
  const selStatus = (classifications[selectedId] && classifications[selectedId].status) || 'done';

  const handleSelect = (id) => {
    setSelectedId(id);
    const m = allById[id];
    if (m && !liveRequested.current.has(id) && !sentIds.has(id)) {
      liveRequested.current.add(id);
      runClassify(m);
    }
  };

  const handleApprove = (id, escalateSend) => {
    const m = allById[id];
    setSentIds(s => new Set(s).add(id));
    if (escalateSend) pushToast('Escalated to ' + getCls(m).route, 'A person will handle ' + m.name.split(' ')[0] + '’s message');
    else pushToast('Reply sent to ' + m.name.split(' ')[0], getCls(m).citation ? 'Cited ' + getCls(m).citation : 'Approved by you');
    // advance to next unsent
    const next = order.find(x => x.id !== id && !sentIds.has(x.id));
    if (next) setTimeout(() => setSelectedId(next.id), 240);
  };

  const handleReassign = (id, q) => {
    setClassifications(c => ({ ...c, [id]: { status: 'done', data: { ...c[id].data, route: q } } }));
    pushToast('Re-routed to ' + q, 'Queue overridden — still nothing sent');
  };

  const handleEscalate = (id) => {
    setClassifications(c => ({ ...c, [id]: { status: 'done', data: { ...c[id].data, escalate: true, escalate_reason: c[id].data.escalate_reason || 'Manually escalated by the coordinator for a person to handle.', draft_reply: '', citation: null } } }));
    pushToast('Escalated', 'Marked for a person — no auto-reply');
  };

  const handleEditSave = (id, text) => {
    setClassifications(c => ({ ...c, [id]: { status: 'done', data: { ...c[id].data, draft_reply: text } } }));
  };

  const simulateNew = () => {
    if (simulating || order.find(x => x.id === INBOUND_NEW.id)) return;
    setSimulating(true);
    // 1) arrives at the BOTTOM in arrival order
    setOrder(prev => [...prev, INBOUND_NEW]);
    setClassifications(c => ({ ...c, [INBOUND_NEW.id]: { status: 'processing', data: undefined } }));
    setSelectedId(INBOUND_NEW.id);
    liveRequested.current.add(INBOUND_NEW.id);
    if (queueBodyRef.current) setTimeout(() => queueBodyRef.current.scrollTo({ top: queueBodyRef.current.scrollHeight, behavior: 'smooth' }), 80);
    // 2) after a beat, classify live + re-sort so it jumps to the top
    setTimeout(() => {
      runClassify(INBOUND_NEW, { reorder: true }).then(() => setSimulating(false));
    }, 1100);
  };

  const counts = { high: 0, medium: 0, low: 0 };
  order.forEach(m => { if (!sentIds.has(m.id)) counts[getCls(m).urgency]++; });
  const openCount = order.filter(m => !sentIds.has(m.id)).length;

  return (
    <div className="app">
      {showIntro && (
        <div className="intro">
          <IconBolt w={15} />
          <span><b>Inbox Triage &amp; Route</b> — the agent classifies intent &amp; urgency, routes each message, and drafts a grounded reply for your approval. Sensitive items are <b>escalated, never auto-answered</b>. Try <span className="e">Simulate new message</span> to watch an urgent one jump the queue.</span>
          <button className="x" onClick={() => setShowIntro(false)} aria-label="Dismiss">×</button>
        </div>
      )}

      <header className="hdr">
        <div className="hdr-left">
          <div className="wordmark"><div className="l1">real minds,</div><div className="l2">artificial intelligence</div></div>
          <div className="hdr-sep" />
          <div className="hdr-deskname">Triage &amp; Route<span className="sub">Shared inbox · coordinator desk</span></div>
        </div>
        <div className="hdr-right">
          <span className="hdr-meta">{openCount} open · {counts.high} urgent</span>
          <span className="live"><span className="dot" />agent live</span>
          <button className="btn btn--dark-ghost" onClick={simulateNew} disabled={simulating || !!order.find(x => x.id === INBOUND_NEW.id)}>
            <IconBolt w={14} />{simulating ? 'Triaging…' : 'Simulate new message'}
          </button>
        </div>
      </header>

      <div className="desk">
        {/* LEFT — queue */}
        <section className="col">
          <div className="col-hd">
            <div className="ttl"><h2>Queue</h2><span className="count">{openCount} open</span></div>
          </div>
          <div className="q-toolbar">
            <span className="q-sort"><IconBolt w={12} />sorted by urgency</span>
            <span style={{ flex: 1 }} />
            <span className="q-chip" data-u="high"><span style={{ color: 'var(--u-high)' }}>●</span> {counts.high} <span className="n">urgent</span></span>
            <span className="q-chip"><span style={{ color: 'var(--u-med)' }}>●</span> {counts.medium}</span>
            <span className="q-chip"><span style={{ color: 'var(--u-low)' }}>●</span> {counts.low}</span>
          </div>
          <div className="col-body" ref={queueBodyRef}>
            <ul className="q-list">
              {order.map(m => (
                <QueueRow key={m.id} msg={m} cls={getCls(m)}
                  selected={m.id === selectedId} sent={sentIds.has(m.id)}
                  flash={m.id === flashId} appear={m.id === flashId}
                  onClick={() => handleSelect(m.id)} />
              ))}
            </ul>
          </div>
        </section>

        {/* CENTER — message + classification */}
        <section className="col">
          <div className="col-hd">
            <div className="ttl"><h2>Message</h2></div>
            <span className="count">{selectedMsg ? selectedMsg.id : ''}</span>
          </div>
          <div className="col-body">
            <MessagePanel msg={sentIds.has(selectedId) ? selectedMsg : selectedMsg} cls={selCls} status={selStatus} />
          </div>
        </section>

        {/* RIGHT — draft / escalation + actions */}
        <section className="col">
          <div className="col-hd">
            <div className="ttl"><h2>Draft reply</h2></div>
            {selCls && selStatus === 'done' && (selCls.escalate
              ? <span className="count" style={{ color: 'var(--u-high)' }}>escalation</span>
              : <span className="count">human-approved send</span>)}
          </div>
          <div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
            <DraftPanel msg={selectedMsg} cls={selCls} status={selStatus}
              sent={sentIds.has(selectedId)}
              onApprove={handleApprove} onReassign={handleReassign}
              onEscalate={handleEscalate} onEditSave={handleEditSave} />
          </div>
        </section>
      </div>

      <Toasts items={toasts} onDone={(id) => setToasts(t => t.filter(x => x.id !== id))} />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
