/* ============================================================================
   DIVONCI WORLD — ARSENAL  ·  WORKFLOW BUILDER · LIVE OPS · COMMAND-ROOM SHELL
   ========================================================================== */

/* ==================================================== WORKFLOW BUILDER ==== */
/* Langflow-style node canvas: pannable / zoomable, draggable component nodes,
   typed connection ports, curved bezier wires. */
function hashMs(s) { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0; return 6 + (h % 92); }
const PER_ROW = 3, GX = 286, GY = 250, OX = 56, OY = 48;
function laneXY(i) {
  const row = Math.floor(i / PER_ROW); let col = i % PER_ROW;
  if (row % 2 === 1) col = PER_ROW - 1 - col;           // serpentine for short wires
  return { x: OX + col * GX, y: OY + row * GY };
}

/* shared run store — "Run circuit" results land here and surface in Live Operations */
const WfRunStore = window.WfRunStore || (window.WfRunStore = (function () {
  let runs = []; const subs = new Set();
  return {
    all: () => runs,
    add: (r) => { runs = [r, ...runs].slice(0, 60); subs.forEach(f => f(runs)); return r; },
    update: (id, patch) => { runs = runs.map(r => r.id === id ? { ...r, ...patch } : r); subs.forEach(f => f(runs)); },
    subscribe: (f) => { subs.add(f); return () => subs.delete(f); },
  };
})());
function stageArtifact(node) {
  const t = ARS.toolBySlug[node.toolSlug];
  const cat = t ? t.cat : "dev";
  const map = { dev: ["patch diff · 12 files", "bundle.js", "build log"], ai: ["completion.json", "draft output", "1.2k tokens"],
    design: ["8 frames exported", "components.fig", "spec sheet"], infra: ["edge bundle", "deploy manifest", "wrangler.toml"],
    db: ["migration applied", "schema.sql", "rows seeded"], media: ["render.mp4", "take-01.wav", "board.png"] };
  const arr = map[cat] || map.dev;
  return arr[Math.floor(Math.random() * arr.length)];
}

