/* @jsxRuntime classic */
/* @jsx React.createElement */
// Orchestra — Frontend v10  (API-wired)
// All data comes from the FastAPI backend. No seed data, no localStorage, no in-browser LLM calls.
// The simulation engine (buildSimEvents) is kept — it runs client-only as a structural dry-run.
// ─────────────────────────────────────────────────────────────────────────────────────────────

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ─── Backend URL ────────────────────────────────────────────────────────────────
// Empty string = same origin (Nginx proxies /api/* to FastAPI).
// To point at a remote server during local dev, set e.g. 'http://YOUR_IP'
const BACKEND = '';

// ─── API helper ─────────────────────────────────────────────────────────────────
async function api(method, path, body) {
  const opts = {
    method,
    headers: { 'Content-Type': 'application/json' },
  };
  if (body !== undefined) opts.body = JSON.stringify(deepSnake(body));
  const res = await fetch(BACKEND + path, opts);
  if (!res.ok) {
    const text = await res.text().catch(() => '');
    throw new Error(`API ${method} ${path} → ${res.status}: ${text}`);
  }
  if (res.status === 204) return null;
  const json = await res.json();
  return deepCamel(json);
}

// ─── Case converters ─────────────────────────────────────────────────────────────
// Python returns snake_case; React uses camelCase. Convert at the boundary.
function toCamel(s) { return s.replace(/_([a-z])/g, (_, c) => c.toUpperCase()); }
function toSnake(s) { return s.replace(/([A-Z])/g, '_$1').toLowerCase(); }

function deepCamel(obj) {
  if (Array.isArray(obj)) return obj.map(deepCamel);
  if (obj && typeof obj === 'object') {
    const out = {};
    for (const k of Object.keys(obj)) out[toCamel(k)] = deepCamel(obj[k]);
    return out;
  }
  return obj;
}
function deepSnake(obj) {
  if (Array.isArray(obj)) return obj.map(deepSnake);
  if (obj && typeof obj === 'object') {
    const out = {};
    for (const k of Object.keys(obj)) out[toSnake(k)] = deepSnake(obj[k]);
    return out;
  }
  return obj;
}

// ─── Map a raw run record from the backend into UI shape ─────────────────────────
function mapRunData(raw) {
  if (!raw) return null;
  return {
    id: raw.id,
    wfId: raw.wfId,
    wfName: raw.wfName,
    input: raw.input,
    status: raw.status,           // running | completed | failed | cancelled
    startedAt: raw.startedAt,
    completedAt: raw.completedAt,
    log: raw.log || [],           // [{time, event, stage, agent, detail, verdict}]
    stageStatus: raw.stageStatus || {}, // { stageId: 'running'|'done'|'rework'|'blocked' }
    docs: raw.docs || {},         // { stageId: { content, deliverableName } }
    calls: raw.calls || 0,
    reworks: raw.reworks || 0,
    stageOrder: raw.stageOrder || [],
    pendingHuman: raw.pendingHuman || null, // { id, purpose, prompt } | null
    advisoryBatch: raw.advisoryBatch || [],
  };
}

// ─── Delivery depth constants ────────────────────────────────────────────────────
const DEPTH_LABEL = ['Advisory', 'Standard', 'Rigorous'];
const DEPTH_COLOR = ['#4c8ab5', '#c8a84a', '#e08080'];

// ─── Deliverable categories ──────────────────────────────────────────────────────
const OUTPUT_CATEGORIES = [
  'Requirements', 'Design', 'Development', 'Quality', 'Release', 'Enablement', 'Management',
];

// ─── CSS ─────────────────────────────────────────────────────────────────────────
const CSS = `
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  font-family: 'Inter', 'Plus Jakarta Sans', system-ui, sans-serif;
  background: #0a0e1a;
  background-image:
    linear-gradient(rgba(255,255,255,0.016) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.016) 1px, transparent 1px);
  background-size: 52px 52px;
  color: #e8e6df;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

/* ── Shell ── */
.shell { display:flex; height:100vh; overflow:hidden; }
.sidebar {
  width:220px; min-width:220px; background:#0d1220; border-right:1px solid #1b2640;
  display:flex; flex-direction:column; padding:0; overflow-y:auto;
}
.sidebar-logo {
  padding:18px 16px 14px; display:flex; align-items:center; gap:9px;
  border-bottom:1px solid #1b2640;
}
.logo-mark {
  width:28px; height:28px; background:#c8a84a; border-radius:6px;
  display:flex; align-items:center; justify-content:center; flex-shrink:0;
}
.logo-text { font-size:1.05rem; font-weight:700; color:#e8e6df; }
.nav-group { padding:18px 10px 6px; }
.nav-label {
  font-size:0.59rem; font-weight:600; letter-spacing:0.1em; text-transform:uppercase;
  color:#344054; padding:0 8px; margin-bottom:4px;
}
.nav-item {
  display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:7px;
  cursor:pointer; font-size:0.85rem; color:#748090; transition:all 0.15s;
  border:none; background:none; width:100%; text-align:left;
}
.nav-item:hover { background:#172038; color:#e8e6df; }
.nav-item.active { background:#172038; color:#e8e6df; }
.nav-item-icon { font-size:0.95rem; width:18px; text-align:center; }

.main { flex:1; display:flex; flex-direction:column; overflow:hidden; }
.topbar {
  padding:14px 24px; border-bottom:1px solid #1b2640; display:flex;
  align-items:center; justify-content:space-between; min-height:56px;
  background:rgba(13,18,32,0.7); backdrop-filter:blur(12px); flex-shrink:0;
}
.topbar-title { font-size:0.95rem; font-weight:600; }
.page { flex:1; overflow-y:auto; padding:24px; }

/* ── Cards & Surfaces ── */
.card {
  background:#0f1525; border:1px solid #1b2640; border-radius:12px; padding:20px;
}
.card-sm { background:#0f1525; border:1px solid #1b2640; border-radius:10px; padding:16px; }
.surface { background:#172038; border-radius:8px; padding:12px 14px; }

/* ── Buttons ── */
.btn {
  display:inline-flex; align-items:center; gap:6px; padding:8px 14px;
  border-radius:7px; font-size:0.85rem; font-weight:500; cursor:pointer;
  border:none; transition:all 0.15s; text-decoration:none;
}
.btn-gold { background:#c8a84a; color:#08090f; }
.btn-gold:hover { background:#d4b860; }
.btn-gold:disabled { background:#3a3016; color:#6b5d30; cursor:not-allowed; }
.btn-outline { background:transparent; color:#748090; border:1px solid #273558; }
.btn-outline:hover { color:#e8e6df; border-color:#4a5568; }
.btn-ghost { background:transparent; color:#748090; border:none; }
.btn-ghost:hover { color:#e8e6df; }
.btn-danger { background:rgba(224,128,128,0.12); color:#e08080; border:1px solid rgba(224,128,128,0.2); }
.btn-danger:hover { background:rgba(224,128,128,0.22); }
.btn-sm { padding:5px 10px; font-size:0.8rem; }
.btn-xs { padding:3px 8px; font-size:0.75rem; }

/* ── Forms ── */
input, textarea, select {
  background:#0a0e1a; border:1px solid #273558; border-radius:6px;
  color:#e8e6df; font-family:inherit; font-size:0.875rem; padding:8px 10px; outline:none;
  transition:border-color 0.15s;
}
input:focus, textarea:focus, select:focus { border-color:#c8a84a; }
textarea { resize:vertical; line-height:1.5; }
label { font-size:0.8rem; color:#748090; display:block; margin-bottom:4px; }
.field { margin-bottom:14px; }

/* ── Badges ── */
.badge {
  display:inline-flex; align-items:center; padding:2px 8px; border-radius:5px;
  font-size:0.72rem; font-weight:500; letter-spacing:0.02em;
}
.badge-gold  { background:rgba(200,168,74,0.15);  color:#c8a84a; }
.badge-blue  { background:rgba(76,138,181,0.15);   color:#6baede; }
.badge-red   { background:rgba(224,128,128,0.12);  color:#e08080; }
.badge-gray  { background:rgba(116,128,144,0.15);  color:#748090; }
.badge-green { background:rgba(74,222,128,0.12);   color:#4ade80; }

/* ── Depth tags ── */
.depth-tag { display:inline-flex; align-items:center; padding:2px 8px; border-radius:20px; font-size:0.73rem; font-weight:500; }
.depth-0 { background:rgba(76,138,181,0.15);   color:#6baede; }
.depth-1 { background:rgba(200,168,74,0.15);   color:#c8a84a; }
.depth-2 { background:rgba(224,128,128,0.12);  color:#e08080; }

/* ── Agent chips ── */
.agent-chip {
  display:inline-flex; align-items:center; gap:5px; padding:3px 8px;
  background:#172038; border:1px solid #1b2640; border-radius:20px;
  font-size:0.77rem; cursor:default;
}
.agent-avatar {
  width:20px; height:20px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; font-size:0.6rem; font-weight:700; flex-shrink:0;
}

/* ── Workflow canvas ── */
.wf-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:14px; }
.wf-card {
  background:#0f1525; border:1px solid #1b2640; border-radius:12px; padding:18px;
  cursor:pointer; transition:all 0.15s;
}
.wf-card:hover { border-color:#c8a84a; transform:translateY(-1px); }
.wf-card.active-wf { border-color:#c8a84a; }
.wf-name { font-weight:600; font-size:0.95rem; margin-bottom:5px; }
.wf-desc { font-size:0.8rem; color:#748090; line-height:1.55; }
.wf-meta { font-size:0.72rem; color:#344054; margin-top:10px; }

/* ── Pipeline ── */
.pipeline-wrap { overflow-x:auto; padding:12px 0 24px; }
.pipeline-row { display:flex; align-items:flex-start; gap:0; min-width:max-content; position:relative; }
.stage-col { display:flex; flex-direction:column; align-items:center; position:relative; }
.stage-connector {
  width:32px; height:2px; background:linear-gradient(90deg,#c8a84a88,#c8a84a44);
  align-self:center; margin-top:52px; flex-shrink:0;
}
.stage-node {
  width:140px; border:1px solid #273558; border-radius:10px;
  background:#0f1525; padding:12px; cursor:pointer; transition:all 0.15s;
  position:relative;
}
.stage-node:hover { border-color:#4a5568; }
.stage-node.active-stage { border-color:#c8a84a; box-shadow:0 0 0 1px #c8a84a22; }
.stage-num {
  font-size:0.6rem; color:#344054; letter-spacing:0.06em; margin-bottom:4px;
  font-variant-numeric:tabular-nums;
}
.stage-name { font-size:0.85rem; font-weight:600; margin-bottom:4px; }
.stage-owner { font-size:0.72rem; color:#748090; }
.stage-output { font-size:0.7rem; color:#4a5568; margin-top:5px; }
.stage-reviews { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; }
.review-dot {
  width:8px; height:8px; border-radius:50%;
}

/* Arc SVG layer */
.arc-layer { position:absolute; top:0; left:0; pointer-events:none; overflow:visible; }

/* ── Inspector panel ── */
.inspector {
  width:360px; min-width:360px; border-left:1px solid #1b2640;
  background:#0d1220; overflow-y:auto; display:flex; flex-direction:column;
}
.inspector-head {
  padding:16px 18px; border-bottom:1px solid #1b2640; display:flex;
  align-items:center; justify-content:space-between; flex-shrink:0;
}
.inspector-body { padding:18px; flex:1; overflow-y:auto; }
.inspector-section { margin-bottom:22px; }
.inspector-section-title {
  font-size:0.7rem; font-weight:600; letter-spacing:0.08em; text-transform:uppercase;
  color:#344054; margin-bottom:10px;
}

/* ── Reviews list ── */
.review-item {
  background:#172038; border-radius:8px; padding:10px 12px; margin-bottom:8px;
  display:flex; align-items:center; justify-content:space-between; gap:8px;
}
.review-drag { color:#344054; cursor:grab; font-size:0.8rem; }
.review-drag:active { cursor:grabbing; }

/* ── Run page ── */
.run-layout { display:flex; gap:20px; height:100%; }
.run-sidebar { width:280px; min-width:280px; display:flex; flex-direction:column; gap:14px; }
.run-main { flex:1; display:flex; flex-direction:column; gap:14px; min-width:0; }

.timeline { display:flex; flex-direction:column; gap:0; }
.tl-entry {
  display:flex; gap:12px; padding:8px 0; border-bottom:1px solid #1b2640;
  font-size:0.82rem;
}
.tl-entry:last-child { border-bottom:none; }
.tl-dot {
  width:8px; height:8px; border-radius:50%; margin-top:5px; flex-shrink:0;
}
.tl-time { color:#344054; font-size:0.72rem; white-space:nowrap; padding-top:1px; min-width:44px; }
.tl-text { flex:1; line-height:1.5; color:#748090; }
.tl-text b { color:#e8e6df; }
.tl-verdict { font-size:0.72rem; margin-top:3px; }

.status-pill {
  display:inline-flex; align-items:center; gap:5px; padding:3px 9px;
  border-radius:20px; font-size:0.78rem; font-weight:500;
}
.status-running { background:rgba(200,168,74,0.12); color:#c8a84a; }
.status-completed { background:rgba(74,222,128,0.1); color:#4ade80; }
.status-failed { background:rgba(224,128,128,0.1); color:#e08080; }
.status-cancelled { background:rgba(116,128,144,0.12); color:#748090; }
.status-idle { background:rgba(116,128,144,0.08); color:#4a5568; }

.pulse-dot {
  width:6px; height:6px; border-radius:50%; background:#c8a84a;
  animation:pulse 2s ease-in-out infinite;
}
@keyframes pulse { 0%,100%{opacity:1;} 50%{opacity:0.25;} }

/* ── Docs panel ── */
.doc-card {
  background:#0f1525; border:1px solid #1b2640; border-radius:10px;
  padding:14px; margin-bottom:10px;
}
.doc-name { font-weight:600; font-size:0.85rem; margin-bottom:6px; }
.doc-content {
  font-size:0.8rem; color:#748090; line-height:1.65; white-space:pre-wrap;
  max-height:200px; overflow-y:auto;
}

/* ── Doc expand modal ── */
.doc-modal { max-width:860px; max-height:90vh; }
.doc-modal-content {
  font-size:0.82rem; color:#c8c4bc; line-height:1.7; white-space:pre-wrap;
  font-family:'JetBrains Mono','Courier New',monospace;
}

/* ── Agents page ── */
.agents-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(280px,1fr)); gap:14px; }
.agent-card {
  background:#0f1525; border:1px solid #1b2640; border-radius:12px; padding:18px;
  cursor:pointer; transition:all 0.15s;
}
.agent-card:hover { border-color:#4a5568; }
.agent-card.active { border-color:#c8a84a; }
.agent-card-head { display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.agent-role { font-weight:600; font-size:0.95rem; }
.agent-tagline { font-size:0.8rem; color:#748090; line-height:1.45; margin-bottom:12px; }
.skill-row {
  display:flex; align-items:flex-start; gap:8px; padding:8px 10px;
  background:#172038; border-radius:7px; margin-bottom:6px;
}
.skill-toggle { flex-shrink:0; margin-top:1px; cursor:pointer; accent-color:#c8a84a; }
.skill-name { font-size:0.82rem; font-weight:500; }
.skill-prompt {
  font-size:0.76rem; color:#748090; margin-top:3px; line-height:1.45;
  white-space:pre-wrap;
}
.skill-modified { color:#c8a84a; font-size:0.68rem; margin-left:5px; }

/* ── Economics page ── */
.econ-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:14px; margin-bottom:24px; }
.stat-card { background:#0f1525; border:1px solid #1b2640; border-radius:10px; padding:18px; }
.stat-val { font-size:1.8rem; font-weight:700; color:#c8a84a; line-height:1; }
.stat-label { font-size:0.78rem; color:#748090; margin-top:5px; }

/* ── Org context page ── */
.org-grid { display:grid; grid-template-columns:1fr 1fr; gap:14px; }

/* ── Advisor / FinOps modals ── */
.modal-overlay {
  position:fixed; inset:0; background:rgba(0,0,0,0.7); display:flex;
  align-items:center; justify-content:center; z-index:500; padding:24px;
}
.modal {
  background:#0d1220; border:1px solid #273558; border-radius:14px;
  max-width:680px; width:100%; max-height:80vh; display:flex; flex-direction:column;
  box-shadow:0 24px 60px rgba(0,0,0,0.5);
}
.modal-head {
  padding:18px 20px; border-bottom:1px solid #1b2640;
  display:flex; align-items:center; justify-content:space-between; flex-shrink:0;
}
.modal-body { padding:20px; overflow-y:auto; flex:1; }
.rec-item {
  background:#172038; border-radius:8px; padding:12px 14px; margin-bottom:10px;
}
.rec-title { font-weight:600; font-size:0.88rem; margin-bottom:4px; }
.rec-detail { font-size:0.8rem; color:#748090; line-height:1.5; margin-bottom:8px; }
.rec-actions { display:flex; gap:6px; flex-wrap:wrap; }

/* ── Human gate ── */
.human-gate {
  background:rgba(200,168,74,0.08); border:1px solid rgba(200,168,74,0.3);
  border-radius:10px; padding:18px; margin-bottom:14px;
}
.human-gate-title { font-weight:600; font-size:0.9rem; color:#c8a84a; margin-bottom:6px; }
.human-gate-prompt { font-size:0.83rem; color:#748090; line-height:1.55; margin-bottom:12px; }
.human-gate-actions { display:flex; gap:8px; flex-wrap:wrap; }

/* ── Sim mode banner ── */
.sim-banner {
  background:rgba(76,138,181,0.08); border:1px solid rgba(76,138,181,0.2);
  border-radius:8px; padding:10px 14px; font-size:0.8rem; color:#6baede;
  margin-bottom:14px;
}

/* ── Load error ── */
.load-error {
  padding:40px; text-align:center;
}
.load-error h2 { font-size:1.1rem; margin-bottom:8px; color:#e08080; }
.load-error p { font-size:0.85rem; color:#748090; line-height:1.6; }

/* ── Tabs ── */
.tabs { display:flex; gap:2px; border-bottom:1px solid #1b2640; margin-bottom:20px; }
.tab {
  padding:9px 16px; font-size:0.84rem; cursor:pointer; border:none;
  background:none; color:#748090; border-bottom:2px solid transparent;
  transition:all 0.15s; margin-bottom:-1px;
}
.tab:hover { color:#e8e6df; }
.tab.active { color:#c8a84a; border-bottom-color:#c8a84a; }

/* ── Misc ── */
.row { display:flex; align-items:center; gap:8px; }
.row-between { display:flex; align-items:center; justify-content:space-between; gap:8px; }
.col { display:flex; flex-direction:column; gap:8px; }
.gap-4 { gap:4px; }
.gap-6 { gap:6px; }
.gap-12 { gap:12px; }
.mt-8 { margin-top:8px; }
.mt-14 { margin-top:14px; }
.mt-20 { margin-top:20px; }
.mb-8 { margin-bottom:8px; }
.mb-14 { margin-bottom:14px; }
.text-muted { color:#748090; font-size:0.82rem; }
.text-xs { font-size:0.75rem; color:#344054; }
.text-gold { color:#c8a84a; }
.text-red { color:#e08080; }
.divider { height:1px; background:#1b2640; margin:18px 0; }
.mono { font-family:'JetBrains Mono','Courier New',monospace; }
.empty-state { padding:40px; text-align:center; color:#344054; font-size:0.85rem; }

/* ── Drag-over highlight ── */
.drag-over { border-color:#c8a84a !important; background:rgba(200,168,74,0.05) !important; }

/* ── Scrollbar ── */
::-webkit-scrollbar { width:6px; height:6px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:#1b2640; border-radius:3px; }
::-webkit-scrollbar-thumb:hover { background:#273558; }

@media (max-width:900px) {
  .sidebar { display:none; }
  .inspector { display:none; }
  .org-grid { grid-template-columns:1fr; }
}
`;