function FlowNode({ n, idx, selected, menuKind, running, ranAt, flash, onOpenMenu, onSetTool, onSetAgent, onRun, onStartLink, onSelect, onRemove, onPointerDown, setNodeEl, setPortEl }) {
  const tool = ARS.toolBySlug[n.toolSlug];
  const ag = DW.agent(n.agent);
  const sc = DW.STATE_META[n.status].c;
  const ax = tool ? ARS.catColor(tool.cat) : "var(--violet-bright)";
  const cap = tool ? ARS.cap(tool.caps[0]) : null;
  const ms = hashMs(n.id + n.stage);
  return (
    <div className={"flownode " + (selected ? "sel " : "") + (menuKind ? "menuopen " : "") + (running ? "running " : "") + (ranAt && !running ? "ran " : "") + (flash ? "flash" : "")} style={{ left: n.x, top: n.y, "--ax": ax, "--sc": sc }}
      ref={el => setNodeEl(n.id, el)} onPointerDown={() => onSelect(n.id)}>
      {/* header — drag handle */}
      <div className="fn-head" onPointerDown={e => onPointerDown(e, n)}>
        {tool ? <TSig tool={tool} size={26} /> : <span className="fn-run" style={{ width: 26, height: 26 }}><Icon name="bolt" style={{ width: 14, height: 14 }} /></span>}
        <span className="fn-title">{n.stage}</span>
        <span className="fn-ms">{ms}ms</span>
        <button className={"fn-run focusable" + (running ? " on" : "")} title="Run this stage" onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); onRun(n.id); }}><Icon name="play" style={{ width: 10, height: 10 }} /></button>
      </div>
      <div className="fn-desc">{tool ? tool.vendor + " · " + (cap ? cap.name : tool.type) : "Custom stage"} — {n.note}</div>
      <div className="fn-body">
        <div className="fn-field">
          <div className="fn-flabel">Tool <span className="i">i</span></div>
          <button className={"fn-ctrl pick focusable " + (menuKind === "tool" ? "open" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); onOpenMenu("tool"); }}>
            <Icon name={tool ? ARS.cat(tool.cat).icon : "bolt"} className="glyph" style={{ color: ax }} /><span className="ctext" style={{ color: "var(--ink)" }}>{tool ? tool.name : "Pick a tool"}</span><Icon name="chevron" className="glyph chev" style={{ transform: "rotate(90deg)" }} />
          </button>
          {menuKind === "tool" && (
            <div className="fn-menu" onPointerDown={e => e.stopPropagation()} onWheel={e => e.stopPropagation()}>
              {ARS.CATS.filter(c => ARS.TOOLS.some(t => t.cat === c.id)).map(c => (
                <div key={c.id} className="fn-menu-grp">
                  <div className="fn-menu-cat">{c.name}</div>
                  {ARS.TOOLS.filter(t => t.cat === c.id).map(t => (
                    <button key={t.id} className={"fn-menu-item " + (t.slug === n.toolSlug ? "on" : "")} onClick={e => { e.stopPropagation(); onSetTool(n.id, t.slug); }}>
                      <TSig tool={t} size={18} /><span className="mn">{t.name}</span><span className="mt">{t.type}</span>
                    </button>
                  ))}
                </div>
              ))}
            </div>
          )}
        </div>
        <div className="fn-field">
          <div className="fn-flabel">Agent <span className="i">i</span></div>
          <button className={"fn-ctrl pick focusable " + (menuKind === "agent" ? "open" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); onOpenMenu("agent"); }}>
            <img src={ag.head} alt="" /><span className="ctext" style={{ color: "var(--ink)" }}>{ag.name}</span><Icon name="chevron" className="glyph chev" style={{ transform: "rotate(90deg)" }} />
          </button>
          {menuKind === "agent" && (
            <div className="fn-menu" onPointerDown={e => e.stopPropagation()} onWheel={e => e.stopPropagation()}>
              {DW.AGENTS.map(a => (
                <button key={a.id} className={"fn-menu-item " + (a.id === n.agent ? "on" : "")} onClick={e => { e.stopPropagation(); onSetAgent(n.id, a.id); }}>
                  <img src={a.head} alt="" style={{ width: 18, height: 18, borderRadius: 5, objectFit: "cover" }} /><span className="mn">{a.name}</span><span className="mt">{a.domain}</span>
                </button>
              ))}
            </div>
          )}
        </div>
        <div className="fn-prow">
          <div className="fn-flabel">Input <span className="i">i</span></div>
          <div className="fn-ctrl locked"><Icon name="lock" className="glyph" /><span className="ctext">Receiving input</span></div>
          <span className="port in" title="Input" data-node={n.id} style={{ "--pc": "var(--violet-bright)" }} ref={el => setPortEl(n.id + "|in", el)} />
        </div>
      </div>
      <div className="fn-orow">
        <span className="ol"><Icon name="log" className="glyph" />{cap ? cap.name : "Output"}</span>
        {running ? <span className="fn-ran live" title="Running"><span className="d" />running</span>
          : ranAt ? <span className="fn-ran" title={"Last ran " + ranAt}><Icon name="check" className="glyph" style={{ width: 9, height: 9 }} />ran {ranAt}</span> : null}
        <span className="port out" title="Drag to connect" data-node={n.id} style={{ "--pc": ax }} ref={el => setPortEl(n.id + "|out", el)} onPointerDown={e => onStartLink(n.id, e)} />
      </div>
      <button className="minilink focusable" title="Remove node" onClick={e => { e.stopPropagation(); onRemove(n.id); }}
        style={{ position: "absolute", top: 10, right: -2, padding: 4, color: "var(--ink-4)", display: selected ? "block" : "none" }}>
        <Icon name="close" className="glyph" style={{ width: 12, height: 12 }} />
      </button>
    </div>
  );
}

function WorkflowBuilder({ nav, focusWf }) {
  const [wfId, setWfId] = useState(focusWf || ARS.WORKFLOWS[0].id);
  const [flash, setFlash] = useState(!!focusWf);
  const wf = ARS.WORKFLOWS.find(w => w.id === wfId);
  const [nodes, setNodes] = useState([]);
  const [sel, setSel] = useState(null);
  const [ports, setPorts] = useState({});
  const [pan, setPan] = useState({ x: 0, y: 0 });
  const [zoom, setZoom] = useState(0.82);
  const [panning, setPanning] = useState(false);
  const [paletteCat, setPaletteCat] = useState("dev");
  const [menu, setMenu] = useState(null); // { nodeId, kind: 'tool' | 'agent' }
  const [edges, setEdges] = useState([]); // [{ from, to }]
  const [link, setLink] = useState(null); // dragging a new wire: { from, x, y } in canvas coords
  const [flow, setFlow] = useState({}); // edgeKey 'from>to' -> true while a signal is travelling it
  const [running, setRunning] = useState({}); // nodeId -> true while the signal is passing through it
  const [ran, setRan] = useState({}); // nodeId -> time string of last successful run (persists)
  const [runMsg, setRunMsg] = useState(null); // { state:'run'|'done', n, t } toolbar run status

  const nodeEls = useRef({}), portEls = useRef({});
  const drag = useRef(null), panRef = useRef(null);
  const canvasRef = useRef(null);
  const runToken = useRef(0);

  // (re)build nodes + edges when workflow changes
  useEffect(() => {
    const w = ARS.WORKFLOWS.find(x => x.id === wfId);
    const ns = w.stages.map((s, i) => ({ id: wfId + "-" + i, ...s, ...laneXY(i) }));
    setNodes(ns);
    setEdges(ns.slice(0, -1).map((n, i) => ({ from: n.id, to: ns[i + 1].id })));
    setPan({ x: 0, y: 0 }); setZoom(0.82); setSel(null); setMenu(null); setLink(null); setFlow({}); setRunning({}); setRan({}); setRunMsg(null); runToken.current++;
  }, [wfId]);

  // when opened from a Live-Ops run, load that workflow + briefly flash all nodes "ready"
  useEffect(() => {
    if (!focusWf) return;
    setWfId(focusWf); setFlash(true);
    const t = setTimeout(() => setFlash(false), 1500);
    return () => clearTimeout(t);
  }, [focusWf]);

  // measure port centres relative to their node (zoom-independent local coords)
  React.useLayoutEffect(() => {
    const m = {};
    nodes.forEach(n => {
      const ne = nodeEls.current[n.id]; if (!ne) return;
      const nr = ne.getBoundingClientRect();
      ["in", "out"].forEach(p => {
        const pe = portEls.current[n.id + "|" + p]; if (!pe) return;
        const pr = pe.getBoundingClientRect();
        m[n.id + "|" + p] = { x: (pr.left + pr.width / 2 - nr.left) / zoom, y: (pr.top + pr.height / 2 - nr.top) / zoom };
      });
    });
    setPorts(m);
  }, [nodes.length, wfId]);

  const setNodeEl = (id, el) => { if (el) nodeEls.current[id] = el; };
  const setPortEl = (k, el) => { if (el) portEls.current[k] = el; };

  // node drag — window listeners (no pointer-capture; robust against re-renders)
  function nodeDown(e, n) {
    e.stopPropagation();
    setSel(n.id); setMenu(null);
    const z = zoom;
    const start = { id: n.id, sx: e.clientX, sy: e.clientY, ox: n.x, oy: n.y };
    drag.current = start;
    const move = (ev) => {
      const dx = (ev.clientX - start.sx) / z, dy = (ev.clientY - start.sy) / z;
      setNodes(ns => ns.map(m => m.id === start.id ? { ...m, x: start.ox + dx, y: start.oy + dy } : m));
    };
    const up = () => {
      drag.current = null;
      window.removeEventListener("pointermove", move);
      window.removeEventListener("pointerup", up);
    };
    window.addEventListener("pointermove", move);
    window.addEventListener("pointerup", up);
  }

  // canvas pan — window listeners
  function canvasDown(e) {
    if (e.target.closest(".flownode")) return;
    setMenu(null);
    const start = { sx: e.clientX, sy: e.clientY, px: pan.x, py: pan.y };
    setPanning(true);
    const move = (ev) => setPan({ x: start.px + (ev.clientX - start.sx), y: start.py + (ev.clientY - start.sy) });
    const up = () => { setPanning(false); window.removeEventListener("pointermove", move); window.removeEventListener("pointerup", up); };
    window.addEventListener("pointermove", move);
    window.addEventListener("pointerup", up);
  }
  function onWheel(e) { const f = e.deltaY < 0 ? 1.08 : 0.93; setZoom(z => Math.min(1.5, Math.max(0.45, +(z * f).toFixed(3)))); }

  // wire connect / disconnect
  function portCanvasPos(id, kind) {
    const n = nodes.find(x => x.id === id), p = ports[id + "|" + kind];
    if (!n || !p) return { x: 0, y: 0 };
    return { x: n.x + p.x, y: n.y + p.y };
  }
  function startLink(fromId, e) {
    e.stopPropagation();
    const r = canvasRef.current.getBoundingClientRect();
    const px = pan.x, py = pan.y, z = zoom;
    const s = portCanvasPos(fromId, "out");
    setLink({ from: fromId, x: s.x, y: s.y });
    const move = (ev) => setLink({ from: fromId, x: (ev.clientX - r.left - px) / z, y: (ev.clientY - r.top - py) / z });
    const up = (ev) => {
      window.removeEventListener("pointermove", move);
      window.removeEventListener("pointerup", up);
      const el = document.elementFromPoint(ev.clientX, ev.clientY);
      const portEl = el && el.closest(".port.in");
      const toId = portEl && portEl.getAttribute("data-node");
      if (toId && toId !== fromId) setEdges(es => es.some(x => x.from === fromId && x.to === toId) ? es : [...es, { from: fromId, to: toId }]);
      setLink(null);
    };
    window.addEventListener("pointermove", move);
    window.addEventListener("pointerup", up);
  }
  function removeEdge(i) { setEdges(es => es.filter((_, idx) => idx !== i)); }

  function addTool(tool, at) {
    const id = "n" + Date.now();
    setNodes(ns => [...ns, { id, stage: tool.name, toolSlug: tool.slug, agent: wf.owner, status: "standby", note: "New · " + ARS.cap(tool.caps[0]).name, x: at.x, y: at.y }]);
    setSel(id);
  }
  function dropOnCanvas(e) {
    e.preventDefault();
    const slug = e.dataTransfer.getData("palette"); if (!slug) return;
    const t = ARS.toolBySlug[slug]; if (!t) return;
    const r = canvasRef.current.getBoundingClientRect();
    const x = (e.clientX - r.left - pan.x) / zoom - 125, y = (e.clientY - r.top - pan.y) / zoom - 40;
    addTool(t, { x, y });
  }
  function removeNode(id) { setNodes(ns => ns.filter(n => n.id !== id)); setEdges(es => es.filter(e => e.from !== id && e.to !== id)); setSel(s => s === id ? null : s); }
  function setNodeTool(id, slug) { setNodes(ns => ns.map(n => n.id === id ? { ...n, toolSlug: slug } : n)); setMenu(null); }
  function setNodeAgent(id, aid) { setNodes(ns => ns.map(n => n.id === id ? { ...n, agent: aid } : n)); setMenu(null); }
  // run a signal through the circuit starting from one or more nodes — lights
  // each node 'active' as the signal reaches it, animates the wires it travels,
  // then settles the node to 'clear' (done). Parallel branches fire together.
  function run(startIds) {
    if (!startIds || !startIds.length) return;
    const adj = {};
    edges.forEach(e => { (adj[e.from] = adj[e.from] || []).push(e.to); });
    const order = []; const seen = new Set();
    let frontier = startIds.slice(); let depth = 0;
    while (frontier.length) {
      const next = [];
      frontier.forEach(id => {
        if (seen.has(id)) return; seen.add(id);
        order.push({ id, depth });
        (adj[id] || []).forEach(to => next.push(to));
      });
      frontier = next.filter(id => !seen.has(id)); depth++;
    }
    const STEP = 560, token = ++runToken.current;
    setRunMsg({ state: "run", n: order.length });
    // record this run so it surfaces in Live Operations as a workflow run
    const runId = "wfr-" + Date.now();
    const wfObj = ARS.WORKFLOWS.find(w => w.id === wfId);
    const stages = order.map(({ id }) => {
      const n = nodes.find(x => x.id === id); const t = ARS.toolBySlug[n.toolSlug];
      return { node: id, name: n.stage, toolSlug: n.toolSlug, toolName: t ? t.name : n.stage, agent: n.agent, ms: hashMs(id + n.stage), status: "clear", artifact: stageArtifact(n) };
    });
    const tokensTotal = stages.reduce((s) => s + Math.floor(800 + Math.random() * 3000), 0);
    WfRunStore.add({ id: runId, kind: "workflow", t: stamp(), wf: wfId, wfName: wfObj ? wfObj.name : "Workflow",
      agent: wf.owner, stages, status: "running", dur: order.length * STEP, cost: +(stages.length * 0.04 + Math.random() * 0.3).toFixed(2), tokens: tokensTotal });
    const lastMs = (order.length ? Math.max(...order.map(o => o.depth)) : 0) * STEP + STEP;
    setTimeout(() => { if (runToken.current === token) { setRunMsg({ state: "done", n: order.length, t: stamp() }); WfRunStore.update(runId, { status: "clear" }); } }, lastMs);
    order.forEach(({ id, depth }) => {
      setTimeout(() => {
        if (runToken.current !== token) return;
        setRunning(r => ({ ...r, [id]: true }));
        setFlow(f => { const nf = { ...f }; (adj[id] || []).forEach(to => { if (seen.has(to)) nf[id + ">" + to] = true; }); return nf; });
      }, depth * STEP);
      setTimeout(() => {
        if (runToken.current !== token) return;
        setRunning(r => { const nr = { ...r }; delete nr[id]; return nr; });
        setRan(rr => ({ ...rr, [id]: stamp() }));
        setFlow(f => { const nf = { ...f }; (adj[id] || []).forEach(to => delete nf[id + ">" + to]); return nf; });
      }, depth * STEP + STEP - 40);
    });
  }
  function runAll() {
    const tg = new Set(edges.map(e => e.to));
    const roots = nodes.filter(n => !tg.has(n.id)).map(n => n.id);
    run(roots.length ? roots : nodes.slice(0, 1).map(n => n.id));
  }

  const owner = DW.agent(wf.owner);
  const paletteTools = ARS.TOOLS.filter(t => t.cat === paletteCat);

  function edgePath(a, b) {
    const dx = Math.max(46, Math.abs(b.x - a.x) * 0.5);
    return `M ${a.x},${a.y} C ${a.x + dx},${a.y} ${b.x - dx},${b.y} ${b.x},${b.y}`;
  }

  return (
    <div>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: "var(--s-6)", alignItems: "center" }}>
        <div className="seg">
          {ARS.WORKFLOWS.map(w => <button key={w.id} className={wfId === w.id ? "on" : ""} onClick={() => setWfId(w.id)}>{w.category}</button>)}
        </div>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--ink-3)", marginLeft: 6 }}>
          <img src={owner.head} alt="" style={{ width: 18, height: 18, borderRadius: 5, objectFit: "cover" }} />{wf.name} · owner {owner.name}
        </span>
        <button className="btn primary" onClick={runAll} style={{ display: "inline-flex", alignItems: "center", gap: 7, marginLeft: 4 }}>
          <Icon name="play" className="glyph" style={{ width: 13, height: 13 }} />Run circuit
        </button>
        {runMsg && (
          <span className={"runstat " + runMsg.state}>
            {runMsg.state === "run"
              ? <><span className="d" />running {runMsg.n} stage{runMsg.n === 1 ? "" : "s"}…</>
              : <><Icon name="check" className="glyph" style={{ width: 12, height: 12 }} />ran {runMsg.n} stage{runMsg.n === 1 ? "" : "s"} · {runMsg.t}</>}
          </span>
        )}
        {runMsg && runMsg.state === "done" && (
          <button className="minilink" onClick={() => nav("arsenal:ops")} style={{ fontSize: 11 }}>View run in Live Operations →</button>
        )}
        <div style={{ flex: 1 }} />
        <span className="note" style={{ color: "var(--ink-4)" }}>run a stage · drag a port to connect · click a wire to disconnect · scroll to zoom</span>
      </div>

      <div className="wfwrap">
        <div className="flowstage">
          <div ref={canvasRef} className={"flowcanvas " + (panning ? "panning" : "")}
            onPointerDown={canvasDown} onWheel={onWheel}
            onDragOver={e => e.preventDefault()} onDrop={dropOnCanvas}>
            <div className="flowpan" style={{ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` }}>
              <svg className="flowedges" width="3000" height="2400">
                {edges.map((e, i) => {
                  const a = ports[e.from + "|out"], b = ports[e.to + "|in"];
                  const na = nodes.find(n => n.id === e.from), nb = nodes.find(n => n.id === e.to);
                  if (!a || !b || !na || !nb) return null;
                  const p1 = { x: na.x + a.x, y: na.y + a.y }, p2 = { x: nb.x + b.x, y: nb.y + b.y };
                  const col = ARS.toolBySlug[na.toolSlug] ? ARS.catColor(ARS.toolBySlug[na.toolSlug].cat) : "var(--violet-bright)";
                  const d = edgePath(p1, p2);
                  return (
                    <g key={e.from + ">" + e.to + i}>
                      <path className={"edge" + (flow[e.from + ">" + e.to] ? " live" : "")} d={d} fill="none" stroke={col} strokeWidth="2" strokeOpacity="0.55" style={{ filter: `drop-shadow(0 0 4px ${col})` }} />
                      <path className="edge-hit" d={d} fill="none" stroke="transparent" strokeWidth="18" onClick={() => removeEdge(i)}><title>Click to disconnect</title></path>
                    </g>
                  );
                })}
                {link && (() => { const a = portCanvasPos(link.from, "out"); return <path d={edgePath(a, { x: link.x, y: link.y })} fill="none" stroke="var(--violet-bright)" strokeWidth="2.5" strokeDasharray="6 5" strokeOpacity="0.92" style={{ filter: "drop-shadow(0 0 5px var(--violet-bright))" }} />; })()}
              </svg>
              {nodes.map((n, i) => (
                <FlowNode key={n.id} n={n} idx={i} selected={sel === n.id}
                  menuKind={menu && menu.nodeId === n.id ? menu.kind : null}
                  running={!!running[n.id]} ranAt={ran[n.id]} flash={flash}
                  onOpenMenu={(kind) => setMenu(m => (m && m.nodeId === n.id && m.kind === kind) ? null : { nodeId: n.id, kind })}
                  onSetTool={setNodeTool} onSetAgent={setNodeAgent} onRun={(id) => run([id])} onStartLink={startLink}
                  onSelect={setSel} onRemove={removeNode}
                  onPointerDown={nodeDown}
                  setNodeEl={setNodeEl} setPortEl={setPortEl} />
              ))}
            </div>

            {nodes.length === 0 && <div className="flow-hint" style={{ top: "46%", bottom: "auto", fontSize: 12 }}>Drop a tool from the palette to begin the circuit</div>}
            <div className="flow-ctl">
              <button title="Zoom in" onClick={() => setZoom(z => Math.min(1.5, +(z + 0.1).toFixed(2)))}>+</button>
              <button title="Zoom out" onClick={() => setZoom(z => Math.max(0.45, +(z - 0.1).toFixed(2)))}>−</button>
              <button title="Reset view" onClick={() => { setPan({ x: 0, y: 0 }); setZoom(0.82); }} style={{ fontSize: 12 }}><Icon name="ops" style={{ width: 14, height: 14 }} /></button>
            </div>
            <div className="flow-zoom">{Math.round(zoom * 100)}%</div>
          </div>
        </div>

        {/* palette */}
        <Panel style={{ "--ax": ARS.catColor(paletteCat) }}>
          <PHead icon="plus" eyebrow="Tool palette" title="Drag onto the canvas" />
          <div style={{ padding: "var(--s-5) var(--s-5) 0" }}>
            <div className="seg" style={{ flexWrap: "wrap", display: "flex" }}>
              {["dev", "ai", "design", "infra", "db", "media"].map(cid => (
                <button key={cid} className={paletteCat === cid ? "on" : ""} onClick={() => setPaletteCat(cid)} style={{ fontSize: 9.5 }}>{ARS.cat(cid).name.split(" ")[0]}</button>
              ))}
            </div>
          </div>
          <div className="pbody">
            <div className="palette">
              {paletteTools.map(t => (
                <div key={t.id} className="palette-item" style={{ "--ax": ARS.catColor(t.cat) }} draggable
                  onDragStart={e => { e.dataTransfer.setData("palette", t.slug); e.dataTransfer.effectAllowed = "copy"; }}
                  onClick={() => addTool(t, { x: (-pan.x) / zoom + 320, y: (-pan.y) / zoom + 120 + Math.random() * 80 })}>
                  <TSig tool={t} size={24} />
                  <span className="pn">{t.name}</span>
                  <span className="pt">{t.type}</span>
                </div>
              ))}
            </div>
          </div>
        </Panel>
      </div>
    </div>
  );
}

/* ======================================================== LIVE OPS ======== */
const RUN_TEMPLATES = [
  { agent: "vv", toolSlug: "codex", action: "Generating service layer", status: "active" },
  { agent: "vv", toolSlug: "cloudflare-workers", action: "Pushing edge function", status: "clear" },
  { agent: "claws", toolSlug: "figma", action: "Syncing component frames", status: "clear" },
  { agent: "nova", toolSlug: "midjourney", action: "Rendering concept board", status: "clear" },
  { agent: "brodex", toolSlug: "github", action: "Scanning dependency tree", status: "focus" },
  { agent: "optimus", toolSlug: "posthog", action: "Auditing latency budget", status: "active" },
  { agent: "claws", toolSlug: "elevenlabs", action: "Rendering voiceover take", status: "clear" },
  { agent: "vv", toolSlug: "supabase", action: "Running migration", status: "clear" },
  { agent: "nova", toolSlug: "perplexity", action: "Sweeping market signals", status: "active" },
  { agent: "viiera", toolSlug: "anthropic", action: "Drafting council directive", status: "active" },
  { agent: "brodex", toolSlug: "stripe", action: "Verifying webhook origin", status: "caution" },
  { agent: "vv", toolSlug: "vercel", action: "Promoting preview to prod", status: "clear" },
];
function stamp() { const t = new Date(); return [t.getHours(), t.getMinutes(), t.getSeconds()].map(x => String(x).padStart(2, "0")).join(":"); }

function LiveOps({ nav, openInBuilder }) {
  const [runs, setRuns] = useState(ARS.RUNS);
  const [live, setLive] = useState(true);
  const [agentF, setAgentF] = useState("all");
  const [wfRuns, setWfRuns] = useState(() => (window.WfRunStore ? window.WfRunStore.all() : []));
  const [expanded, setExpanded] = useState(null);

  useEffect(() => { if (!window.WfRunStore) return; return window.WfRunStore.subscribe(setWfRuns); }, []);

  useEffect(() => {
    if (!live) return;
    const id = setInterval(() => {
      const tpl = RUN_TEMPLATES[Math.floor(Math.random() * RUN_TEMPLATES.length)];
      const dur = 1500 + Math.floor(Math.random() * 40000);
      const tokens = Math.random() > 0.5 ? Math.floor(Math.random() * 40000) : 0;
      const cost = +(tokens / 100000 + Math.random() * 0.2).toFixed(2);
      setRuns(r => [{ t: stamp(), ...tpl, workflow: null, dur, cost, tokens }, ...r].slice(0, 40));
    }, 3200);
    return () => clearInterval(id);
  }, [live]);

  const wfRows = wfRuns.filter(r => agentF === "all" || r.agent === agentF).map(r => ({ ...r, key: r.id }));
  const toolRows = runs.filter(r => agentF === "all" || r.agent === agentF).map((r, i) => ({ ...r, kind: "tool", key: "t" + i + r.t }));
  const rows = [...wfRows, ...toolRows];
  const activeN = runs.filter(r => r.status === "active").length + wfRuns.filter(r => r.status === "running").length;
  const totalCost = runs.reduce((s, r) => s + (r.cost || 0), 0) + wfRuns.reduce((s, r) => s + (r.cost || 0), 0);
  const totalTok = runs.reduce((s, r) => s + (r.tokens || 0), 0) + wfRuns.reduce((s, r) => s + (r.tokens || 0), 0);
  const okRate = Math.round((runs.filter(r => r.status === "clear" || r.status === "active").length / runs.length) * 100);
  const maxDur = Math.max(1, ...runs.map(r => r.dur), ...wfRuns.map(r => r.dur));

  return (
    <div>
      <div className="cols c-4" style={{ marginBottom: "var(--s-6)" }}>
        {[["Active runs", activeN, "active", "bolt"], ["Spend · session", "$" + totalCost.toFixed(2), "clear", "card"], ["Tokens · session", (totalTok / 1000).toFixed(1) + "k", "focus", "chip"], ["Success", okRate + "%", "clear", "check"]].map(([k, v, s, ic]) => (
          <Panel key={k}><div className="mtile"><div className="k"><Icon name={ic} style={{ width: 12, height: 12 }} />{k}</div><div className="v" style={{ color: DW.STATE_META[s].c }}>{v}</div></div></Panel>
        ))}
      </div>

      <Panel className="tight">
        <div className="phead" style={{ flexWrap: "wrap", gap: 12 }}>
          <div className="eyebrow"><span className="livedot" style={{ opacity: live ? 1 : 0.3 }} />Live operations feed</div>
          <div className="right" style={{ flexWrap: "wrap", gap: 10 }}>
            <div className="seg">
              <button className={agentF === "all" ? "on" : ""} onClick={() => setAgentF("all")}>All</button>
              {DW.AGENTS.map(a => <button key={a.id} className={agentF === a.id ? "on" : ""} onClick={() => setAgentF(a.id)}>{a.name}</button>)}
            </div>
            <button className={"btn " + (live ? "" : "primary")} onClick={() => setLive(l => !l)} style={{ padding: "7px 14px", display: "inline-flex", alignItems: "center", gap: 7 }}>
              <Icon name={live ? "pause" : "play"} className="glyph" style={{ width: 13, height: 13 }} />{live ? "Pause" : "Resume"}
            </button>
          </div>
        </div>
        <div className="opsrow head">
          <span>Time</span><span></span><span>Action</span><span>Tool</span><span>Cost</span><span>Duration</span>
        </div>
        <div>
          {wfRows.length === 0 && (
            <div className="ops-hint"><Icon name="branch" className="glyph" style={{ width: 13, height: 13 }} />No workflow runs yet — hit <b>Run circuit</b> in the Workflow Builder and the run lands here with its stage artifacts.</div>
          )}
          {rows.map((r) => {
            const isWf = r.kind === "workflow";
            const a = DW.agent(r.agent), tool = isWf ? null : ARS.toolBySlug[r.toolSlug];
            const sc = DW.STATE_META[r.status === "running" ? "active" : r.status].c;
            const open = expanded === r.key;
            return (
              <div key={r.key}>
                <div className={"opsrow rowlink" + (open ? " open" : "") + (isWf ? " wf" : "")} onClick={() => setExpanded(open ? null : r.key)} style={{ cursor: "pointer" }}>
                  <span className="t">{r.t}</span>
                  <span className="actor"><img src={a.head} alt={a.name} /></span>
                  <div style={{ minWidth: 0 }}>
                    <div className="act">
                      {isWf
                        ? <><b style={{ fontWeight: 600 }}>{a.name}</b> · ran <b style={{ color: "var(--violet-ink)" }}>{r.wfName}</b> <span className="ops-wftag">workflow</span></>
                        : <><b style={{ fontWeight: 600 }}>{a.name}</b> · {r.action}</>}
                    </div>
                    <div className="runbar"><i style={{ width: `${Math.max(8, (r.dur / maxDur) * 100)}%`, background: sc, boxShadow: `0 0 8px ${sc}` }} /></div>
                  </div>
                  <span className="toolref">{isWf ? <><Icon name="branch" className="glyph" style={{ width: 14, height: 14, color: "var(--violet-ink)" }} />{r.stages.length} stages</> : <>{tool ? <TSig tool={tool} size={20} /> : null}{tool ? tool.name : "—"}</>}</span>
                  <span className="num cost">{r.cost ? "$" + r.cost.toFixed(2) : "—"}</span>
                  <span className="num"><span style={{ color: sc }}>●</span> {ARS.fmtDur(r.dur)} <Icon name="chevron" className="glyph ops-chev" style={{ width: 12, height: 12, transform: open ? "rotate(270deg)" : "rotate(90deg)" }} /></span>
                </div>
                {open && (
                  <div className="ops-detail">
                    {isWf ? (
                      <>
                        <div className="ops-detail-h">Stages &amp; artifacts <span style={{ color: DW.STATE_META[r.status === "running" ? "active" : "clear"].c }}>{r.status === "running" ? "· running…" : "· complete"}</span></div>
                        <div className="ops-stages">
                          {r.stages.map((s, si) => { const sa = DW.agent(s.agent), st = ARS.toolBySlug[s.toolSlug]; return (
                            <div key={si} className="ops-stage">
                              <span className="ops-stage-n">{si + 1}</span>
                              {st ? <TSig tool={st} size={22} /> : <span className="ops-stage-n" />}
                              <div className="ops-stage-main"><b>{s.name}</b><span>{s.toolName} · {sa.name}</span></div>
                              <span className="ops-artifact"><Icon name="evidence" className="glyph" style={{ width: 11, height: 11 }} />{s.artifact}</span>
                              <span className="ops-stage-st" style={{ color: DW.STATE_META["clear"].c }}>done</span>
                            </div>
                          ); })}
                        </div>
                        <button className="minilink" onClick={(e) => { e.stopPropagation(); openInBuilder ? openInBuilder(r.wf) : nav("arsenal:workflow"); }}>Open in Workflow Builder →</button>
                      </>
                    ) : (
                      <div className="ops-tooldetail">
                        <div className="ops-tooldetail-act">{r.action}</div>
                        <div className="ops-tool-meta"><span>cost ${r.cost ? r.cost.toFixed(2) : "0.00"}</span><span>{(r.tokens / 1000).toFixed(1)}k tokens</span><span>{ARS.fmtDur(r.dur)}</span></div>
                        {tool && <button className="minilink" onClick={(e) => { e.stopPropagation(); nav("arsenal:tool:" + tool.slug); }}>Open {tool.name} in library →</button>}
                      </div>
                    )}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      </Panel>
    </div>
  );
}

/* ================================================ ARSENAL COMMAND ROOM ==== */
const ARS_TABS = [
  { id: "library",   label: "Tool Library",     icon: "ops" },
  { id: "capability",label: "Capabilities",     icon: "bolt" },
  { id: "agent",     label: "Agent Loadout",    icon: "agent" },
  { id: "workflow",  label: "Workflow Builder", icon: "branch" },
  { id: "ops",       label: "Live Operations",  icon: "device" },
];
function ArsenalScreen({ nav, sub }) {
  const [tab, setTab] = useState("library");
  const [selSlug, setSelSlug] = useState("figma");
  const [agentId, setAgentId] = useState("nova");
  const [builderWf, setBuilderWf] = useState(null); // workflow id to load in the builder (from a Live-Ops run)
  const openWorkflowInBuilder = (wfId) => { setBuilderWf(wfId); setTab("workflow"); };

  // deep-link from other screens: arsenal:tool:slug / arsenal:agent:id / arsenal:ops ...
  useEffect(() => {
    if (!sub) return;
    const parts = sub.split(":"); // e.g. ["tool","figma"]
    if (parts[0] === "tool" && parts[1]) { setSelSlug(parts[1]); setTab("library"); }
    else if (parts[0] === "agent" && parts[1]) { setAgentId(parts[1]); setTab("agent"); }
    else if (ARS_TABS.some(t => t.id === parts[0])) setTab(parts[0]);
  }, [sub]);

  // reset page scroll when switching tabs; Agent Loadout always opens on Nova
  useEffect(() => {
    const cv = document.querySelector(".canvas");
    if (cv) cv.scrollTop = 0;
    if (tab === "agent" && !sub) setAgentId("nova");
  }, [tab]);

  const counts = {
    library: ARS.TOOLS.length, capability: ARS.CAPS.length,
    agent: DW.AGENTS.length, workflow: ARS.WORKFLOWS.length, ops: ARS.RUNS.length,
  };

  return (
    <div className={"screen" + (tab === "capability" ? " ars-fill" : "")}>
      <div className="screen-head">
        <div>
          <div className="title"><span className="sub">Arsenal · Capability registry</span>Command Room</div>
          <div className="meta">Every tool, model, engine and service the empire can wield — discoverable, permission-gated and auditable. Agents read their weapons from here; nothing is hardcoded.</div>
        </div>
        <div className="screen-actions">
          <button className="btn primary" onClick={() => setTab("workflow")} style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
            <Icon name="branch" className="glyph" style={{ width: 15, height: 15 }} />Build workflow
          </button>
        </div>
      </div>

      <div className="ars-tabs" style={{ marginBottom: "var(--s-7)" }}>
        {ARS_TABS.map(t => (
          <button key={t.id} className={"ars-tab " + (tab === t.id ? "on" : "")} onClick={() => setTab(t.id)}>
            <Icon name={t.icon} className="glyph" />{t.label}<span className="count">{counts[t.id]}</span>
          </button>
        ))}
      </div>

      {tab === "library" && <ToolLibrary nav={nav} selSlug={selSlug} setSelSlug={setSelSlug} />}
      {tab === "capability" && <CapabilityView nav={nav} setSelSlug={setSelSlug} setTab={setTab} />}
      {tab === "agent" && <AgentLoadout nav={nav} agentId={agentId} setAgentId={setAgentId} setSelSlug={setSelSlug} setTab={setTab} />}
      {tab === "workflow" && <WorkflowBuilder nav={nav} focusWf={builderWf} />}
      {tab === "ops" && <LiveOps nav={nav} openInBuilder={openWorkflowInBuilder} />}
    </div>
  );
}

Object.assign(window, { WorkflowBuilder, LiveOps, ArsenalScreen });