// ─── Simulation engine (client-only, no API calls) ───────────────────────────────
function buildSimEvents(workflow, agentById) {
  const events = [];
  let t = 0;
  const stamp = (pause = 650) => { t += pause; return t; };

  for (let si = 0; si < workflow.stages.length; si++) {
    const stage = workflow.stages[si];
    const owner = agentById(stage.ownerId);
    events.push({ t: stamp(400), type: 'stage_start', stage: stage.name, agent: owner?.role || '?', detail: `${owner?.role || 'Agent'} beginning work on ${stage.name}` });
    events.push({ t: stamp(900), type: 'generating', stage: stage.name, agent: owner?.role || '?', detail: `Producing ${stage.outputId || 'deliverable'}…` });
    events.push({ t: stamp(1100), type: 'stage_done', stage: stage.name, agent: owner?.role || '?', detail: `Deliverable complete` });

    const reviews = (stage.reviews || []).filter(r => r.kind !== 'human');
    for (const rev of reviews) {
      if (!rev.agentId) continue;
      const reviewer = agentById(rev.agentId);
      const depthLabel = DEPTH_LABEL[rev.depth ?? 1];
      events.push({ t: stamp(600), type: 'review_start', stage: stage.name, agent: reviewer?.role || '?', detail: `${depthLabel} review starting`, depth: rev.depth });
      // Simulate occasional rework at Standard/Rigorous
      const rework = rev.depth >= 1 && Math.random() < 0.25;
      if (rework && si > 0) {
        const prevStage = workflow.stages[si - 1];
        events.push({ t: stamp(800), type: 'rework', stage: stage.name, agent: reviewer?.role || '?', detail: `Changes required — routing back to ${prevStage.name}`, verdict: 'rework' });
        events.push({ t: stamp(600), type: 'stage_start', stage: prevStage.name, agent: agentById(prevStage.ownerId)?.role || '?', detail: `Rework: revising ${prevStage.name}` });
        events.push({ t: stamp(900), type: 'stage_done', stage: prevStage.name, agent: agentById(prevStage.ownerId)?.role || '?', detail: `Revision complete` });
        events.push({ t: stamp(500), type: 'review_start', stage: stage.name, agent: reviewer?.role || '?', detail: `Re-review after revision`, depth: rev.depth });
      }
      events.push({ t: stamp(700), type: 'review_done', stage: stage.name, agent: reviewer?.role || '?', detail: `Approved`, verdict: 'approve' });
    }
  }
  events.push({ t: stamp(400), type: 'workflow_done', stage: '', agent: '', detail: 'Workflow complete — all stages and review gates cleared' });
  return events;
}

// ─── Icon helpers ─────────────────────────────────────────────────────────────────
const PAGE_ICONS = { workflows:'⚡', run:'▶', agents:'🧑‍💼', 'context-sources':'🔗', economics:'💰', org:'🏢', documents:'📄', operations:'📊' };
const EVENT_COLORS = {
  stage_start:'#c8a84a', generating:'#4c8ab5', stage_done:'#4ade80',
  review_start:'#6baede', review_done:'#4ade80', rework:'#e08080',
  workflow_done:'#4ade80', human_gate:'#c8a84a', advisory:'#4c8ab5',
  error:'#e08080',
};

// ─── Main App Component ─────────────────────────────────────────────────────────
function Orchestra() {
  // ── Page state ──
  const [page, setPage] = useState('run');
  const [loadError, setLoadError] = useState(null);
  const [loading, setLoading] = useState(true);

  // ── Data state (all loaded from backend) ──
  const [agents, setAgents] = useState([]);
  const [workflows, setWorkflows] = useState([]);
  const [outputs, setOutputs] = useState([]);   // deliverable catalog
  const [economics, setEconomics] = useState(null);
  const [operations, setOperations] = useState(null);
  const [orgContext, setOrgContext] = useState({ description: '', objects: '', automations: '', security: '', conventions: '', openWork: '' });
  const [orgEntries, setOrgEntries] = useState([]);
  const [allDocs, setAllDocs] = useState([]);

  // ── Workflow editor state ──
  const [activeWfId, setActiveWfId] = useState(null);
  const [activeStageId, setActiveStageId] = useState(null);
  const [wfTab, setWfTab] = useState('canvas'); // canvas | settings

  // ── Agent inspector state ──
  const [activeAgentId, setActiveAgentId] = useState(null);
  const [expandedSkillId, setExpandedSkillId] = useState(null);

  // ── Run state ──
  const [runs, setRuns] = useState([]);
  const [activeRunId, setActiveRunId] = useState(null);
  const [running, setRunning] = useState(false);
  const [runInput, setRunInput] = useState('');
  const [selectedWfForRun, setSelectedWfForRun] = useState(null);

  // ── Simulation state ──
  const [simMode, setSimMode] = useState(false);
  const [sim, setSim] = useState(null); // { log, running, wfName }
  const simTimers = useRef([]);

  // ── Advisor / FinOps modals ──
  const [advisorModal, setAdvisorModal] = useState(null);  // { wfId, loading, recs }
  const [finopsModal, setFinopsModal] = useState(null);    // { loading, data }
  const [settingsModal, setSettingsModal] = useState(null); // { loading, data, error, saving }
  const [settingsPin, setSettingsPin] = useState('');

  // ── Arc rendering ──
  const pipeRef = useRef(null);
  const [cardRects, setCardRects] = useState({});

  // ── Debounce save timers ──
  const saveTimers = useRef({});

  // ─── Load everything on mount ────────────────────────────────────────────────
  useEffect(() => {
    (async () => {
      try {
        const [ags, wfs, outs] = await Promise.all([
          api('GET', '/api/agents'),
          api('GET', '/api/workflows'),
          api('GET', '/api/outputs'),
        ]);
        setAgents(ags);
        setWorkflows(wfs);
        setOutputs(outs);
        if (wfs.length) {
          setActiveWfId(wfs[0].id);
          setSelectedWfForRun(wfs[0].id);
        }
        if (ags.length) setActiveAgentId(ags[0].id);

        // Load runs, economics, org context (non-critical — don't block on failure)
        try {
          const runsData = await api('GET', '/api/runs');
          setRuns((runsData || []).map(mapRunData));
          if (runsData?.length) setActiveRunId(runsData[0].id);
        } catch {}
        try {
          const econ = await api('GET', '/api/economics');
          setEconomics(econ);
        } catch {}
        try {
          const org = await api('GET', '/api/org-context');
          if (org) setOrgContext(org);
        } catch {}
        try {
          const entries = await api('GET', '/api/org-context/entries');
          if (entries) setOrgEntries(entries);
        } catch {}
        try {
          const docs = await api('GET', '/api/documents');
          if (docs) setAllDocs(docs);
        } catch {}

        setLoading(false);
      } catch (err) {
        setLoadError(err.message);
        setLoading(false);
      }
    })();
  }, []);

  // ─── Derived helpers ─────────────────────────────────────────────────────────
  const agentById = useCallback((id) => agents.find(a => a.id === id), [agents]);
  const outputById = useCallback((id) => outputs.find(o => o.id === id), [outputs]);
  const activeWf = useMemo(() => workflows.find(w => w.id === activeWfId), [workflows, activeWfId]);
  const activeStage = useMemo(() => activeWf?.stages?.find(s => s.id === activeStageId), [activeWf, activeStageId]);
  const activeAgent = useMemo(() => agents.find(a => a.id === activeAgentId), [agents, activeAgentId]);
  const activeRun = useMemo(() => runs.find(r => r.id === activeRunId), [runs, activeRunId]);

  // ─── Debounced save helpers ──────────────────────────────────────────────────
  function debounceSave(key, fn, delay = 700) {
    if (saveTimers.current[key]) clearTimeout(saveTimers.current[key]);
    saveTimers.current[key] = setTimeout(fn, delay);
  }

  // ─── Workflow mutations ──────────────────────────────────────────────────────
  function patchWorkflows(fn) {
    setWorkflows(ws => {
      const next = fn(ws);
      const updated = next.find(w => w.id === activeWfId);
      if (updated) {
        debounceSave(`wf-${updated.id}`, () => {
          api('PUT', `/api/workflows/${updated.id}`, updated).catch(console.error);
        });
      }
      return next;
    });
  }

  function patchStages(fn) {
    patchWorkflows(ws => ws.map(w => w.id === activeWfId ? { ...w, stages: fn(w.stages) } : w));
  }

  function patchStage(stageId, fn) {
    patchStages(stages => stages.map(s => s.id === stageId ? fn(s) : s));
  }

  // ─── Stage operations ────────────────────────────────────────────────────────
  function addStage() {
    const id = `s_${Date.now()}`;
    patchStages(stages => [...stages, {
      id, name: 'New Stage', ownerId: agents[0]?.id || '', outputId: outputs[0]?.id || '',
      ownerSkillIds: null, instructions: '', reviews: [],
    }]);
    setActiveStageId(id);
  }

  function deleteStage(stageId) {
    patchStages(stages => stages.filter(s => s.id !== stageId));
    if (activeStageId === stageId) setActiveStageId(null);
  }

  function addReview(stageId) {
    const id = `rv_${Date.now()}`;
    patchStage(stageId, s => ({ ...s, reviews: [...(s.reviews || []), { id, agentId: agents[0]?.id || '', depth: 1, skillIds: null }] }));
  }

  function addHumanGate(stageId) {
    const id = `hg_${Date.now()}`;
    patchStage(stageId, s => ({ ...s, reviews: [...(s.reviews || []), { id, kind: 'human', purpose: 'review_approve', trigger: 'always', flags: [], prompt: '' }] }));
  }

  function removeReview(stageId, reviewId) {
    patchStage(stageId, s => ({ ...s, reviews: (s.reviews || []).filter(r => r.id !== reviewId) }));
  }

  // ─── Agent mutations ─────────────────────────────────────────────────────────
  function patchAgent(agentId, fn) {
    setAgents(as => {
      const next = as.map(a => a.id === agentId ? fn(a) : a);
      const updated = next.find(a => a.id === agentId);
      if (updated) {
        debounceSave(`ag-${agentId}`, () => {
          api('PUT', `/api/agents/${agentId}`, updated).catch(console.error);
        });
      }
      return next;
    });
  }

  function toggleSkill(agentId, skillId) {
    patchAgent(agentId, a => ({ ...a, skills: a.skills.map(sk => sk.id === skillId ? { ...sk, enabled: !sk.enabled } : sk) }));
  }

  function editSkillPrompt(agentId, skillId, prompt) {
    patchAgent(agentId, a => ({
      ...a, skills: a.skills.map(sk => sk.id === skillId ? { ...sk, prompt, custom: prompt !== sk.defaultPrompt } : sk),
    }));
  }

  function revertSkill(agentId, skillId) {
    patchAgent(agentId, a => ({
      ...a, skills: a.skills.map(sk => sk.id === skillId ? { ...sk, prompt: sk.defaultPrompt, custom: false } : sk),
    }));
  }

  // ─── Workflow CRUD ───────────────────────────────────────────────────────────
  async function createWorkflow() {
    const id = `wf_${Date.now()}`;
    const wf = { id, name: 'New Workflow', description: '', stages: [] };
    try {
      const saved = await api('POST', '/api/workflows', wf);
      setWorkflows(ws => [...ws, saved || wf]);
      setActiveWfId(id);
    } catch (err) { console.error(err); }
  }

  async function duplicateWorkflow(wfId) {
    const src = workflows.find(w => w.id === wfId);
    if (!src) return;
    const id = `wf_${Date.now()}`;
    const copy = { ...src, id, name: src.name + ' (copy)' };
    try {
      const saved = await api('POST', '/api/workflows', copy);
      setWorkflows(ws => [...ws, saved || copy]);
      setActiveWfId(id);
    } catch (err) { console.error(err); }
  }

  async function deleteWorkflow(wfId) {
    try {
      await api('DELETE', `/api/workflows/${wfId}`);
      setWorkflows(ws => ws.filter(w => w.id !== wfId));
      if (activeWfId === wfId) {
        const remaining = workflows.filter(w => w.id !== wfId);
        setActiveWfId(remaining[0]?.id || null);
      }
    } catch (err) { console.error(err); }
  }

  // ─── Run workflow ────────────────────────────────────────────────────────────
  async function startRun(wfId, input) {
    if (!input.trim()) return;
    setRunning(true);
    try {
      const run = await api('POST', '/api/runs', { wfId, input });
      const mapped = mapRunData(run);
      setRuns(rs => [mapped, ...rs]);
      setActiveRunId(mapped.id);
      pollRun(mapped.id);
    } catch (err) {
      console.error(err);
      setRunning(false);
    }
  }

  function pollRun(runId) {
    let live = true;
    const tick = async () => {
      if (!live) return;
      try {
        const raw = await api('GET', `/api/runs/${runId}`);
        const mapped = mapRunData(raw);
        setRuns(rs => rs.map(r => r.id === runId ? mapped : r));
        if (mapped.status === 'running') {
          setTimeout(tick, 2000);
        } else {
          setRunning(false);
        }
      } catch {
        setTimeout(tick, 3000);
      }
    };
    setTimeout(tick, 1500);
    return () => { live = false; };
  }

  async function stopRun(runId) {
    try { await api('POST', `/api/runs/${runId}/cancel`); } catch {}
    setRunning(false);
  }

  async function resolveHuman(runId, gateId, approved, notes) {
    try {
      await api('POST', `/api/runs/${runId}/resume`, { gateId, approved, notes });
      pollRun(runId);
    } catch (err) { console.error(err); }
  }

  // ─── Simulation (client-only) ────────────────────────────────────────────────
  function runSimulation(wf) {
    simTimers.current.forEach(t => clearTimeout(t));
    simTimers.current = [];
    setSim({ log: [], running: true, wfName: wf.name });
    setSimMode(true);
    const events = buildSimEvents(wf, agentById);
    events.forEach(ev => {
      const tid = setTimeout(() => {
        setSim(s => {
          if (!s) return s;
          const done = ev.type === 'workflow_done';
          return { ...s, log: [...s.log, ev], running: !done };
        });
      }, ev.t);
      simTimers.current.push(tid);
    });
  }

  function stopSim() {
    simTimers.current.forEach(t => clearTimeout(t));
    simTimers.current = [];
    setSim(null);
    setSimMode(false);
  }

  // ─── Advisor ────────────────────────────────────────────────────────────────
  async function openSettings() {
    setSettingsPin('');
    setSettingsModal({ loading: true });
    try {
      const data = await api('GET', '/api/admin/settings');
      setSettingsModal({ loading: false, data });
    } catch (err) {
      setSettingsModal({ loading: false, error: err.message });
    }
  }

  async function setModelProvider(provider) {
    setSettingsModal(m => ({ ...m, saving: true, error: null }));
    try {
      const headers = { 'Content-Type': 'application/json' };
      if (settingsPin) headers['X-Admin-Pin'] = settingsPin;
      const res = await fetch(BACKEND + '/api/admin/settings', {
        method: 'PATCH',
        headers,
        body: JSON.stringify(deepSnake({ modelProvider: provider })),
      });
      if (!res.ok) {
        const text = await res.text().catch(() => '');
        throw new Error(`API PATCH /api/admin/settings → ${res.status}: ${text}`);
      }
      const data = deepCamel(await res.json());
      setSettingsModal({ loading: false, data });
    } catch (err) {
      const match = (err.message || '').match(/"detail":"([^"]+)"/);
      const msg = match ? match[1] : err.message;
      setSettingsModal(m => ({ ...m, saving: false, error: msg }));
    }
  }

  async function runAdvisor(wfId) {
    setAdvisorModal({ wfId, loading: true, recs: [] });
    try {
      const res = await api('POST', `/api/workflows/${wfId}/advisor`, {});
      setAdvisorModal({ wfId, loading: false, recs: res.recommendations || [] });
    } catch (err) {
      setAdvisorModal({ wfId, loading: false, recs: [], error: err.message });
    }
  }

  async function applyRec(wfId, action) {
    try {
      const res = await api('POST', `/api/workflows/${wfId}/apply-action`, { action });
      if (res?.workflow) {
        setWorkflows(ws => ws.map(w => w.id === wfId ? res.workflow : w));
      }
    } catch (err) { console.error(err); }
  }

  // ─── FinOps ─────────────────────────────────────────────────────────────────
  async function runFinOps(wfId) {
    setFinopsModal({ loading: true, data: null });
    try {
      const res = await api('POST', `/api/workflows/${wfId}/finops`, {});
      setFinopsModal({ loading: false, data: res });
    } catch (err) {
      setFinopsModal({ loading: false, data: null, error: err.message });
    }
  }

  // ─── Org context ────────────────────────────────────────────────────────────
  function saveOrgContext(updates) {
    const next = { ...orgContext, ...updates };
    setOrgContext(next);
    debounceSave('org', () => {
      api('PUT', '/api/org-context', next).catch(console.error);
    });
  }

  async function createOrgEntry(data) {
    const entry = await api('POST', '/api/org-context/entries', data);
    setOrgEntries(prev => [...prev, entry]);
    return entry;
  }

  async function updateOrgEntry(id, data) {
    await api('PATCH', `/api/org-context/entries/${id}`, data);
    setOrgEntries(prev => prev.map(e => e.id === id ? { ...e, ...data } : e));
  }

  async function deleteOrgEntry(id) {
    await api('DELETE', `/api/org-context/entries/${id}`);
    setOrgEntries(prev => prev.filter(e => e.id !== id));
  }

  async function refreshDocs() {
    try { const docs = await api('GET', '/api/documents'); if (docs) setAllDocs(docs); } catch {}
  }

  // ─── Arc rendering ───────────────────────────────────────────────────────────
  const arcs = useMemo(() => {
    if (!activeWf?.stages || Object.keys(cardRects).length === 0) return [];
    const result = [];
    activeWf.stages.forEach((stage, si) => {
      (stage.reviews || []).forEach(rev => {
        if (rev.kind === 'human' || !rev.agentId) return;
        // find the stage the reviewer "owns" (where they are the owner agent)
        const reviewerStageIdx = activeWf.stages.findIndex(s => s.ownerId === rev.agentId);
        if (reviewerStageIdx < 0 || reviewerStageIdx >= si) return; // only backward arcs
        const fromRect = cardRects[stage.id];
        const toRect = cardRects[activeWf.stages[reviewerStageIdx].id];
        if (!fromRect || !toRect) return;
        result.push({ from: stage.id, to: activeWf.stages[reviewerStageIdx].id, fromRect, toRect, depth: rev.depth ?? 1 });
      });
    });
    return result;
  }, [activeWf, cardRects]);

  // ─── Measure card positions ──────────────────────────────────────────────────
  useEffect(() => {
    if (!pipeRef.current) return;
    const measure = () => {
      const pipe = pipeRef.current;
      if (!pipe) return;
      const pipeRect = pipe.getBoundingClientRect();
      const rects = {};
      pipe.querySelectorAll('[data-stage-id]').forEach(el => {
        const sid = el.dataset.stageId;
        const r = el.getBoundingClientRect();
        rects[sid] = {
          x: r.left - pipeRect.left + r.width / 2,
          y: r.top - pipeRect.top,
          w: r.width,
          h: r.height,
        };
      });
      setCardRects(rects);
    };
    measure();
    window.addEventListener('resize', measure);
    return () => window.removeEventListener('resize', measure);
  }, [activeWf, page]);

  // ─── Inject CSS ──────────────────────────────────────────────────────────────
  useEffect(() => {
    const el = document.createElement('style');
    el.textContent = CSS;
    document.head.appendChild(el);
    return () => el.remove();
  }, []);

  // ─── Error / loading screens ─────────────────────────────────────────────────
  if (loadError) {
    return (
      <div style={{ display:'flex', alignItems:'center', justifyContent:'center', height:'100vh', flexDirection:'column', gap:'16px', padding:'32px' }}>
        <div style={{ fontSize:'2rem' }}>⚠️</div>
        <div style={{ fontSize:'1.1rem', fontWeight:600, color:'#e08080' }}>Cannot connect to Orchestra backend</div>
        <div style={{ fontSize:'0.85rem', color:'#748090', textAlign:'center', maxWidth:'480px', lineHeight:1.7 }}>
          Make sure the backend is running (<code style={{color:'#c8a84a'}}>docker compose up -d</code>) and accessible, then reload this page.
          <br/><br/>
          <span style={{ color:'#344054', fontSize:'0.78rem' }}>Error: {loadError}</span>
        </div>
        <button className="btn btn-outline" onClick={() => window.location.reload()}>Reload</button>
      </div>
    );
  }

  if (loading) {
    return (
      <div style={{ display:'flex', alignItems:'center', justifyContent:'center', height:'100vh', flexDirection:'column', gap:'14px' }}>
        <div style={{ fontSize:'1.2rem', color:'#c8a84a', fontWeight:700 }}>Orchestra</div>
        <div className="spin" style={{ width:24, height:24 }}></div>
      </div>
    );
  }

  // ─── Render ──────────────────────────────────────────────────────────────────
  return (
    <div className="shell">
      {/* ── Sidebar ── */}
      <div className="sidebar">
        <div className="sidebar-logo">
          <div className="logo-mark">
            <svg width="13" height="13" viewBox="0 0 13 13" fill="none">
              <path d="M1 6.5C2.2 4 3.8 4 6.5 6.5 9.2 9 10.8 9 12 6.5" stroke="#090C16" strokeWidth="2" strokeLinecap="round" fill="none"/>
            </svg>
          </div>
          <span className="logo-text">Orchestra</span>
        </div>
        <div className="nav-group">
          <div className="nav-label">Workspace</div>
          {[
            ['run', 'Run & Generate'],
            ['workflows', 'Workflows'],
            ['agents', 'Agent Library'],
          ].map(([id, label]) => (
            <button key={id} className={`nav-item ${page === id ? 'active' : ''}`} onClick={() => setPage(id)}>
              <span className="nav-item-icon">{PAGE_ICONS[id]}</span>
              {label}
            </button>
          ))}
        </div>
        <div className="nav-group">
          <div className="nav-label">Context</div>
          {[
            ['org', 'Org Context'],
            ['documents', 'Documents'],
          ].map(([id, label]) => (
            <button key={id} className={`nav-item ${page === id ? 'active' : ''}`} onClick={() => { setPage(id); if (id === 'documents') refreshDocs(); }}>
              <span className="nav-item-icon">{PAGE_ICONS[id]}</span>
              {label}
            </button>
          ))}
        </div>
        <div className="nav-group">
          <div className="nav-label">Analytics</div>
          {[
            ['economics', 'Economics'],
            ['operations', 'Operations'],
          ].map(([id, label]) => (
            <button key={id} className={`nav-item ${page === id ? 'active' : ''}`} onClick={() => setPage(id)}>
              <span className="nav-item-icon">{PAGE_ICONS[id]}</span>
              {label}
            </button>
          ))}
        </div>
        <div className="nav-group">
          <div className="nav-label">Configuration</div>
          <button className="nav-item" onClick={openSettings}>
            <span className="nav-item-icon">⚙️</span>
            Settings
          </button>
        </div>
      </div>

      {/* ── Main content area ── */}
      <div className="main">
        {page === 'workflows' && <WorkflowsPage
          workflows={workflows} activeWfId={activeWfId} activeStageId={activeStageId}
          setActiveWfId={setActiveWfId} setActiveStageId={setActiveStageId}
          activeWf={activeWf} activeStage={activeStage}
          agents={agents} outputs={outputs} agentById={agentById} outputById={outputById}
          wfTab={wfTab} setWfTab={setWfTab}
          addStage={addStage} deleteStage={deleteStage}
          patchStage={patchStage} patchWorkflows={patchWorkflows}
          addReview={addReview} addHumanGate={addHumanGate} removeReview={removeReview}
          createWorkflow={createWorkflow} duplicateWorkflow={duplicateWorkflow} deleteWorkflow={deleteWorkflow}
          runSimulation={runSimulation} runAdvisor={runAdvisor}
          pipeRef={pipeRef} arcs={arcs}
        />}
        {page === 'run' && <RunPage
          workflows={workflows} runs={runs} activeRun={activeRun} activeRunId={activeRunId}
          setActiveRunId={setActiveRunId} running={running}
          runInput={runInput} setRunInput={setRunInput}
          selectedWfForRun={selectedWfForRun} setSelectedWfForRun={setSelectedWfForRun}
          startRun={startRun} stopRun={stopRun} resolveHuman={resolveHuman}
          agentById={agentById}
          simMode={simMode} sim={sim} runSimulation={runSimulation} stopSim={stopSim} activeWf={activeWf}
          onRunComplete={refreshDocs}
        />}
        {page === 'agents' && <AgentsPage
          agents={agents} activeAgentId={activeAgentId} setActiveAgentId={setActiveAgentId}
          activeAgent={activeAgent}
          expandedSkillId={expandedSkillId} setExpandedSkillId={setExpandedSkillId}
          toggleSkill={toggleSkill} editSkillPrompt={editSkillPrompt} revertSkill={revertSkill}
        />}
        {page === 'context-sources' && window.ContextSourcesPage &&
          React.createElement(window.ContextSourcesPage, { agents })}
        {page === 'economics' && <EconomicsPage economics={economics} runFinOps={runFinOps} activeWfId={activeWfId} />}
        {page === 'operations' && <OperationsPage operations={operations} />}
        {page === 'org' && <OrgContextPage orgEntries={orgEntries} onCreateEntry={createOrgEntry} onUpdateEntry={updateOrgEntry} onDeleteEntry={deleteOrgEntry} />}
        {page === 'documents' && <DocumentsPage allDocs={allDocs} />}
      </div>

      {/* ── Advisor modal ── */}
      {advisorModal && (
        <div className="modal-overlay" onClick={(e) => e.target === e.currentTarget && setAdvisorModal(null)}>
          <div className="modal">
            <div className="modal-head">
              <div>
                <div style={{ fontWeight:600, fontSize:'0.95rem' }}>Delivery Advisor</div>
                <div className="text-muted" style={{ marginTop:2 }}>Workflow analysis &amp; recommendations</div>
              </div>
              <button className="btn btn-ghost btn-sm" onClick={() => setAdvisorModal(null)}>✕</button>
            </div>
            <div className="modal-body">
              {advisorModal.loading && <div className="text-muted" style={{ padding:'20px 0', textAlign:'center' }}>Analysing workflow…</div>}
              {advisorModal.error && <div className="text-red">{advisorModal.error}</div>}
              {!advisorModal.loading && (advisorModal.recs || []).map((rec, i) => (
                <div key={i} className="rec-item">
                  <div className="rec-title">{rec.title}</div>
                  <div className="rec-detail">{rec.detail || rec.description}</div>
                  <div className="rec-actions">
                    {rec.action && (
                      <button className="btn btn-gold btn-xs" onClick={() => { applyRec(advisorModal.wfId, rec.action); setAdvisorModal(null); }}>
                        Apply
                      </button>
                    )}
                  </div>
                </div>
              ))}
              {!advisorModal.loading && !advisorModal.error && !(advisorModal.recs?.length) && (
                <div className="empty-state">No recommendations — workflow looks well-configured.</div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* ── FinOps modal ── */}
      {finopsModal && (
        <div className="modal-overlay" onClick={(e) => e.target === e.currentTarget && setFinopsModal(null)}>
          <div className="modal">
            <div className="modal-head">
              <div>
                <div style={{ fontWeight:600, fontSize:'0.95rem' }}>FinOps Analyst</div>
                <div className="text-muted" style={{ marginTop:2 }}>Cost projection &amp; run economics</div>
              </div>
              <button className="btn btn-ghost btn-sm" onClick={() => setFinopsModal(null)}>✕</button>
            </div>
            <div className="modal-body">
              {finopsModal.loading && <div className="text-muted" style={{ padding:'20px 0', textAlign:'center' }}>Calculating cost projection…</div>}
              {finopsModal.error && <div className="text-red">{finopsModal.error}</div>}
              {finopsModal.data && (
                <div>
                  <div className="econ-grid">
                    {[
                      ['Estimated cost', finopsModal.data.estimatedCost || '—'],
                      ['Estimated tokens', finopsModal.data.estimatedTokens || '—'],
                      ['Estimated duration', finopsModal.data.estimatedDuration || '—'],
                    ].map(([label, val]) => (
                      <div key={label} className="stat-card">
                        <div className="stat-val" style={{ fontSize:'1.2rem' }}>{val}</div>
                        <div className="stat-label">{label}</div>
                      </div>
                    ))}
                  </div>
                  {finopsModal.data.notes && (
                    <div className="text-muted mt-14" style={{ lineHeight:1.65 }}>{finopsModal.data.notes}</div>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* ── Settings modal (AI model toggle) ── */}
      {settingsModal && (
        <div className="modal-overlay" onClick={(e) => e.target === e.currentTarget && setSettingsModal(null)}>
          <div className="modal" style={{ maxWidth: 520 }}>
            <div className="modal-head">
              <div>
                <div style={{ fontWeight: 600, fontSize: '0.95rem' }}>Settings</div>
                <div className="text-muted" style={{ marginTop: 2 }}>AI model &amp; preferences</div>
              </div>
              <button className="btn btn-ghost btn-sm" onClick={() => setSettingsModal(null)}>✕</button>
            </div>
            <div className="modal-body">
              {settingsModal.loading && (
                <div className="text-muted" style={{ padding: '20px 0', textAlign: 'center' }}>Loading settings…</div>
              )}
              {settingsModal.error && (
                <div className="text-red mb-14" style={{ lineHeight: 1.5 }}>{settingsModal.error}</div>
              )}
              {settingsModal.data && (
                <div>
                  <div className="inspector-section-title">AI Model</div>
                  <div className="text-muted mb-14" style={{ lineHeight: 1.55 }}>
                    Which model new runs use. Vertex AI is production (billed); AI Studio is the free tier for testing.
                  </div>
                  <div className="col" style={{ gap: 8 }}>
                    {[['vertex', settingsModal.data.providers?.vertex],
                      ['aistudio', settingsModal.data.providers?.aistudio]].map(([key, info]) => {
                      const cur = settingsModal.data.modelProvider;
                      const active = cur === key || (!cur && settingsModal.data.activeModel === info?.model);
                      const unavailable = info && !info.available;
                      return (
                        <button key={key} disabled={settingsModal.saving}
                          onClick={() => setModelProvider(key)}
                          style={{
                            display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10,
                            width: '100%', textAlign: 'left', padding: '12px 14px', borderRadius: 8,
                            background: '#172038', color: '#e8e6df',
                            border: active ? '1px solid #c8a84a' : '1px solid #1b2640',
                            cursor: settingsModal.saving ? 'wait' : 'pointer',
                          }}>
                          <div>
                            <div className="row" style={{ gap: 6 }}>
                              <span style={{ fontWeight: 600, fontSize: '0.86rem' }}>{info?.label || key}</span>
                              {active && <span className="badge badge-green">active</span>}
                              {unavailable && <span className="badge badge-gray">key not set</span>}
                            </div>
                            <div className="mono text-xs" style={{ marginTop: 4 }}>{info?.model}</div>
                          </div>
                          <span style={{ color: active ? '#c8a84a' : '#344054', fontSize: '1rem' }}>{active ? '●' : '○'}</span>
                        </button>
                      );
                    })}
                  </div>
                  <div className="divider"></div>
                  <div className="row-between">
                    <span className="text-muted">Active model</span>
                    <span className="badge badge-gold mono">{settingsModal.data.activeModel}</span>
                  </div>
                  {settingsModal.data.pinRequired && (
                    <div className="mt-14">
                      <div className="divider"></div>
                      <div className="inspector-section-title" style={{ marginBottom:6 }}>Admin PIN</div>
                      <input
                        type="password"
                        placeholder="Enter PIN to change settings"
                        value={settingsPin}
                        onChange={e => setSettingsPin(e.target.value)}
                        style={{ width:'100%' }}
                      />
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Workflows Page ──────────────────────────────────────────────────────────────
function WorkflowsPage({ workflows, activeWfId, activeStageId, setActiveWfId, setActiveStageId,
  activeWf, activeStage, agents, outputs, agentById, outputById, wfTab, setWfTab,
  addStage, deleteStage, patchStage, patchWorkflows, addReview, addHumanGate, removeReview,
  createWorkflow, duplicateWorkflow, deleteWorkflow, runSimulation, runAdvisor,
  pipeRef, arcs }) {

  return (
    <div style={{ display:'flex', height:'100%', overflow:'hidden' }}>
      {/* Left panel: wf list */}
      <div style={{ width:260, minWidth:260, borderRight:'1px solid #1b2640', overflow:'auto', padding:16 }}>
        <div className="row-between mb-14">
          <div style={{ fontWeight:600, fontSize:'0.9rem' }}>Workflows</div>
          <button className="btn btn-gold btn-sm" onClick={createWorkflow}>+ New</button>
        </div>
        {workflows.map(wf => (
          <div key={wf.id}
            className={`wf-card mb-8 ${wf.id === activeWfId ? 'active-wf' : ''}`}
            style={{ padding:'12px 14px' }}
            onClick={() => { setActiveWfId(wf.id); setActiveStageId(null); }}
          >
            <div className="wf-name" style={{ fontSize:'0.88rem' }}>{wf.name}</div>
            <div className="wf-meta">{wf.stages?.length || 0} stages</div>
            <div className="row mt-8" style={{ gap:4 }}>
              <button className="btn btn-ghost btn-xs" onClick={(e) => { e.stopPropagation(); duplicateWorkflow(wf.id); }}>⧉</button>
              {workflows.length > 1 && (
                <button className="btn btn-ghost btn-xs text-red" onClick={(e) => { e.stopPropagation(); deleteWorkflow(wf.id); }}>✕</button>
              )}
            </div>
          </div>
        ))}
      </div>

      {/* Centre: canvas */}
      <div style={{ flex:1, overflow:'auto', padding:20 }}>
        {activeWf ? (
          <>
            <div className="row-between mb-14">
              <div>
                <div style={{ fontWeight:600, fontSize:'1rem' }}>{activeWf.name}</div>
                <div className="text-muted">{activeWf.description}</div>
              </div>
              <div className="row">
                <button className="btn btn-outline btn-sm" onClick={() => runAdvisor(activeWf.id)}>🤖 Advisor</button>
                <button className="btn btn-gold btn-sm" onClick={() => runSimulation(activeWf)}>▶ Simulate</button>
              </div>
            </div>

            {/* Pipeline canvas */}
            <div className="pipeline-wrap" ref={pipeRef}>
              <div className="pipeline-row" style={{ position:'relative' }}>
                {/* Arc SVG layer */}
                {arcs.length > 0 && (
                  <svg className="arc-layer" style={{ width:'100%', height:120, position:'absolute', top:-110, left:0, overflow:'visible' }}>
                    {arcs.map((arc, i) => {
                      const x1 = arc.fromRect.x, x2 = arc.toRect.x;
                      const y1 = -10, y2 = -10;
                      const cpY = -80 - i * 18;
                      const color = DEPTH_COLOR[arc.depth ?? 1];
                      const dash = arc.depth === 0 ? '5,4' : arc.depth === 2 ? 'none' : 'none';
                      const sw = arc.depth === 2 ? 2 : arc.depth === 0 ? 1 : 1.5;
                      return (
                        <path key={i}
                          d={`M${x1},${y1} C${x1},${cpY} ${x2},${cpY} ${x2},${y2}`}
                          stroke={color} strokeWidth={sw} fill="none"
                          strokeDasharray={dash} strokeLinecap="round" opacity={0.7}
                        />
                      );
                    })}
                  </svg>
                )}

                {(activeWf.stages || []).map((stage, si) => {
                  const owner = agentById(stage.ownerId);
                  const out = outputById(stage.outputId);
                  const isActive = stage.id === activeStageId;
                  return (
                    <React.Fragment key={stage.id}>
                      {si > 0 && <div className="stage-connector" />}
                      <div className="stage-col">
                        <div
                          className={`stage-node ${isActive ? 'active-stage' : ''}`}
                          data-stage-id={stage.id}
                          onClick={() => setActiveStageId(isActive ? null : stage.id)}
                        >
                          <div className="stage-num">STAGE {String(si+1).padStart(2,'0')}</div>
                          <div className="stage-name">{stage.name}</div>
                          <div className="stage-owner">{owner?.role || '—'}</div>
                          {out && <div className="stage-output">{out.name}</div>}
                          <div className="stage-reviews">
                            {(stage.reviews || []).map(rev => (
                              <div key={rev.id} className="review-dot"
                                style={{ background: rev.kind === 'human' ? '#c8a84a' : DEPTH_COLOR[rev.depth ?? 1] }}
                                title={rev.kind === 'human' ? 'Human gate' : `${agentById(rev.agentId)?.role || '?'} — ${DEPTH_LABEL[rev.depth ?? 1]}`}
                              />
                            ))}
                          </div>
                        </div>
                      </div>
                    </React.Fragment>
                  );
                })}
                <div style={{ display:'flex', alignItems:'center', paddingLeft:8 }}>
                  <button className="btn btn-outline btn-sm" onClick={addStage}>+ Stage</button>
                </div>
              </div>
            </div>
          </>
        ) : (
          <div className="empty-state">Select a workflow or create a new one.</div>
        )}
      </div>

      {/* Right: stage inspector */}
      {activeStage && (
        <StageInspector
          stage={activeStage} stageIndex={(activeWf?.stages || []).findIndex(s => s.id === activeStage.id)}
          agents={agents} outputs={outputs} agentById={agentById}
          patchStage={patchStage} addReview={addReview} addHumanGate={addHumanGate} removeReview={removeReview}
          deleteStage={deleteStage}
        />
      )}
    </div>
  );
}

// ─── Stage Inspector ─────────────────────────────────────────────────────────────
function StageInspector({ stage, stageIndex, agents, outputs, agentById, patchStage, addReview, addHumanGate, removeReview, deleteStage }) {
  return (
    <div className="inspector">
      <div className="inspector-head">
        <div>
          <div style={{ fontWeight:600, fontSize:'0.9rem' }}>Stage {stageIndex+1}: {stage.name}</div>
        </div>
        <button className="btn btn-danger btn-xs" onClick={() => deleteStage(stage.id)}>Delete</button>
      </div>
      <div className="inspector-body">
        {/* Name */}
        <div className="inspector-section">
          <div className="inspector-section-title">Name</div>
          <input style={{ width:'100%' }} value={stage.name}
            onChange={e => patchStage(stage.id, s => ({ ...s, name: e.target.value }))} />
        </div>

        {/* Owner */}
        <div className="inspector-section">
          <div className="inspector-section-title">Owner Agent</div>
          <select style={{ width:'100%' }} value={stage.ownerId}
            onChange={e => patchStage(stage.id, s => ({ ...s, ownerId: e.target.value }))}>
            {agents.filter(a => !a.meta).map(a => (
              <option key={a.id} value={a.id}>{a.role}</option>
            ))}
          </select>
        </div>

        {/* Deliverable */}
        <div className="inspector-section">
          <div className="inspector-section-title">Deliverable</div>
          <select style={{ width:'100%' }} value={stage.outputId}
            onChange={e => patchStage(stage.id, s => ({ ...s, outputId: e.target.value }))}>
            {OUTPUT_CATEGORIES.map(cat => (
              <optgroup key={cat} label={cat}>
                {outputs.filter(o => o.category === cat).map(o => (
                  <option key={o.id} value={o.id}>{o.name}</option>
                ))}
              </optgroup>
            ))}
          </select>
        </div>

        {/* Instructions */}
        <div className="inspector-section">
          <div className="inspector-section-title">Stage Instructions</div>
          <textarea style={{ width:'100%' }} rows={3} placeholder="Optional instructions for this stage…"
            value={stage.instructions || ''}
            onChange={e => patchStage(stage.id, s => ({ ...s, instructions: e.target.value }))} />
        </div>

        {/* Review gates */}
        <div className="inspector-section">
          <div className="row-between mb-8">
            <div className="inspector-section-title" style={{ margin:0 }}>Review Gates</div>
            <div className="row" style={{ gap:4 }}>
              <button className="btn btn-outline btn-xs" onClick={() => addReview(stage.id)}>+ Agent</button>
              <button className="btn btn-outline btn-xs" onClick={() => addHumanGate(stage.id)}>+ Human</button>
            </div>
          </div>
          {(stage.reviews || []).length === 0 && <div className="text-xs">No review gates configured.</div>}
          {(stage.reviews || []).map(rev => (
            <div key={rev.id} className="review-item">
              {rev.kind === 'human' ? (
                <div style={{ flex:1 }}>
                  <div className="row" style={{ gap:6, marginBottom:4 }}>
                    <span style={{ fontSize:'0.8rem' }}>👤</span>
                    <span style={{ fontWeight:600, fontSize:'0.82rem' }}>Human Checkpoint</span>
                    <span className="badge badge-gold" style={{ fontSize:'0.68rem' }}>{rev.trigger || 'always'}</span>
                  </div>
                  <select style={{ width:'100%', fontSize:'0.78rem' }} value={rev.purpose || 'review_approve'}
                    onChange={e => patchStage(stage.id, s => ({ ...s, reviews: s.reviews.map(r => r.id === rev.id ? { ...r, purpose: e.target.value } : r) }))}>
                    <option value="review_approve">Review &amp; Approve</option>
                    <option value="ask_question">Ask a Question</option>
                  </select>
                </div>
              ) : (
                <div style={{ flex:1 }}>
                  <div className="row-between" style={{ marginBottom:5 }}>
                    <select style={{ flex:1, fontSize:'0.78rem' }} value={rev.agentId}
                      onChange={e => patchStage(stage.id, s => ({ ...s, reviews: s.reviews.map(r => r.id === rev.id ? { ...r, agentId: e.target.value } : r) }))}>
                      {agents.filter(a => !a.meta).map(a => <option key={a.id} value={a.id}>{a.role}</option>)}
                    </select>
                  </div>
                  <div className="row" style={{ gap:4 }}>
                    {DEPTH_LABEL.map((label, di) => (
                      <button key={di}
                        className={`btn btn-xs ${rev.depth === di ? '' : 'btn-outline'}`}
                        style={rev.depth === di ? { background: DEPTH_COLOR[di] + '33', color: DEPTH_COLOR[di], border:`1px solid ${DEPTH_COLOR[di]}44` } : {}}
                        onClick={() => patchStage(stage.id, s => ({ ...s, reviews: s.reviews.map(r => r.id === rev.id ? { ...r, depth: di } : r) }))}>
                        {label}
                      </button>
                    ))}
                  </div>
                </div>
              )}
              <button className="btn btn-ghost btn-xs text-red" onClick={() => removeReview(stage.id, rev.id)}>✕</button>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─── Run Page ────────────────────────────────────────────────────────────────────
function RunPage({ workflows, runs, activeRun, activeRunId, setActiveRunId, running,
  runInput, setRunInput, selectedWfForRun, setSelectedWfForRun,
  startRun, stopRun, resolveHuman, agentById,
  simMode, sim, runSimulation, stopSim, activeWf, onRunComplete }) {

  const [humanNotes, setHumanNotes] = useState('');
  const [expandedDoc, setExpandedDoc] = useState(null);
  const tlRef = useRef(null);
  const intakeInputRef = useRef(null);

  // Intake conversation state
  const [intake, setIntake] = useState(null);
  // null | { thinking: bool, history: [{role,content}], reply: string, ready: bool, refinedPrompt: string }
  const [intakeInput, setIntakeInput] = useState('');

  function downloadMd(name, content) {
    const blob = new Blob([content || ''], { type: 'text/markdown' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${(name || 'document').replace(/[^a-z0-9]/gi, '_').toLowerCase()}.md`;
    a.click();
    URL.revokeObjectURL(url);
  }

  async function callIntake(userMessage, history) {
    setIntake(prev => ({ ...(prev || { history: [], reply: '', ready: false, refinedPrompt: '' }), thinking: true }));
    try {
      const res = await api('POST', '/api/intake', {
        message: userMessage,
        wf_id: selectedWfForRun,
        history: history || [],
      });
      if (res.type === 'ready') {
        setIntake({ thinking: false, history, reply: res.reply, ready: true, refinedPrompt: res.refined_prompt });
        // Auto-launch after brief pause to show the "Ready" state
        setTimeout(() => {
          setRunInput(res.refined_prompt);
          setIntake(null);
          startRun(selectedWfForRun, res.refined_prompt);
          if (onRunComplete) onRunComplete();
        }, 1200);
      } else {
        const newHistory = [...(history || []), { role: 'user', content: userMessage }, { role: 'assistant', content: res.reply }];
        setIntake({ thinking: false, history: newHistory, reply: res.reply, ready: false, refinedPrompt: '' });
        setIntakeInput('');
        setTimeout(() => intakeInputRef.current && intakeInputRef.current.focus(), 50);
      }
    } catch (err) {
      setIntake(null);
      // Fall back to direct launch if intake fails
      startRun(selectedWfForRun, userMessage);
    }
  }

  function handleRunClick() {
    if (!runInput.trim() || !selectedWfForRun || running) return;
    callIntake(runInput, []);
  }

  async function handleIntakeSend() {
    if (!intakeInput.trim() || !intake || intake.thinking) return;
    const userMsg = intakeInput.trim();
    setIntakeInput('');
    await callIntake(userMsg, intake.history);
  }

  function cancelIntake() {
    setIntake(null);
    setIntakeInput('');
  }

  useEffect(() => {
    if (tlRef.current) tlRef.current.scrollTop = tlRef.current.scrollHeight;
  }, [activeRun?.log, sim?.log]);

  const displayLog = simMode ? (sim?.log || []) : (activeRun?.log || []);
  const displayStatus = simMode ? (sim?.running ? 'running' : 'completed') : (activeRun?.status || 'idle');

  function statusPill(status) {
    return (
      <span className={`status-pill status-${status}`}>
        {status === 'running' && <span className="pulse-dot" />}
        {status.charAt(0).toUpperCase() + status.slice(1)}
      </span>
    );
  }

  return (
    <div style={{ display:'flex', height:'100%', overflow:'hidden' }}>

      {/* Left: recent runs history */}
      <div style={{ width:220, minWidth:220, borderRight:'1px solid #1b2640', padding:16, overflow:'auto', flexShrink:0 }}>
        <div style={{ fontWeight:600, fontSize:'0.78rem', color:'#748090', marginBottom:10, textTransform:'uppercase', letterSpacing:'0.06em' }}>Run History</div>
        {runs.length === 0 && <div className="text-xs" style={{ color:'#344054' }}>No runs yet. Start one above.</div>}
        {runs.slice(0, 25).map(run => (
          <div key={run.id}
            className={`card-sm mb-8 ${run.id === activeRunId && !simMode ? 'active-wf' : ''}`}
            style={{ cursor:'pointer', padding:'10px 12px' }}
            onClick={() => { setActiveRunId(run.id); stopSim(); }}
          >
            <div className="row-between" style={{ marginBottom:4 }}>
              <div style={{ fontWeight:500, fontSize:'0.8rem', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', flex:1 }}>{run.wfName}</div>
              <span className={`status-pill status-${run.status}`} style={{ fontSize:'0.68rem', padding:'1px 5px', flexShrink:0, marginLeft:4 }}>
                {run.status}
              </span>
            </div>
            <div className="text-xs" style={{ overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', color:'#4a5568' }}>
              {run.input}
            </div>
          </div>
        ))}
      </div>

      {/* Main area: hero launch + timeline */}
      <div style={{ flex:1, display:'flex', flexDirection:'column', overflow:'hidden' }}>

        {/* ── Hero launch section ── */}
        <div style={{ padding:'20px 28px 18px', borderBottom:'1px solid #1b2640', background:'#0d1220', flexShrink:0 }}>
          <div style={{ maxWidth:780 }}>
            <div style={{ fontSize:'1.05rem', fontWeight:700, marginBottom:3, color:'#e8e6df' }}>What would you like to build?</div>
            <div style={{ fontSize:'0.8rem', color:'#748090', marginBottom:12 }}>
              Describe the change, enhancement, bug, or request. The AI will ask a clarifying question if it needs more detail before launching.
            </div>

            {/* Intake conversation (visible when active) */}
            {intake && (
              <div style={{ background:'#111827', border:'1px solid #1b2640', borderRadius:8, padding:'14px 16px', marginBottom:12 }}>
                {/* History bubbles */}
                {intake.history.map((h, i) => (
                  <div key={i} style={{ marginBottom:10, display:'flex', flexDirection:'column',
                    alignItems: h.role === 'user' ? 'flex-end' : 'flex-start' }}>
                    <div style={{
                      maxWidth:'85%', padding:'8px 12px', borderRadius:8, fontSize:'0.82rem', lineHeight:1.55,
                      background: h.role === 'user' ? 'rgba(200,168,74,0.15)' : '#172038',
                      color: h.role === 'user' ? '#c8a84a' : '#c8c4bc',
                      border: h.role === 'user' ? '1px solid rgba(200,168,74,0.3)' : '1px solid #1b2640',
                    }}>{h.content}</div>
                  </div>
                ))}

                {/* Current AI reply or thinking */}
                {intake.thinking && (
                  <div style={{ fontSize:'0.82rem', color:'#748090', fontStyle:'italic', marginBottom:8 }}>Thinking…</div>
                )}
                {!intake.thinking && intake.reply && !intake.ready && (
                  <div style={{ marginBottom:12, display:'flex', alignItems:'flex-start' }}>
                    <div style={{ maxWidth:'85%', padding:'8px 12px', borderRadius:8, fontSize:'0.82rem',
                      lineHeight:1.55, background:'#172038', color:'#c8c4bc', border:'1px solid #1b2640' }}>
                      {intake.reply}
                    </div>
                  </div>
                )}
                {!intake.thinking && intake.ready && (
                  <div style={{ fontSize:'0.82rem', color:'#4ade80', marginBottom:8 }}>
                    ✓ Ready — launching now…
                  </div>
                )}

                {/* Reply input */}
                {!intake.thinking && !intake.ready && (
                  <div style={{ display:'flex', gap:8, alignItems:'flex-end' }}>
                    <textarea ref={intakeInputRef} rows={2}
                      value={intakeInput}
                      onChange={e => setIntakeInput(e.target.value)}
                      onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleIntakeSend(); } }}
                      placeholder="Reply… (Enter to send)"
                      style={{ flex:1, fontSize:'0.82rem', resize:'none' }} />
                    <div style={{ display:'flex', flexDirection:'column', gap:6 }}>
                      <button className="btn btn-gold btn-sm"
                        disabled={!intakeInput.trim()}
                        onClick={handleIntakeSend}>Send</button>
                      <button className="btn btn-ghost btn-sm" onClick={cancelIntake}
                        style={{ fontSize:'0.72rem' }}>Skip</button>
                    </div>
                  </div>
                )}
              </div>
            )}

            {/* Main prompt textarea (hidden during active intake) */}
            {!intake && (
              <textarea
                style={{ width:'100%', minHeight:76 }} rows={3}
                placeholder="e.g. Add email validation to the Contact object. Show an inline error when the format is invalid and block save until corrected..."
                value={runInput}
                onChange={e => setRunInput(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter' && e.metaKey) handleRunClick(); }}
              />
            )}

            {/* Workflow selector pills */}
            <div style={{ display:'flex', gap:6, flexWrap:'wrap', margin:'10px 0 14px' }}>
              {workflows.map(wf => (
                <button key={wf.id}
                  onClick={() => setSelectedWfForRun(wf.id)}
                  style={{
                    padding:'5px 13px', borderRadius:20, fontSize:'0.79rem', fontWeight:500, cursor:'pointer',
                    border: selectedWfForRun === wf.id ? '1px solid #c8a84a' : '1px solid #273558',
                    background: selectedWfForRun === wf.id ? 'rgba(200,168,74,0.12)' : 'transparent',
                    color: selectedWfForRun === wf.id ? '#c8a84a' : '#748090',
                    transition:'all 0.15s',
                  }}>
                  {wf.name}
                </button>
              ))}
            </div>
            <div className="row" style={{ gap:8 }}>
              <button className="btn btn-gold"
                disabled={running || (!runInput.trim() && !intake) || !selectedWfForRun || (intake && (intake.thinking || intake.ready))}
                onClick={handleRunClick}
                style={{ minWidth:148 }}>
                {running ? '⏳ Running…' : intake?.thinking ? '💬 Thinking…' : '▶ Run Workflow'}
              </button>
              {running && activeRunId && (
                <button className="btn btn-danger btn-sm" onClick={() => stopRun(activeRunId)}>■ Stop</button>
              )}
              <button className="btn btn-outline btn-sm"
                onClick={() => { const wf = workflows.find(w => w.id === selectedWfForRun); if (wf) runSimulation(wf); }}>
                ◈ Simulate
              </button>
              {simMode && (
                <button className="btn btn-ghost btn-sm" onClick={stopSim}>✕ End Simulation</button>
              )}
            </div>
          </div>
        </div>

        {/* ── Timeline + documents ── */}
        <div style={{ flex:1, display:'flex', overflow:'hidden' }}>

          {/* Timeline */}
          <div style={{ flex:1, padding:20, overflow:'auto', display:'flex', flexDirection:'column', gap:14 }}>
            {simMode && (
              <div className="sim-banner">◈ Simulation — structural dry-run only, no AI calls. {sim?.wfName}</div>
            )}

            {(activeRun || simMode) ? (
              <>
                <div className="row-between">
                  <div>
                    <div style={{ fontWeight:600, fontSize:'0.95rem' }}>
                      {simMode ? (sim?.wfName || 'Simulation') : activeRun?.wfName}
                    </div>
                    {!simMode && activeRun?.input && (
                      <div className="text-muted mt-8" style={{ fontSize:'0.8rem' }}>{activeRun.input}</div>
                    )}
                  </div>
                  {statusPill(displayStatus)}
                </div>

                {!simMode && activeRun?.pendingHuman && (
                  <div className="human-gate">
                    <div className="human-gate-title">⏸ Human Checkpoint</div>
                    <div className="human-gate-prompt">{activeRun.pendingHuman.prompt || 'Your review is required before this run can continue.'}</div>
                    <textarea style={{ width:'100%', marginBottom:10 }} rows={2} placeholder="Optional notes…"
                      value={humanNotes} onChange={e => setHumanNotes(e.target.value)} />
                    <div className="human-gate-actions">
                      <button className="btn btn-gold btn-sm" onClick={() => resolveHuman(activeRun.id, activeRun.pendingHuman.id, true, humanNotes)}>
                        ✓ Approve &amp; Continue
                      </button>
                      <button className="btn btn-danger btn-sm" onClick={() => resolveHuman(activeRun.id, activeRun.pendingHuman.id, false, humanNotes)}>
                        ✕ Reject
                      </button>
                    </div>
                  </div>
                )}

                <div className="card" style={{ flex:1, overflow:'hidden', display:'flex', flexDirection:'column' }}>
                  <div style={{ fontWeight:600, fontSize:'0.85rem', marginBottom:12 }}>Timeline</div>
                  <div className="timeline" ref={tlRef} style={{ overflow:'auto', flex:1 }}>
                    {displayLog.length === 0 && <div className="empty-state">Waiting for first event…</div>}
                    {displayLog.map((entry, i) => {
                      const color = EVENT_COLORS[entry.type] || EVENT_COLORS[entry.event] || '#748090';
                      const timeStr = entry.t ? `${(entry.t/1000).toFixed(1)}s` : (entry.time ? new Date(entry.time).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit',second:'2-digit'}) : '');
                      return (
                        <div key={i} className="tl-entry">
                          <div className="tl-time">{timeStr}</div>
                          <div className="tl-dot" style={{ background:color }} />
                          <div className="tl-text">
                            {entry.stage && <b>{entry.stage}</b>}{entry.stage && ' — '}
                            {entry.detail || entry.event}
                            {entry.verdict && <div className="tl-verdict" style={{ color }}>{entry.verdict}</div>}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              </>
            ) : (
              <div className="empty-state" style={{ paddingTop:60 }}>
                Select a workflow above and describe your work item to get started.
              </div>
            )}
          </div>

          {/* Documents panel */}
          {!simMode && activeRun?.docs && Object.keys(activeRun.docs).length > 0 && (
            <div style={{ width:340, minWidth:340, borderLeft:'1px solid #1b2640', padding:16, overflow:'auto' }}>
              <div style={{ fontWeight:600, fontSize:'0.88rem', marginBottom:12 }}>Generated Documents</div>
              {Object.entries(activeRun.docs).map(([stageId, doc]) => (
                <div key={stageId} className="doc-card">
                  <div className="row-between" style={{ marginBottom:8 }}>
                    <div className="doc-name" style={{ marginBottom:0 }}>{doc.deliverableName || stageId}</div>
                    <div className="row" style={{ gap:4, flexShrink:0 }}>
                      <button className="btn btn-outline btn-xs"
                        onClick={() => setExpandedDoc({ name: doc.deliverableName || stageId, content: doc.content })}>
                        ⤢ Expand
                      </button>
                      <button className="btn btn-outline btn-xs"
                        onClick={() => downloadMd(doc.deliverableName || stageId, doc.content)}>
                        ↓ .md
                      </button>
                    </div>
                  </div>
                  <div className="doc-content">{doc.content}</div>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>

      {/* Expanded document modal */}
      {expandedDoc && (
        <div className="modal-overlay" onClick={(e) => e.target === e.currentTarget && setExpandedDoc(null)}>
          <div className="modal doc-modal">
            <div className="modal-head">
              <div style={{ fontWeight:600, fontSize:'0.95rem' }}>{expandedDoc.name}</div>
              <div className="row" style={{ gap:6 }}>
                <button className="btn btn-outline btn-sm"
                  onClick={() => downloadMd(expandedDoc.name, expandedDoc.content)}>
                  ↓ Download .md
                </button>
                <button className="btn btn-ghost btn-sm" onClick={() => setExpandedDoc(null)}>✕</button>
              </div>
            </div>
            <div className="modal-body">
              <div className="doc-modal-content">{expandedDoc.content}</div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Agents Page ─────────────────────────────────────────────────────────────────
function AgentsPage({ agents, activeAgentId, setActiveAgentId, activeAgent,
  expandedSkillId, setExpandedSkillId, toggleSkill, editSkillPrompt, revertSkill }) {

  return (
    <div style={{ display:'flex', height:'100%', overflow:'hidden' }}>
      {/* Agent grid */}
      <div style={{ flex:1, padding:20, overflow:'auto' }}>
        <div style={{ fontWeight:600, fontSize:'0.95rem', marginBottom:16 }}>Agent Library</div>
        <div className="agents-grid">
          {agents.map(agent => (
            <div key={agent.id}
              className={`agent-card ${agent.id === activeAgentId ? 'active' : ''}`}
              onClick={() => setActiveAgentId(agent.id === activeAgentId ? null : agent.id)}
            >
              <div className="agent-card-head">
                <div className="agent-avatar" style={{ background: agent.color || '#273558', color:'#fff', width:32, height:32 }}>
                  {agent.initials || agent.role?.slice(0,2).toUpperCase()}
                </div>
                <div>
                  <div className="agent-role">{agent.role}</div>
                  {agent.meta && <span className="badge badge-blue" style={{ fontSize:'0.65rem' }}>Meta</span>}
                </div>
              </div>
              <div className="agent-tagline">{agent.tagline}</div>
              <div className="text-xs">{(agent.skills || []).filter(s => s.enabled).length} of {(agent.skills || []).length} skills enabled</div>
            </div>
          ))}
        </div>
      </div>

      {/* Right: skill editor */}
      {activeAgent && (
        <div className="inspector">
          <div className="inspector-head">
            <div>
              <div style={{ fontWeight:600, fontSize:'0.9rem' }}>{activeAgent.role}</div>
              <div className="text-muted" style={{ marginTop:2, fontSize:'0.78rem' }}>{activeAgent.tagline}</div>
            </div>
          </div>
          <div className="inspector-body">
            <div className="inspector-section">
              <div className="inspector-section-title">Skills</div>
              {(activeAgent.skills || []).map(sk => (
                <div key={sk.id} className="skill-row">
                  <input type="checkbox" className="skill-toggle"
                    checked={sk.enabled}
                    onChange={() => toggleSkill(activeAgent.id, sk.id)} />
                  <div style={{ flex:1 }}>
                    <div className="row-between">
                      <div className="row" style={{ gap:4 }}>
                        <span className="skill-name">{sk.name}</span>
                        {sk.custom && <span className="skill-modified">✎ modified</span>}
                      </div>
                      <div className="row" style={{ gap:3 }}>
                        <button className="btn btn-ghost btn-xs"
                          onClick={() => setExpandedSkillId(expandedSkillId === sk.id ? null : sk.id)}>
                          {expandedSkillId === sk.id ? '▲' : '▼'}
                        </button>
                        {sk.custom && (
                          <button className="btn btn-ghost btn-xs" onClick={() => revertSkill(activeAgent.id, sk.id)}>↺</button>
                        )}
                      </div>
                    </div>
                    {expandedSkillId === sk.id && (
                      <textarea className="skill-prompt" style={{ width:'100%', marginTop:6 }} rows={4}
                        value={sk.prompt || sk.defaultPrompt || ''}
                        onChange={e => editSkillPrompt(activeAgent.id, sk.id, e.target.value)} />
                    )}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Economics Page ───────────────────────────────────────────────────────────────
function EconomicsPage({ economics, runFinOps, activeWfId }) {
  if (!economics) {
    return (
      <div className="page">
        <div style={{ fontWeight:600, fontSize:'0.95rem', marginBottom:16 }}>Economics</div>
        <div className="empty-state">No run data yet — complete a workflow run to see cost analytics.</div>
      </div>
    );
  }

  const { totalCost, totalCalls, totalReworks, avgCostPerRun, runsCompleted, modelName } = economics;

  return (
    <div className="page">
      <div className="row-between mb-14">
        <div style={{ fontWeight:600, fontSize:'0.95rem' }}>Economics</div>
        {activeWfId && (
          <button className="btn btn-outline btn-sm" onClick={() => runFinOps(activeWfId)}>
            💰 Project Cost
          </button>
        )}
      </div>

      <div className="econ-grid">
        {[
          ['Total runs', runsCompleted ?? '—'],
          ['Total cost', totalCost ? `$${Number(totalCost).toFixed(4)}` : '—'],
          ['Total API calls', totalCalls ?? '—'],
          ['Avg cost / run', avgCostPerRun ? `$${Number(avgCostPerRun).toFixed(4)}` : '—'],
          ['Total reworks', totalReworks ?? '—'],
          ['Model', modelName || '—'],
        ].map(([label, val]) => (
          <div key={label} className="stat-card">
            <div className="stat-val" style={{ fontSize:'1.5rem' }}>{val}</div>
            <div className="stat-label">{label}</div>
          </div>
        ))}
      </div>

      {economics.byWorkflow?.length > 0 && (
        <div className="card mt-20">
          <div style={{ fontWeight:600, fontSize:'0.85rem', marginBottom:12 }}>By Workflow</div>
          {economics.byWorkflow.map(row => (
            <div key={row.wfId} className="row-between" style={{ padding:'8px 0', borderBottom:'1px solid #1b2640', fontSize:'0.83rem' }}>
              <span>{row.wfName}</span>
              <span className="text-gold">{row.runs} runs — {row.cost ? `$${Number(row.cost).toFixed(4)}` : '—'}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Operations Page ──────────────────────────────────────────────────────────────
function OperationsPage({ operations }) {
  if (!operations) {
    return (
      <div className="page">
        <div style={{ fontWeight:600, fontSize:'0.95rem', marginBottom:16 }}>Operations</div>
        <div className="empty-state">No run data yet — complete workflow runs to see analytics here.</div>
      </div>
    );
  }

  const { reworkHotspots, reviewerStats, stageStats } = operations;

  return (
    <div className="page">
      <div style={{ fontWeight:600, fontSize:'0.95rem', marginBottom:16 }}>Operations</div>

      {reworkHotspots?.length > 0 && (
        <div className="card mb-14">
          <div style={{ fontWeight:600, fontSize:'0.85rem', marginBottom:12 }}>Rework Hotspots</div>
          {reworkHotspots.map((h, i) => (
            <div key={i} className="row-between" style={{ padding:'7px 0', borderBottom:'1px solid #1b2640', fontSize:'0.83rem' }}>
              <span>{h.stageName}</span>
              <span className="badge badge-red">{h.count} reworks</span>
            </div>
          ))}
        </div>
      )}

      {stageStats?.length > 0 && (
        <div className="card">
          <div style={{ fontWeight:600, fontSize:'0.85rem', marginBottom:12 }}>Stage Performance</div>
          {stageStats.map((s, i) => (
            <div key={i} className="row-between" style={{ padding:'7px 0', borderBottom:'1px solid #1b2640', fontSize:'0.83rem' }}>
              <span>{s.stageName}</span>
              <span className="text-muted">{s.avgRevisions?.toFixed(1) || '0'} avg revisions</span>
            </div>
          ))}
        </div>
      )}

      {!reworkHotspots?.length && !stageStats?.length && (
        <div className="empty-state">Not enough run data yet for analytics.</div>
      )}
    </div>
  );
}

// ─── Documents Page ───────────────────────────────────────────────────────────────
function DocumentsPage({ allDocs }) {
  const [expandedDoc, setExpandedDoc] = React.useState(null);
  const [filterType, setFilterType] = React.useState('');

  function downloadMd(name, content) {
    const blob = new Blob([content || ''], { type: 'text/markdown' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${(name || 'document').replace(/[^a-z0-9]/gi, '_').toLowerCase()}.md`;
    a.click();
    URL.revokeObjectURL(url);
  }

  // Group by deliverable_name
  const groups = {};
  allDocs.forEach(d => {
    const key = d.deliverable_name || 'Untitled';
    if (!groups[key]) groups[key] = [];
    groups[key].push(d);
  });
  const groupKeys = Object.keys(groups).sort();
  const filtered = filterType ? [filterType] : groupKeys;

  return (
    React.createElement('div', { className: 'page' },
      React.createElement('div', { style: { fontWeight:600, fontSize:'0.95rem', marginBottom:4 } }, 'Documents'),
      React.createElement('div', { className: 'text-muted mb-14', style: { lineHeight:1.6 } },
        `${allDocs.length} document${allDocs.length !== 1 ? 's' : ''} generated across all runs, organized by deliverable type. Click any document to expand it.`
      ),

      allDocs.length === 0 && React.createElement('div', { className: 'empty-state', style: { paddingTop:40 } },
        'No documents yet. Complete a workflow run to generate deliverables.'
      ),

      /* Type filter pills */
      groupKeys.length > 1 && React.createElement('div', {
        style: { display:'flex', gap:6, flexWrap:'wrap', marginBottom:18 }
      },
        React.createElement('button', {
          onClick: () => setFilterType(''),
          style: {
            padding:'4px 12px', borderRadius:20, fontSize:'0.76rem', cursor:'pointer',
            border: !filterType ? '1px solid #c8a84a' : '1px solid #273558',
            background: !filterType ? 'rgba(200,168,74,0.12)' : 'transparent',
            color: !filterType ? '#c8a84a' : '#748090',
          }
        }, 'All'),
        groupKeys.map(key => React.createElement('button', {
          key,
          onClick: () => setFilterType(filterType === key ? '' : key),
          style: {
            padding:'4px 12px', borderRadius:20, fontSize:'0.76rem', cursor:'pointer',
            border: filterType === key ? '1px solid #c8a84a' : '1px solid #273558',
            background: filterType === key ? 'rgba(200,168,74,0.12)' : 'transparent',
            color: filterType === key ? '#c8a84a' : '#748090',
          }
        }, `${key} (${groups[key].length})`)
        )
      ),

      /* Groups */
      filtered.map(key => {
        const docs = groups[key] || [];
        return React.createElement('div', { key, style: { marginBottom:28 } },
          React.createElement('div', {
            style: { display:'flex', alignItems:'center', gap:8, borderBottom:'1px solid #1b2640',
                     paddingBottom:6, marginBottom:10 }
          },
            React.createElement('span', {
              style: { fontWeight:600, fontSize:'0.78rem', textTransform:'uppercase',
                       letterSpacing:'0.06em', color:'#748090' }
            }, key),
            React.createElement('span', {
              style: { fontSize:'0.72rem', background:'#1b2640', borderRadius:10,
                       padding:'1px 7px', color:'#748090' }
            }, docs.length)
          ),
          docs.map(doc => React.createElement('div', {
            key: doc.id,
            style: { background:'#111827', border:'1px solid #1b2640', borderRadius:6,
                     padding:'10px 14px', marginBottom:8, cursor:'pointer' },
            onClick: () => setExpandedDoc(doc),
          },
            React.createElement('div', {
              style: { display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:6 }
            },
              React.createElement('div', null,
                React.createElement('span', { style: { fontSize:'0.82rem', color:'#748090' } },
                  doc.wf_name || 'Unknown workflow'
                ),
                doc.started_at && React.createElement('span', {
                  style: { fontSize:'0.75rem', color:'#344054', marginLeft:10 }
                }, new Date(doc.started_at).toLocaleDateString())
              ),
              React.createElement('div', { style: { display:'flex', gap:6 } },
                React.createElement('button', {
                  className: 'btn btn-outline btn-xs',
                  onClick: e => { e.stopPropagation(); setExpandedDoc(doc); }
                }, '⤢ Expand'),
                React.createElement('button', {
                  className: 'btn btn-outline btn-xs',
                  onClick: e => { e.stopPropagation(); downloadMd(doc.deliverable_name, doc.content); }
                }, '↓ .md')
              )
            ),
            React.createElement('div', {
              style: { fontSize:'0.8rem', color:'#748090', lineHeight:1.5,
                       overflow:'hidden', display:'-webkit-box', WebkitLineClamp:3,
                       WebkitBoxOrient:'vertical', whiteSpace:'pre-wrap' }
            }, (doc.content || '').slice(0, 300) + (doc.content?.length > 300 ? '…' : ''))
          ))
        );
      }),

      /* Expand modal */
      expandedDoc && React.createElement('div', {
        className: 'modal-overlay',
        onClick: e => e.target === e.currentTarget && setExpandedDoc(null)
      },
        React.createElement('div', { className: 'modal doc-modal' },
          React.createElement('div', { className: 'modal-head' },
            React.createElement('div', null,
              React.createElement('div', { style: { fontWeight:600, fontSize:'0.95rem' } }, expandedDoc.deliverable_name || 'Document'),
              React.createElement('div', { className: 'text-muted', style: { fontSize:'0.78rem', marginTop:2 } },
                `${expandedDoc.wf_name} — ${expandedDoc.started_at ? new Date(expandedDoc.started_at).toLocaleString() : ''}`
              )
            ),
            React.createElement('div', { className: 'row', style: { gap:6 } },
              React.createElement('button', {
                className: 'btn btn-outline btn-sm',
                onClick: () => downloadMd(expandedDoc.deliverable_name, expandedDoc.content)
              }, '↓ Download .md'),
              React.createElement('button', {
                className: 'btn btn-ghost btn-sm',
                onClick: () => setExpandedDoc(null)
              }, '✕')
            )
          ),
          React.createElement('div', { className: 'modal-body' },
            React.createElement('div', { className: 'doc-modal-content' }, expandedDoc.content)
          )
        )
      )
    )
  );
}

// ─── Org Context Page ─────────────────────────────────────────────────────────────
const ORG_CATEGORIES = [
  { key: 'overview',      label: 'Org Overview',               hint: 'Industry, scale, edition (Enterprise/Unlimited), user count, sandbox vs. production, org ID' },
  { key: 'objects',       label: 'Object & Field Model',        hint: 'Custom objects, important fields, non-standard naming, key lookup/master-detail relationships' },
  { key: 'automations',   label: 'Automations & Flows',         hint: 'Flows, Process Builder, Apex triggers, workflow rules — include names of critical automations' },
  { key: 'integrations',  label: 'Integrations',                hint: 'External systems, middleware, APIs, named credentials (MuleSoft, Heroku Connect, etc.)' },
  { key: 'security',      label: 'Security Model',              hint: 'Profiles, permission sets, org-wide defaults, sharing rules, field-level security' },
  { key: 'data',          label: 'Data Governance',             hint: 'Data quality rules, deduplication, ownership model, master-detail relationships, rollup summaries' },
  { key: 'conventions',   label: 'Naming Conventions',          hint: 'API naming patterns, label conventions, field prefix rules, namespace prefix' },
  { key: 'business',      label: 'Business Rules & Processes',  hint: 'Validation rules, approval processes, required logic, key business process flows' },
  { key: 'open_work',     label: 'Open Work & Known Issues',    hint: 'Active projects, known bugs, upcoming changes, frozen areas, deployment windows' },
  { key: 'other',         label: 'Other',                       hint: 'Anything else agents should know about your org' },
];

function CritDots({ value, onChange }) {
  return (
    React.createElement('div', { style: { display:'flex', gap:3, alignItems:'center' } },
      [1,2,3,4,5].map(n =>
        React.createElement('span', {
          key: n,
          title: ['','Minimal','Low','Standard','High','Critical'][n],
          onClick: onChange ? () => onChange(n) : undefined,
          style: {
            cursor: onChange ? 'pointer' : 'default',
            fontSize: '0.72rem',
            lineHeight: 1,
            color: n <= value ? 'var(--accent)' : 'var(--border)',
            userSelect: 'none',
          }
        }, '●')
      )
    )
  );
}

function OrgContextPage({ orgEntries, onCreateEntry, onUpdateEntry, onDeleteEntry }) {
  const [addingTo, setAddingTo] = React.useState(null);
  const [draft, setDraft] = React.useState({ title: '', description: '', criticality: 3 });
  const [editId, setEditId] = React.useState(null);
  const [editDraft, setEditDraft] = React.useState(null);
  const [saving, setSaving] = React.useState(false);

  function startAdd(catKey) {
    setAddingTo(catKey);
    setDraft({ title: '', description: '', criticality: 3 });
    setEditId(null);
    setEditDraft(null);
  }

  function cancelAdd() { setAddingTo(null); }

  async function saveNew(catKey) {
    if (!draft.title.trim() && !draft.description.trim()) { setAddingTo(null); return; }
    setSaving(true);
    try { await onCreateEntry({ category: catKey, ...draft }); } finally { setSaving(false); }
    setAddingTo(null);
  }

  function startEdit(entry) {
    setEditId(entry.id);
    setEditDraft({ title: entry.title, description: entry.description, criticality: entry.criticality });
    setAddingTo(null);
  }

  function cancelEdit() { setEditId(null); setEditDraft(null); }

  async function saveEdit(entryId) {
    setSaving(true);
    try { await onUpdateEntry(entryId, editDraft); } finally { setSaving(false); }
    setEditId(null);
    setEditDraft(null);
  }

  async function handleDelete(id) {
    if (!window.confirm('Remove this context entry?')) return;
    await onDeleteEntry(id);
  }

  const totalEntries = orgEntries.length;

  return (
    React.createElement('div', { className: 'page' },
      React.createElement('div', { style: { fontWeight:600, fontSize:'0.95rem', marginBottom:4 } }, 'Org Context'),
      React.createElement('div', { className: 'text-muted mb-14', style: { lineHeight:1.6 } },
        `Injected into every agent prompt at run time. ${totalEntries} ${totalEntries === 1 ? 'entry' : 'entries'} across ${ORG_CATEGORIES.length} categories. Agents treat higher-priority entries as stronger constraints.`
      ),

      ORG_CATEGORIES.map(cat => {
        const entries = orgEntries.filter(e => e.category === cat.key);
        const isAdding = addingTo === cat.key;

        return React.createElement('div', { key: cat.key, style: { marginBottom: 28 } },

          /* ── Section header ── */
          React.createElement('div', {
            style: { display:'flex', alignItems:'center', justifyContent:'space-between',
                     borderBottom:'1px solid var(--border)', paddingBottom:6, marginBottom:10 }
          },
            React.createElement('div', { style: { display:'flex', alignItems:'center', gap:8 } },
              React.createElement('span', {
                style: { fontWeight:600, fontSize:'0.78rem', textTransform:'uppercase',
                         letterSpacing:'0.06em', color:'var(--text-muted)' }
              }, cat.label),
              entries.length > 0 && React.createElement('span', {
                style: { fontSize:'0.72rem', color:'var(--text-muted)',
                         background:'var(--border)', borderRadius:10, padding:'1px 7px' }
              }, entries.length)
            ),
            !isAdding && React.createElement('button', {
              className: 'btn-ghost',
              style: { fontSize:'0.72rem', padding:'2px 10px' },
              onClick: () => startAdd(cat.key)
            }, '+ Add')
          ),

          /* ── Empty hint ── */
          entries.length === 0 && !isAdding && React.createElement('div', {
            style: { fontSize:'0.78rem', color:'var(--text-muted)', fontStyle:'italic',
                     paddingLeft:2, paddingBottom:4 }
          }, cat.hint),

          /* ── Entry cards ── */
          entries.map(entry =>
            React.createElement('div', {
              key: entry.id,
              style: { background:'var(--surface)', border: editId === entry.id
                ? '1px solid var(--accent)' : '1px solid var(--border)',
                borderRadius:6, padding:'10px 12px', marginBottom:6 }
            },
              editId === entry.id
                /* Edit mode */
                ? React.createElement('div', null,
                    React.createElement('div', { style: { display:'flex', gap:8, marginBottom:8, alignItems:'center' } },
                      React.createElement('input', {
                        value: editDraft.title,
                        onChange: e => setEditDraft(d => ({...d, title: e.target.value})),
                        placeholder: 'Entry title',
                        style: { flex:1, fontSize:'0.85rem' },
                        autoFocus: true,
                      }),
                      React.createElement('div', { style: { display:'flex', alignItems:'center', gap:6, flexShrink:0 } },
                        React.createElement('span', { style: { fontSize:'0.72rem', color:'var(--text-muted)' } }, 'Priority'),
                        React.createElement(CritDots, {
                          value: editDraft.criticality,
                          onChange: v => setEditDraft(d => ({...d, criticality: v}))
                        })
                      )
                    ),
                    React.createElement('textarea', {
                      rows: 3,
                      value: editDraft.description,
                      onChange: e => setEditDraft(d => ({...d, description: e.target.value})),
                      placeholder: 'Describe what agents need to know…',
                      style: { width:'100%', fontSize:'0.82rem', marginBottom:8 }
                    }),
                    React.createElement('div', { style: { display:'flex', gap:8 } },
                      React.createElement('button', {
                        className: 'btn-primary',
                        style: { fontSize:'0.78rem', padding:'4px 14px' },
                        disabled: saving,
                        onClick: () => saveEdit(entry.id)
                      }, saving ? 'Saving…' : 'Save'),
                      React.createElement('button', {
                        className: 'btn-ghost',
                        style: { fontSize:'0.78rem', padding:'4px 10px' },
                        onClick: cancelEdit
                      }, 'Cancel')
                    )
                  )
                /* View mode */
                : React.createElement('div', { style: { display:'flex', alignItems:'flex-start', gap:10 } },
                    React.createElement('div', {
                      style: { flex:1, cursor:'pointer' },
                      onClick: () => startEdit(entry)
                    },
                      React.createElement('div', {
                        style: { display:'flex', alignItems:'center', gap:8,
                                 marginBottom: entry.description ? 4 : 0 }
                      },
                        React.createElement(CritDots, { value: entry.criticality }),
                        entry.title && React.createElement('span', {
                          style: { fontWeight:500, fontSize:'0.85rem' }
                        }, entry.title)
                      ),
                      entry.description && React.createElement('div', {
                        style: { fontSize:'0.82rem', color:'var(--text-muted)', lineHeight:1.55, paddingLeft:1 }
                      }, entry.description)
                    ),
                    React.createElement('button', {
                      className: 'btn-ghost',
                      title: 'Delete',
                      style: { padding:'2px 7px', fontSize:'0.85rem', color:'var(--text-muted)',
                               flexShrink:0, lineHeight:1 },
                      onClick: () => handleDelete(entry.id)
                    }, '×')
                  )
            )
          ),

          /* ── Add form ── */
          isAdding && React.createElement('div', {
            style: { background:'var(--surface)', border:'1px solid var(--accent)',
                     borderRadius:6, padding:'12px', marginTop: entries.length ? 6 : 0 }
          },
            React.createElement('div', { style: { display:'flex', gap:8, marginBottom:8, alignItems:'center' } },
              React.createElement('input', {
                value: draft.title,
                onChange: e => setDraft(d => ({...d, title: e.target.value})),
                placeholder: `Title — e.g. "${cat.hint.split(',')[0]}"`,
                style: { flex:1, fontSize:'0.85rem' },
                autoFocus: true,
                onKeyDown: e => { if (e.key === 'Enter') saveNew(cat.key); if (e.key === 'Escape') cancelAdd(); }
              }),
              React.createElement('div', { style: { display:'flex', alignItems:'center', gap:6, flexShrink:0 } },
                React.createElement('span', { style: { fontSize:'0.72rem', color:'var(--text-muted)' } }, 'Priority'),
                React.createElement(CritDots, {
                  value: draft.criticality,
                  onChange: v => setDraft(d => ({...d, criticality: v}))
                })
              )
            ),
            React.createElement('textarea', {
              rows: 3,
              value: draft.description,
              onChange: e => setDraft(d => ({...d, description: e.target.value})),
              placeholder: 'Describe what agents need to know about this…',
              style: { width:'100%', fontSize:'0.82rem', marginBottom:8 },
              onKeyDown: e => { if (e.key === 'Escape') cancelAdd(); }
            }),
            React.createElement('div', { style: { display:'flex', gap:8 } },
              React.createElement('button', {
                className: 'btn-primary',
                style: { fontSize:'0.78rem', padding:'4px 14px' },
                disabled: saving,
                onClick: () => saveNew(cat.key)
              }, saving ? 'Saving…' : 'Save'),
              React.createElement('button', {
                className: 'btn-ghost',
                style: { fontSize:'0.78rem', padding:'4px 10px' },
                onClick: cancelAdd
              }, 'Cancel')
            )
          )
        );
      })
    )
  );
}

// ─── Mount ────────────────────────────────────────────────────────────────────────
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Orchestra />);
