/* ============================================================================
   DIVONCI HQ — OFFICE SCREEN (React wrapper)
   Full-bleed pixel office canvas + a live command surface. On the stage: a
   metrics HUD, a mission-lifecycle lane, the day-clock, and a camera reset.
   In the panel: roster, a clickable agent inspector (with Assign Mission), and
   a live feed where every event flies the camera to its agent. Chat drives the
   floor — recognized commands fire scenarios. Engine + sim in office/*.js.
   Window: OfficeScreen.
   ========================================================================== */
const { useState: useStateOf, useEffect: useEffectOf, useRef: useRefOf, useMemo: useMemoOf } = React;

const OFC_ACCENT = {};
(window.OFCSim ? window.OFCSim.ROSTER : []).forEach((r) => (OFC_ACCENT[r.id] = r.accent));
OFC_ACCENT.diego = "#d8d8e2";
const OFC_ROOM = {};
(window.OFCSim ? window.OFCSim.ROSTER : []).forEach((r) => (OFC_ROOM[r.id] = r.room));
const OFC_ROLE = {
  viiera: "Approval Authority", claws: "Comms · Routing", brodex: "Audit · Vault",
  vv: "Execution Operator", optimus: "Optimization Lab", nova: "Research · Ideation",
};

const OFC_TAGC = {
  ONLINE: "#A855F7", CREATED: "#4D9FFF", ROUTED: "#A855F7", CLAIMED: "#D946EF",
  "WORKER STARTED": "#2FE0A1", "FILES APPLIED": "#2FE0A1", VALIDATED: "#2FE0A1", WORKING: "#4D9FFF",
  APPROVED: "#2FE0A1", "DEPLOY HELD": "#F5B544", DEPLOYING: "#4D9FFF", DEPLOYED: "#2FE0A1",
  CRISIS: "#F87171", "DUAL-REASONING": "#F5B544", CLEARED: "#2FE0A1",
  CONVENE: "#A855F7", ADJOURNED: "#9090A0", COFFEE: "#caa15a", BREAK: "#9090A0",
  IDLE: "#9090A0", CHAT: "#7C3AED", WORKING_AGENT: "#4D9FFF",
};

/* mission lifecycle lanes — which feed tags belong to each stage */
const OFC_STAGES = [
  { key: "created", label: "Created", color: "#4D9FFF", tags: ["CREATED"] },
  { key: "routed", label: "Routed", color: "#A855F7", tags: ["ROUTED"] },
  { key: "claimed", label: "Claimed", color: "#D946EF", tags: ["CLAIMED"] },
  { key: "working", label: "Working", color: "#4D9FFF", tags: ["WORKER STARTED", "WORKING", "FILES APPLIED", "DUAL-REASONING"] },
  { key: "validated", label: "Validated", color: "#2FE0A1", tags: ["VALIDATED", "APPROVED", "CLEARED"] },
  { key: "deployed", label: "Deployed", color: "#2FE0A1", tags: ["DEPLOYING", "DEPLOYED"] },
];
const OFC_STAGE_OF = {};
OFC_STAGES.forEach((s) => s.tags.forEach((t) => (OFC_STAGE_OF[t] = s.key)));

const OFC_HAS_CURTAIN = { viiera: true, vv: true };
const OFC_ACTIONS = [
  { act: "coffee", label: "Get coffee" },
  { act: "smoke", label: "Smoke break" },
  { act: "dance", label: "Breakdance" },
  { act: "relax", label: "Take five" },
  { act: "desk", label: "Back to desk" },
];

function ofcClock(d) {
  return [d.getHours(), d.getMinutes(), d.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
}
function fmtTok(n) {
  n = n || 0;
  if (n >= 1e6) return (n / 1e6).toFixed(2) + "M";
  if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
  return String(n);
}

function OfficeScreen() {
  const wrapRef = useRefOf(null);
  const canvasRef = useRefOf(null);
  const engineRef = useRefOf(null);
  const feedRef = useRefOf(null);
  const [feed, setFeed] = useStateOf([]);
  const [activity, setActivity] = useStateOf([]);
  const [selected, setSelected] = useStateOf(null);
  const [draft, setDraft] = useStateOf("");
  const [statuses, setStatuses] = useStateOf({});
  const [stageFilter, setStageFilter] = useStateOf(null);
  const [onlySelected, setOnlySelected] = useStateOf(false);
  const [missionDraft, setMissionDraft] = useStateOf("");
  const [dayLabel, setDayLabel] = useStateOf("");
  const [rate, setRate] = useStateOf(Array(36).fill(0));
  const [menu, setMenu] = useStateOf(null);          // { agentId, x, y }
  const [soundOn, setSoundOn] = useStateOf(() => (window.OFCSound ? !window.OFCSound.isMuted() : true));
  const [buildOn, setBuildOn] = useStateOf(false);
  const [soundMenu, setSoundMenu] = useStateOf(false);
  const [catalog, setCatalog] = useStateOf([]);
  const [remaining, setRemaining] = useStateOf({});
  const [buildSel, setBuildSel] = useStateOf(null);
  const [immersive, setImmersive] = useStateOf(false);
  const [buildCorner, setBuildCorner] = useStateOf("br");   // 'br' | 'bl'
  const [buildPos, setBuildPos] = useStateOf(null);        // free-drag {x,y} (overrides corner)
  const [tokens, setTokens] = useStateOf({});
  const [soundCfg, setSoundCfg] = useStateOf(() => (window.OFCSound ? window.OFCSound.getMap() : {}));
  const [uploadErr, setUploadErr] = useStateOf({});
  const [toast, setToast] = useStateOf(null);   // { id, label }
  const toastT = useRefOf(null);
  const menuRef = useRefOf(null);
  const roster = window.OFCSim ? window.OFCSim.ROSTER : [];
  const lastLenRef = useRefOf(0);

  useEffectOf(() => {
    if (!window.OFCEngine || !canvasRef.current) return;
    const eng = window.OFCEngine.mount(canvasRef.current, {
      onPick: (a) => { setSelected(a.id); },
      onMenu: (a, pos) => { if (!a) { setMenu(null); return; } setMenu({ agentId: a.id, x: pos ? pos.x : 0, y: pos ? pos.y : 0 }); },
      onBuildSelect: (info) => setBuildSel(info),
    });
    engineRef.current = eng;
    const off = eng.sim.onEntry((e) => {
      const stamped = { ...e, clock: ofcClock(new Date()) };
      setFeed((f) => { const n = [...f, stamped]; return n.length > 90 ? n.slice(n.length - 90) : n; });
    });
    const tick = setInterval(() => {
      const s = {};
      eng.sim.agents.forEach((a) => { s[a.id] = a.alert ? "alert" : a.pose === "walk" ? "moving" : (a.task && a.task.act === "work") || a.pose === "sit" ? "working" : "idle"; });
      setStatuses(s);
      const tk = {}; eng.sim.agents.forEach((a) => { tk[a.id] = a.tokens || 0; }); setTokens(tk);
      if (eng.getDay) setDayLabel(eng.getDay().label);
      if (eng.isBuildMode && eng.isBuildMode()) setRemaining(eng.catalogRemaining());
      menuRef.current = eng;
      setMenu((m) => { if (!m) return m; const p = eng.agentScreen(m.agentId); return p ? { ...m, x: p.x, y: p.y } : m; });
    }, 240);
    // events/sec sampler → HUD sparkline
    const rateInt = setInterval(() => {
      setFeed((f) => {
        const delta = Math.max(0, f.length - lastLenRef.current);
        lastLenRef.current = f.length;
        setRate((r) => { const n = [...r.slice(1), delta]; return n; });
        return f;
      });
    }, 1100);
    // "who sounded" indicator
    const offSound = window.OFCSound ? window.OFCSound.onPlay((id, label) => {
      setToast({ id, label }); if (toastT.current) clearTimeout(toastT.current);
      toastT.current = setTimeout(() => setToast(null), 1700);
    }) : null;
    return () => { clearInterval(tick); clearInterval(rateInt); off && off(); offSound && offSound(); eng.destroy(); };
  }, []);

  useEffectOf(() => {
    const el = feedRef.current; if (el) el.scrollTop = el.scrollHeight;
  }, [feed, stageFilter, onlySelected]);

  // shared activity from the Command view (localStorage) — live across tabs
  useEffectOf(() => {
    const read = () => {
      try { const raw = localStorage.getItem("t9_activity"); const d = raw ? JSON.parse(raw) : null; setActivity(d && Array.isArray(d.items) ? d.items : []); }
      catch (e) { setActivity([]); }
    };
    read();
    const onStore = (e) => { if (!e || e.key === "t9_activity") read(); };
    window.addEventListener("storage", onStore);
    const iv = setInterval(read, 1500);
    return () => { window.removeEventListener("storage", onStore); clearInterval(iv); };
  }, []);

  // keep engine selection in sync
  useEffectOf(() => { if (engineRef.current) engineRef.current.setSelected(selected); }, [selected]);

  /* ---- derived metrics ---- */
  const metrics = useMemoOf(() => {
    let missions = 0, deploys = 0, threats = 0, held = 0;
    const perAgent = {};
    feed.forEach((e) => {
      if (e.kind === "msg") return;
      perAgent[e.agentId] = (perAgent[e.agentId] || 0) + 1;
      if (e.tag === "CREATED") missions++;
      else if (e.tag === "DEPLOYED") deploys++;
      else if (e.tag === "DEPLOY HELD") held++;
      else if (e.tag === "CLEARED") threats++;
    });
    const sv = Object.values(statuses);
    const busy = sv.filter((s) => s === "working" || s === "moving" || s === "alert").length;
    const util = sv.length ? Math.round((busy / sv.length) * 100) : 0;
    const success = deploys + held > 0 ? Math.round((deploys / (deploys + held)) * 100) : 100;
    return { missions, deploys, threats, util, success, perAgent };
  }, [feed, statuses]);

  const stageCounts = useMemoOf(() => {
    const c = {}; OFC_STAGES.forEach((s) => (c[s.key] = 0));
    feed.forEach((e) => { const k = OFC_STAGE_OF[e.tag]; if (k) c[k]++; });
    return c;
  }, [feed]);

  /* ---- filtered feed ---- */
  const shownFeed = useMemoOf(() => {
    return feed.filter((e) => {
      if (onlySelected && selected) { if (e.agentId !== selected && !(e.kind === "msg" && e.agentId === "diego")) return false; }
      if (stageFilter) { if (e.kind === "msg") return false; if (OFC_STAGE_OF[e.tag] !== stageFilter) return false; }
      return true;
    });
  }, [feed, stageFilter, onlySelected, selected]);

  const selAgent = roster.find((r) => r.id === selected) || null;
  const selStatus = selected ? (statuses[selected] || "idle") : null;

  function flyTo(agentId) {
    if (!agentId || !engineRef.current) return;
    setSelected(agentId);
    engineRef.current.focus(agentId);
    const room = OFC_ROOM[agentId]; if (room) engineRef.current.glowRoom(room, OFC_ACCENT[agentId]);
  }

  function send() {
    const t = draft.trim(); if (!t || !engineRef.current) return;
    engineRef.current.sim.say(t); setDraft("");
  }
  function assignMission() {
    const t = missionDraft.trim(); if (!t || !selected || !engineRef.current) return;
    engineRef.current.sim.assign(selected, t); setMissionDraft("");
    flyTo(selected);
  }
  function quick(cmd) { if (!engineRef.current) return; if (window.OFCSound) window.OFCSound.arm(); engineRef.current.sim.say(cmd); }
  function doAgentAction(act) {
    if (!engineRef.current || !menu) return;
    if (window.OFCSound) window.OFCSound.arm();
    engineRef.current.action(menu.agentId, act);
    setMenu(null);
  }
  function toggleSound() {
    if (!window.OFCSound) return; const next = !soundOn; window.OFCSound.setMuted(!next); setSoundOn(next); if (next) window.OFCSound.play("viiera");
  }
  /* ---- sound menu helpers ---- */
  function setAgentSound(id, cfg) { if (!window.OFCSound) return; window.OFCSound.setAgentSound(id, cfg); setSoundCfg(window.OFCSound.getMap()); }
  function onKindChange(id, value) {
    if (value === "url") setAgentSound(id, { kind: "url", url: (soundCfg[id] && soundCfg[id].url) || "" });
    else if (value === "upload") setAgentSound(id, soundCfg[id] && soundCfg[id].kind === "upload" ? soundCfg[id] : { kind: "upload" });
    else setAgentSound(id, { kind: "synth", sig: value });
  }
  function onUrl(id, url) { setAgentSound(id, { kind: "url", url }); }
  function onUpload(id, file) {
    if (!file) return;
    if (file.size > (window.OFCSound.UPLOAD_LIMIT || 320000)) {
      setUploadErr((e) => ({ ...e, [id]: "Too big (max " + Math.round((window.OFCSound.UPLOAD_LIMIT || 320000) / 1024) + "KB)" }));
      return;
    }
    setUploadErr((e) => ({ ...e, [id]: null }));
    const fr = new FileReader();
    fr.onload = () => setAgentSound(id, { kind: "upload", data: fr.result, name: file.name });
    fr.readAsDataURL(file);
  }
  function preview(id) { if (window.OFCSound) { window.OFCSound.arm(); window.OFCSound.play(id, true); } }
  function toggleBuild() {
    const next = !buildOn; setBuildOn(next); setMenu(null); setSelected(null);
    if (engineRef.current) {
      engineRef.current.setBuildMode(next);
      if (next) { setCatalog(engineRef.current.getCatalog()); setRemaining(engineRef.current.catalogRemaining()); }
      else setBuildSel(null);
    }
  }
  function addItem(kind) { if (engineRef.current) { engineRef.current.addItem(kind); setRemaining(engineRef.current.catalogRemaining()); } }
  function rotateSel() { if (engineRef.current) engineRef.current.rotateSelected(); }
  function delSel() { if (engineRef.current) { engineRef.current.deleteSelected(); setRemaining(engineRef.current.catalogRemaining()); } }
  function toggleImmersive() { setImmersive((v) => !v); setMenu(null); }
  function quickMoveBuild() { setBuildPos(null); setBuildCorner((c) => (c === "br" ? "bl" : "br")); }
  function onBuildBarDown(e) {
    if (e.target.closest("button")) return;            // let header buttons work
    const stage = wrapRef.current && wrapRef.current.querySelector(".office-stage"); if (!stage) return;
    const panel = e.currentTarget.closest(".ofc-build-bar"); if (!panel) return;
    const sr = stage.getBoundingClientRect(), pr = panel.getBoundingClientRect();
    const offX = e.clientX - pr.left, offY = e.clientY - pr.top;
    e.preventDefault();
    function mv(ev) {
      let x = ev.clientX - sr.left - offX, y = ev.clientY - sr.top - offY;
      x = Math.max(6, Math.min(x, sr.width - pr.width - 6));
      y = Math.max(6, Math.min(y, sr.height - pr.height - 6));
      setBuildPos({ x, y });
    }
    function up() { window.removeEventListener("mousemove", mv); window.removeEventListener("mouseup", up); }
    window.addEventListener("mousemove", mv); window.addEventListener("mouseup", up);
  }
  const buildStyle = buildPos
    ? { left: buildPos.x, top: buildPos.y, right: "auto", bottom: "auto" }
    : (buildCorner === "bl" ? { left: 12, right: "auto", bottom: 48, top: "auto" } : { right: 12, left: "auto", bottom: 48, top: "auto" });

  const statusMeta = { working: ["#4D9FFF", "working"], moving: ["#A855F7", "moving"], idle: ["#2FE0A1", "idle"], alert: ["#F87171", "alert"] };

  return (
    <div className={"office-root" + (immersive ? " immersive" : "")} ref={wrapRef}>
      <div className="office-stage">
        <canvas ref={canvasRef} className="office-canvas"></canvas>

        {/* top HUD */}
        <div className="ofc-hud">
          <div className="hud-id">
            <div className="ttl">Divonci HQ</div>
            <div className="sub">Live command floor</div>
          </div>
          <div className="hud-stats">
            <div className="hstat"><b>{metrics.missions}</b><span>missions</span></div>
            <div className="hstat"><b style={{ color: "#2FE0A1" }}>{metrics.deploys}</b><span>deploys</span></div>
            <div className="hstat"><b style={{ color: metrics.success >= 80 ? "#2FE0A1" : "#F5B544" }}>{metrics.success}%</b><span>deploy ok</span></div>
            <div className="hstat"><b style={{ color: "#F87171" }}>{metrics.threats}</b><span>threats cleared</span></div>
            <div className="hstat"><b style={{ color: "#CDB6FF" }}>{fmtTok(Object.values(tokens).reduce((a, b) => a + b, 0))}</b><span>tokens</span></div>
            <div className="hstat util"><b style={{ color: "#A855F7" }}>{metrics.util}%</b><span>utilization</span>
              <div className="hspark"><Sparkline data={rate.some((v) => v) ? rate : [0, 1, 0]} color="#A855F7" h={20} w={120} fill={true} /></div>
            </div>
          </div>
          <div className="hud-right">
            <a className="hud-btn cmd" href="../../terminal9/The Office - Command.html" title="Open Engineering Command"><span className="cmdglyph">›_</span><span className="cmdlbl">Command</span></a>
            <span className="day-pill"><span className="sun"></span>{dayLabel || "—"}</span>
            <button className={"hud-btn" + (soundOn ? " on" : "") + (soundMenu ? " act" : "")} title="Sound menu" onClick={() => { setSoundMenu(true); if (window.OFCSound) window.OFCSound.arm(); }}>
              <Icon name={soundOn ? "mic" : "power"} style={{ width: 14, height: 14 }} />
            </button>
            <button className={"hud-btn" + (buildOn ? " build" : "")} title="Build mode — drag furniture" onClick={toggleBuild}>
              <Icon name="chip" style={{ width: 14, height: 14 }} />
            </button>
            {buildOn && <button className="hud-btn" title="Reset layout" onClick={() => engineRef.current && engineRef.current.resetLayout()}>
              <Icon name="refresh" style={{ width: 14, height: 14 }} /></button>}
            <button className="hud-btn" title="Reset camera" onClick={() => { engineRef.current && engineRef.current.reset(); setSelected(null); }}>
              <Icon name="globe" style={{ width: 14, height: 14 }} />
            </button>
            <button className={"hud-btn" + (immersive ? " act" : "")} title={immersive ? "Exit full screen" : "Full screen"} onClick={toggleImmersive}>
              <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                {immersive ? <path d="M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5"></path> : <path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5"></path>}
              </svg>
            </button>
          </div>
        </div>

        {/* mission lifecycle lane */}
        <div className="ofc-lane">
          {OFC_STAGES.map((s, i) => (
            <React.Fragment key={s.key}>
              <button className={"lane-stage" + (stageFilter === s.key ? " on" : "")} style={{ "--lc": s.color }}
                onClick={() => setStageFilter(stageFilter === s.key ? null : s.key)} title={"Filter feed · " + s.label}>
                <span className="lc"></span>
                <span className="ll">{s.label}</span>
                <span className="ln">{stageCounts[s.key]}</span>
              </button>
              {i < OFC_STAGES.length - 1 && <span className="lane-arrow">›</span>}
            </React.Fragment>
          ))}
          {stageFilter && <button className="lane-clear" onClick={() => setStageFilter(null)}>clear</button>}
        </div>

        {buildOn && (
          <div className="ofc-build-bar" style={buildStyle}>
            <div className="bb-bar" onMouseDown={onBuildBarDown} title="Drag to move">
              <div className="bb-title"><span className="bb-grip"></span>BUILD</div>
              <div className="bb-actions">
                <button onClick={quickMoveBuild} title="Snap to other corner">
                  <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M8 7l-4 4 4 4M16 7l4 4-4 4M4 11h16"></path></svg>
                </button>
                <button disabled={!buildSel} onClick={rotateSel} title="Rotate selected (R)"><Icon name="refresh" style={{ width: 14, height: 14 }} /></button>
                <button className="del" disabled={!buildSel} onClick={delSel} title="Delete selected (Del)"><Icon name="close" style={{ width: 14, height: 14 }} /></button>
              </div>
            </div>
            <div className="bb-palette">
              {catalog.map((c) => {
                const n = remaining[c.key] == null ? 2 : remaining[c.key];
                return (
                  <button key={c.key} className="bb-item" disabled={n <= 0} onClick={() => addItem(c.key)} title={n > 0 ? ("Add " + c.label + " (" + n + " left)") : (c.label + " — none left")}>
                    <span className="bb-ico">{c.thumb ? <img src={c.thumb} alt="" /> : null}</span>
                    <span className="bb-lbl">{c.label}</span>
                    <i>{n}</i>
                  </button>
                );
              })}
            </div>
          </div>
        )}

        {/* agent node links — the only floor chrome kept in full screen */}
        {immersive && (
          <div className="ofc-nodes">
            {roster.map((r) => {
              const st = statuses[r.id] || "idle"; const m = statusMeta[st] || statusMeta.idle;
              return (
                <button key={r.id} className={"node" + (selected === r.id ? " on" : "")} style={{ "--ac": r.accent }} onClick={() => flyTo(r.id)} title={r.name}>
                  <span className="nd-av" style={{ background: r.accent }}>{r.name[0]}</span>
                  <span className="nd-dot" style={{ background: m[0] }}></span>
                  <span className="nd-name">{r.name}</span>
                </button>
              );
            })}
          </div>
        )}

        {/* who-just-sounded indicator */}
        {toast && (() => { const ag = roster.find((r) => r.id === toast.id); if (!ag) return null; return (
          <div className="ofc-toast" style={{ "--ac": ag.accent }}>
            <span className="t-av" style={{ background: ag.accent }}>{ag.name[0]}</span>
            <span className="t-name">{ag.name}</span>
            <span className="t-wave"><i></i><i></i><i></i></span>
            <span className="t-lbl">{toast.label}</span>
          </div>
        ); })()}

        <div className="office-legend">
          <span><i style={{ background: "#2FE0A1" }}></i>idle</span>
          <span><i style={{ background: "#4D9FFF" }}></i>working</span>
          <span><i style={{ background: "#A855F7" }}></i>moving</span>
          <span><i style={{ background: "#F87171" }}></i>alert</span>
        </div>

        {/* agent action menu (2nd click on a zoomed agent) */}
        {menu && (() => {
          const ag = roster.find((r) => r.id === menu.agentId); if (!ag) return null;
          const acts = OFC_ACTIONS.concat(OFC_HAS_CURTAIN[ag.id] ? [{ act: "curtain", label: "Close / open curtain" }] : []);
          const stageW = wrapRef.current && wrapRef.current.querySelector(".office-stage") ? wrapRef.current.querySelector(".office-stage").clientWidth : 900;
          const left = Math.max(8, Math.min(menu.x - 100, stageW - 220));
          const top = Math.max(8, menu.y - 14);
          return (
            <div className="ofc-menu" style={{ left, top, "--ac": ag.accent }}>
              <div className="m-head">
                <span className="m-av" style={{ background: ag.accent }}>{ag.name[0]}</span>
                <span className="m-name">{ag.name}</span>
                <span className="m-tok" title="Tokens used">{fmtTok(tokens[ag.id])}</span>
                <button className="m-sound" title="Play signature" onClick={() => { if (window.OFCSound) { window.OFCSound.arm(); window.OFCSound.play(ag.id); } }}><Icon name="mic" style={{ width: 12, height: 12 }} /></button>
                <button className="m-x" onClick={() => setMenu(null)} aria-label="Close"><Icon name="close" style={{ width: 12, height: 12 }} /></button>
              </div>
              <div className="m-acts">
                {acts.map((a) => <button key={a.act} className="m-act" onClick={() => doAgentAction(a.act)}>{a.label}</button>)}
              </div>
            </div>
          );
        })()}
      </div>

      <aside className="office-panel">
        <div className="op-roster">
          {roster.map((r) => {
            const st = statuses[r.id] || "idle"; const m = statusMeta[st] || statusMeta.idle;
            return (
              <button key={r.id} className={"op-chip" + (selected === r.id ? " on" : "") + (toast && toast.id === r.id ? " sounding" : "")} style={{ "--ac": r.accent }}
                onClick={() => flyTo(r.id)} title={r.name + " · " + m[1]}>
                <span className="av" style={{ background: r.accent }}>{r.name[0]}</span>
                <span className="dot" style={{ background: m[0] }}></span>
              </button>
            );
          })}
        </div>

        {/* agent inspector */}
        {selAgent && (
          <div className="op-inspect" style={{ "--ac": selAgent.accent }}>
            <div className="ins-head">
              <span className="ins-av" style={{ background: selAgent.accent }}>{selAgent.name[0]}</span>
              <div className="ins-id">
                <div className="ins-name">{selAgent.name}</div>
                <div className="ins-role">{OFC_ROLE[selAgent.id] || selAgent.room}</div>
              </div>
              <span className="ins-status" style={{ "--sc": (statusMeta[selStatus] || statusMeta.idle)[0] }}>
                <i></i>{(statusMeta[selStatus] || statusMeta.idle)[1]}
              </span>
              <button className="ins-x" onClick={() => setSelected(null)} aria-label="Close"><Icon name="close" style={{ width: 13, height: 13 }} /></button>
            </div>
            <div className="ins-stats">
              <div className="ins-st"><b style={{ color: "#CDB6FF" }}>{fmtTok(tokens[selAgent.id])}</b><span>tokens</span></div>
              <div className="ins-st"><b>{metrics.perAgent[selAgent.id] || 0}</b><span>events</span></div>
              <div className="ins-st"><b style={{ textTransform: "capitalize" }}>{selAgent.room}</b><span>station</span></div>
              <div className="ins-st">
                <button className={"ins-toggle" + (onlySelected ? " on" : "")} onClick={() => setOnlySelected((v) => !v)}>
                  {onlySelected ? "showing only" : "filter feed"}
                </button>
              </div>
            </div>
            <div className="ins-assign">
              <input value={missionDraft} onChange={(e) => setMissionDraft(e.target.value)}
                onKeyDown={(e) => { if (e.key === "Enter") assignMission(); }}
                placeholder={"Assign mission to " + selAgent.name + "…"} />
              <button onClick={assignMission} title="Assign"><Icon name="bolt" style={{ width: 13, height: 13 }} /></button>
            </div>
          </div>
        )}

        {activity.length > 0 && (
          <div className="op-activity">
            <div className="oa-head"><span className="lbl">Active work</span><span className="cnt">{activity.length}</span></div>
            <div className="oa-list">
              {activity.map((a, i) => (
                <div key={i} className={"oa-item" + (a.mine ? " mine" : "")} style={{ "--ac": (a.agents && a.agents[0] && OFC_ACCENT[a.agents[0]]) || "#FF6A1F" }}>
                  <div className="oa-top">
                    {a.mine && <span className="oa-you">YOU</span>}
                    {a.priority && <span className={"oa-prio " + a.priority}>{String(a.priority).toUpperCase()}</span>}
                    <span className="oa-label">{a.label}</span>
                  </div>
                  {a.objective ? <div className="oa-obj">{a.objective}</div> : null}
                  <div className="oa-foot">
                    <span className="oa-stage">{a.stage}</span>
                    <div className="oa-bar"><span style={{ width: (a.pct || 0) + "%" }}></span></div>
                    <span className="oa-pct">{a.pct || 0}%</span>
                  </div>
                  {typeof a.stepsTotal === "number" && a.stepsTotal > 0 ? (
                    <div className="oa-steps">{a.stepsDone}/{a.stepsTotal} steps{a.next ? <span className="oa-next"> · next: {a.next}</span> : null}</div>
                  ) : null}
                </div>
              ))}
            </div>
          </div>
        )}

        <div className="op-feedhead">
          <span className="lbl"><span className="rec"></span> HQ LIVE FEED</span>
          <span className="cnt">{shownFeed.length}{stageFilter || onlySelected ? " / " + feed.length : ""} events</span>
        </div>

        <div className="op-feed" ref={feedRef}>
          {shownFeed.map((e) => e.kind === "msg" ? (
            <div key={e.id} className={"op-msg" + (e.agentId === "diego" ? " me" : "")} style={{ "--ac": OFC_ACCENT[e.agentId] || "#9090A0" }}>
              <div className="who">{e.tag}<span className="tm">{e.clock}</span></div>
              <div className="bd">{e.text}</div>
            </div>
          ) : (
            <button key={e.id} className={"op-ev" + (selected === e.agentId ? " sel" : "")} style={{ "--tc": OFC_TAGC[e.tag] || OFC_ACCENT[e.agentId] || "#9090A0" }}
              onClick={() => flyTo(e.agentId)} title="Fly camera to agent">
              <div className="ev-top">
                <span className="ev-tag">{e.tag}</span>
                <span className="ev-tm">{e.clock}</span>
              </div>
              <div className="ev-tx">{e.text}</div>
            </button>
          ))}
        </div>

        <div className="op-quick">
          {["Deploy the EU bundle", "Verify #A7F2", "Convene the Council"].map((q) => (
            <button key={q} className="qchip" onClick={() => quick(q)}>{q}</button>
          ))}
        </div>

        <div className="op-chatbar">
          <input value={draft} onChange={(e) => setDraft(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") send(); }}
            placeholder={selected ? "Message " + (roster.find((r) => r.id === selected) || {}).name + "…" : "Command the floor…"} />
          <button className="op-send" onClick={send} aria-label="Send"><Icon name="arrow" style={{ width: 15, height: 15 }} /></button>
        </div>
      </aside>

      {soundMenu && (
        <div className="ofc-sm-back" onClick={() => setSoundMenu(false)}>
          <div className="ofc-sm" onClick={(e) => e.stopPropagation()}>
            <div className="sm-head">
              <div className="sm-ttl"><Icon name="mic" style={{ width: 15, height: 15 }} /> Sound</div>
              <button className="sm-master" onClick={toggleSound}>
                <span className="sw" data-on={soundOn}></span>{soundOn ? "On" : "Muted"}
              </button>
              <button className="sm-x" onClick={() => setSoundMenu(false)} aria-label="Close"><Icon name="close" style={{ width: 14, height: 14 }} /></button>
            </div>
            <div className="sm-note">Assign a voice per agent — pick a built-in, paste an audio URL, or upload a clip (≤{Math.round((window.OFCSound ? window.OFCSound.UPLOAD_LIMIT : 320000) / 1024)}KB).</div>
            <div className="sm-rows">
              {roster.map((r) => {
                const cfg = soundCfg[r.id] || { kind: "synth", sig: r.id };
                const sel = cfg.kind === "synth" ? (cfg.sig || r.id) : cfg.kind;
                return (
                  <div className="sm-row" key={r.id} style={{ "--ac": r.accent }}>
                    <span className="sm-av" style={{ background: r.accent }}>{r.name[0]}</span>
                    <span className="sm-name">{r.name}</span>
                    <select className="sm-sel" value={sel} onChange={(e) => onKindChange(r.id, e.target.value)}>
                      <optgroup label="Built-in voices">
                        {(window.OFCSound ? window.OFCSound.SYNTH_KEYS : []).map((k) => (
                          <option key={k} value={k}>{window.OFCSound.SIG_LABELS[k]}</option>
                        ))}
                      </optgroup>
                      <optgroup label="Custom">
                        <option value="url">From URL…</option>
                        <option value="upload">Upload file…</option>
                      </optgroup>
                    </select>
                    {cfg.kind === "url" && (
                      <input className="sm-url" placeholder="https://…/clip.mp3" defaultValue={cfg.url || ""}
                        onBlur={(e) => onUrl(r.id, e.target.value.trim())}
                        onKeyDown={(e) => { if (e.key === "Enter") onUrl(r.id, e.target.value.trim()); }} />
                    )}
                    {cfg.kind === "upload" && (
                      <label className="sm-up">
                        <input type="file" accept="audio/*" onChange={(e) => onUpload(r.id, e.target.files[0])} />
                        <span>{uploadErr[r.id] ? uploadErr[r.id] : (cfg.name ? cfg.name : "Choose file")}</span>
                      </label>
                    )}
                    <button className="sm-play" title="Preview" onClick={() => preview(r.id)}><Icon name="play" style={{ width: 13, height: 13 }} /></button>
                  </div>
                );
              })}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ---- styles ---- */
(function injectOfficeStyles() {
  if (document.getElementById("office-styles")) return;
  const css = `
  .canvas:has(.office-root){padding:0 !important;overflow:hidden !important}
  .office-root{display:flex;height:100%;min-height:560px;background:#07070b}
  .office-stage{position:relative;flex:1;min-width:0;overflow:hidden}
  .office-canvas{position:absolute;inset:0;width:100%;height:100%;display:block;image-rendering:pixelated}

  /* top HUD */
  .ofc-hud{position:absolute;top:0;left:0;right:0;z-index:4;display:flex;align-items:center;gap:18px;padding:12px 16px;
    background:linear-gradient(180deg,rgba(7,7,12,.82),rgba(7,7,12,0));pointer-events:none}
  .ofc-hud>*{pointer-events:auto}
  .ofc-hud .hud-id .ttl{font-family:var(--font-display);font-weight:700;font-size:17px;letter-spacing:-.01em;color:#fff;text-shadow:0 2px 8px rgba(0,0,0,.7);line-height:1}
  .ofc-hud .hud-id .sub{font-family:var(--font-mono);font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--violet-ink);margin-top:4px}
  .hud-stats{display:flex;gap:7px;align-items:stretch;margin-left:auto}
  .hstat{display:flex;flex-direction:column;justify-content:center;gap:1px;padding:5px 11px;border-radius:9px;background:rgba(10,10,16,.62);border:1px solid var(--hairline-2);backdrop-filter:blur(7px);min-width:54px}
  .hstat b{font-family:var(--font-mono);font-size:16px;font-weight:600;line-height:1;color:var(--ink)}
  .hstat span{font-family:var(--font-mono);font-size:8px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);margin-top:3px}
  .hstat.util{min-width:120px}
  .hspark{margin-top:3px;height:20px}
  .hud-right{display:flex;align-items:center;gap:8px}
  .day-pill{display:inline-flex;align-items:center;gap:7px;font-family:var(--font-mono);font-size:10px;color:var(--ink-2);background:rgba(10,10,16,.62);border:1px solid var(--hairline-2);border-radius:99px;padding:6px 11px;backdrop-filter:blur(7px);white-space:nowrap}
  .day-pill .sun{width:8px;height:8px;border-radius:50%;background:radial-gradient(circle at 35% 35%,#ffd98a,#f5a64a);box-shadow:0 0 8px #f5a64a88}
  .hud-btn{width:32px;height:32px;border-radius:9px;border:1px solid var(--hairline-2);background:rgba(10,10,16,.62);color:var(--ink-2);cursor:pointer;display:grid;place-items:center;backdrop-filter:blur(7px)}
  .hud-btn:hover{color:#fff;border-color:color-mix(in srgb,var(--violet) 55%,transparent)}
  .hud-btn.act{color:#fff;border-color:color-mix(in srgb,var(--violet) 60%,transparent);background:color-mix(in srgb,var(--violet) 22%,transparent)}

  /* full-screen / immersive mode */
  .office-root.immersive{position:fixed;inset:0;z-index:200;min-height:0}
  .office-root.immersive .office-panel{display:none}
  .office-root.immersive .ofc-hud{background:none}
  .office-root.immersive .ofc-hud .hud-id,
  .office-root.immersive .ofc-hud .hud-stats,
  .office-root.immersive .day-pill{display:none}
  .office-root.immersive .ofc-lane,
  .office-root.immersive .office-legend{display:none}
  .ofc-hud .hud-right{margin-left:auto}

  /* agent node links (kept in full screen) */
  .ofc-nodes{position:absolute;top:16px;left:16px;z-index:7;display:flex;flex-direction:column;gap:13px;padding:8px 6px}
  .ofc-nodes::before{content:"";position:absolute;left:23px;top:16px;bottom:16px;width:2px;background:linear-gradient(180deg,color-mix(in srgb,var(--violet) 50%,transparent),color-mix(in srgb,var(--violet) 12%,transparent));border-radius:2px}
  .ofc-nodes .node{position:relative;display:flex;align-items:center;background:none;border:none;cursor:pointer;padding:0;height:30px}
  .ofc-nodes .nd-av{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;font-family:var(--font-display);font-weight:700;font-size:13px;color:#0b0b10;border:2px solid rgba(8,8,12,.85);box-shadow:0 0 10px color-mix(in srgb,var(--ac) 50%,transparent);position:relative;z-index:1;transition:transform .12s}
  .ofc-nodes .node:hover .nd-av{transform:scale(1.1)}
  .ofc-nodes .node.on .nd-av{outline:2px solid var(--ac);outline-offset:2px}
  .ofc-nodes .nd-dot{position:absolute;left:24px;top:0;width:9px;height:9px;border-radius:50%;border:2px solid rgba(8,8,12,.92);z-index:2}
  .ofc-nodes .nd-name{margin-left:11px;font-family:var(--font-mono);font-size:10.5px;color:#fff;background:rgba(8,8,12,.78);padding:4px 9px;border-radius:7px;white-space:nowrap;opacity:0;transform:translateX(-4px);transition:all .14s;text-shadow:0 1px 2px rgba(0,0,0,.6)}
  .ofc-nodes .node:hover .nd-name,.ofc-nodes .node.on .nd-name{opacity:1;transform:none}
  .hud-btn.on{color:#2FE0A1;border-color:color-mix(in srgb,#2FE0A1 50%,transparent)}
  .hud-btn.build{color:#0b0b10;background:#2FE0A1;border-color:#2FE0A1}
  .ofc-build-bar{position:absolute;bottom:48px;right:12px;z-index:6;width:282px;display:flex;flex-direction:column;background:rgba(8,16,13,.94);border:1px solid color-mix(in srgb,#2FE0A1 40%,transparent);border-radius:13px;backdrop-filter:blur(9px);box-shadow:0 12px 30px rgba(0,0,0,.5);overflow:hidden}
  .ofc-build-bar .bb-bar{display:flex;align-items:center;gap:10px;padding:10px 11px;border-bottom:1px solid var(--hairline);cursor:grab;user-select:none}
  .ofc-build-bar .bb-bar:active{cursor:grabbing}
  .ofc-build-bar .bb-title{display:flex;align-items:center;gap:7px;font-family:var(--font-mono);font-size:10px;letter-spacing:.12em;color:#2FE0A1;flex:1}
  .ofc-build-bar .bb-grip{width:8px;height:11px;flex:none;background-image:radial-gradient(currentColor 1px,transparent 1px);background-size:4px 4px;color:color-mix(in srgb,#2FE0A1 70%,transparent);opacity:.7}
  .bb-palette{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;padding:10px;max-height:268px;overflow-y:auto;scrollbar-width:thin}
  .bb-item{position:relative;display:flex;flex-direction:column;align-items:center;gap:4px;font-family:var(--font-ui);font-size:10px;line-height:1.1;text-align:center;color:var(--ink-2);background:var(--panel-2);border:1px solid var(--hairline-2);border-radius:8px;padding:7px 5px 6px;cursor:pointer;transition:all .12s;min-height:62px;justify-content:flex-start}
  .bb-ico{display:grid;place-items:center;width:100%;height:32px}
  .bb-ico img{max-width:38px;max-height:32px;width:auto;height:auto;image-rendering:pixelated;filter:drop-shadow(0 2px 3px rgba(0,0,0,.5))}
  .bb-lbl{display:block;width:100%;overflow:hidden;text-overflow:ellipsis}
  .bb-item:hover:not(:disabled){color:#fff;border-color:color-mix(in srgb,#2FE0A1 50%,transparent);background:var(--panel-3)}
  .bb-item:disabled{opacity:.34;cursor:not-allowed}
  .bb-item i{position:absolute;top:4px;right:4px;font-family:var(--font-mono);font-size:8.5px;font-style:normal;color:#2FE0A1;background:color-mix(in srgb,#2FE0A1 18%,var(--panel));border-radius:5px;padding:1px 4px}
  .bb-actions{display:flex;gap:6px;flex:none}
  .bb-actions button{width:30px;height:30px;border-radius:8px;border:1px solid var(--hairline-2);background:var(--panel-2);color:var(--ink-2);cursor:pointer;display:grid;place-items:center}
  .bb-actions button:hover:not(:disabled){color:#fff;border-color:color-mix(in srgb,#2FE0A1 50%,transparent)}
  .bb-actions button.del:hover:not(:disabled){color:#F87171;border-color:color-mix(in srgb,#F87171 55%,transparent)}
  .bb-actions button:disabled{opacity:.3;cursor:not-allowed}

  /* who-just-sounded toast */
  .office-root{position:relative}
  .ofc-toast{position:absolute;bottom:54px;left:50%;transform:translateX(-50%);z-index:6;display:flex;align-items:center;gap:9px;background:rgba(10,10,16,.92);border:1px solid color-mix(in srgb,var(--ac) 50%,transparent);border-radius:99px;padding:6px 13px 6px 6px;backdrop-filter:blur(8px);box-shadow:0 6px 22px rgba(0,0,0,.45);animation:ofcToastIn .2s var(--ease-out,ease)}
  @keyframes ofcToastIn{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}
  .ofc-toast .t-av{width:24px;height:24px;border-radius:7px;display:grid;place-items:center;font-family:var(--font-display);font-weight:700;font-size:12px;color:#0b0b10}
  .ofc-toast .t-name{font-family:var(--font-display);font-weight:600;font-size:13px;color:#fff}
  .ofc-toast .t-wave{display:inline-flex;align-items:flex-end;gap:2px;height:13px}
  .ofc-toast .t-wave i{width:2px;background:var(--ac);border-radius:1px;animation:ofcWave .6s ease-in-out infinite}
  .ofc-toast .t-wave i:nth-child(1){height:5px;animation-delay:0s}
  .ofc-toast .t-wave i:nth-child(2){height:11px;animation-delay:.15s}
  .ofc-toast .t-wave i:nth-child(3){height:7px;animation-delay:.3s}
  @keyframes ofcWave{0%,100%{transform:scaleY(.5)}50%{transform:scaleY(1)}}
  .ofc-toast .t-lbl{font-family:var(--font-mono);font-size:10px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}
  .op-chip.sounding{border-color:var(--ac);box-shadow:0 0 0 2px color-mix(in srgb,var(--ac) 55%,transparent);animation:ofcChipPulse .5s ease}
  @keyframes ofcChipPulse{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}

  /* sound menu */
  .ofc-sm-back{position:absolute;inset:0;z-index:20;display:grid;place-items:center;background:rgba(5,5,9,.6);backdrop-filter:blur(3px);animation:ofcMenuIn .15s ease}
  .ofc-sm{width:min(540px,calc(100% - 40px));max-height:calc(100% - 48px);overflow:auto;background:var(--panel);border:1px solid var(--hairline-3);border-radius:15px;box-shadow:0 24px 60px rgba(0,0,0,.6)}
  .sm-head{display:flex;align-items:center;gap:12px;padding:15px 17px;border-bottom:1px solid var(--hairline);position:sticky;top:0;background:var(--panel);z-index:1}
  .sm-ttl{display:flex;align-items:center;gap:8px;font-family:var(--font-display);font-weight:600;font-size:16px;flex:1;color:var(--violet-ink)}
  .sm-master{display:inline-flex;align-items:center;gap:7px;font-family:var(--font-mono);font-size:11px;color:var(--ink-2);background:var(--panel-2);border:1px solid var(--hairline-2);border-radius:99px;padding:5px 11px 5px 6px;cursor:pointer}
  .sm-master .sw{width:22px;height:13px;border-radius:99px;background:var(--graphite,#33323d);position:relative;transition:background .15s}
  .sm-master .sw::after{content:"";position:absolute;top:2px;left:2px;width:9px;height:9px;border-radius:50%;background:#fff;transition:left .15s}
  .sm-master .sw[data-on="true"]{background:#2FE0A1}
  .sm-master .sw[data-on="true"]::after{left:11px}
  .sm-x{width:28px;height:28px;border-radius:8px;border:1px solid var(--hairline-2);background:var(--panel-2);color:var(--ink-3);cursor:pointer;display:grid;place-items:center}
  .sm-x:hover{color:#fff}
  .sm-note{padding:11px 17px;font-size:12px;color:var(--ink-3);line-height:1.5;border-bottom:1px solid var(--hairline)}
  .sm-rows{padding:8px 10px}
  .sm-row{display:flex;align-items:center;gap:9px;padding:8px;border-radius:10px}
  .sm-row:hover{background:var(--panel-2)}
  .sm-av{width:28px;height:28px;border-radius:8px;display:grid;place-items:center;font-family:var(--font-display);font-weight:700;font-size:13px;color:#0b0b10;flex:none}
  .sm-name{font-family:var(--font-display);font-weight:600;font-size:13px;width:62px;flex:none}
  .sm-sel{flex:none;width:130px;background:var(--panel-2);border:1px solid var(--hairline-2);border-radius:8px;color:var(--ink);font:inherit;font-size:12px;padding:7px 8px;cursor:pointer}
  .sm-sel:focus{outline:none;border-color:color-mix(in srgb,var(--ac) 60%,transparent)}
  .sm-url{flex:1;min-width:0;background:var(--panel-2);border:1px solid var(--hairline-2);border-radius:8px;color:var(--ink);font:inherit;font-size:12px;padding:7px 9px}
  .sm-url:focus{outline:none;border-color:color-mix(in srgb,var(--ac) 60%,transparent)}
  .sm-up{flex:1;min-width:0;position:relative;display:flex;align-items:center;background:var(--panel-2);border:1px dashed var(--hairline-3);border-radius:8px;padding:7px 9px;cursor:pointer;overflow:hidden}
  .sm-up input{position:absolute;inset:0;opacity:0;cursor:pointer}
  .sm-up span{font-family:var(--font-mono);font-size:11px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .sm-play{width:32px;height:32px;flex:none;border-radius:8px;border:1px solid color-mix(in srgb,var(--ac) 45%,transparent);background:color-mix(in srgb,var(--ac) 16%,transparent);color:#fff;cursor:pointer;display:grid;place-items:center}
  .sm-play:hover{background:color-mix(in srgb,var(--ac) 28%,transparent)}

  /* agent action menu */
  .ofc-menu{position:absolute;z-index:6;width:212px;background:rgba(12,12,18,.95);border:1px solid color-mix(in srgb,var(--ac) 45%,var(--hairline-2));border-radius:11px;box-shadow:0 10px 30px rgba(0,0,0,.5);backdrop-filter:blur(10px);overflow:hidden;animation:ofcMenuIn .14s var(--ease-out,ease)}
  @keyframes ofcMenuIn{from{opacity:0;transform:translateY(4px) scale(.97)}to{opacity:1;transform:none}}
  .ofc-menu .m-head{display:flex;align-items:center;gap:8px;padding:9px 10px;border-bottom:1px solid var(--hairline);background:linear-gradient(180deg,color-mix(in srgb,var(--ac) 14%,transparent),transparent)}
  .ofc-menu .m-av{width:22px;height:22px;border-radius:6px;display:grid;place-items:center;font-family:var(--font-display);font-weight:700;font-size:11px;color:#0b0b10;flex:none}
  .ofc-menu .m-name{font-family:var(--font-display);font-weight:600;font-size:13px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .ofc-menu .m-tok{flex:none;font-family:var(--font-mono);font-size:10px;color:#CDB6FF;background:color-mix(in srgb,#A855F7 16%,transparent);border:1px solid color-mix(in srgb,#A855F7 32%,transparent);border-radius:6px;padding:2px 6px;flex:none}
  .ofc-menu .m-sound,.ofc-menu .m-x{width:22px;height:22px;border-radius:6px;border:1px solid var(--hairline-2);background:var(--panel-2);color:var(--ink-3);cursor:pointer;display:grid;place-items:center;flex:none}
  .ofc-menu .m-sound:hover{color:var(--ac)}
  .ofc-menu .m-x:hover{color:#fff}
  .ofc-menu .m-acts{display:flex;flex-direction:column;padding:5px}
  .ofc-menu .m-act{text-align:left;font-family:var(--font-ui);font-size:12.5px;color:var(--ink-2);background:none;border:none;border-radius:7px;padding:8px 9px;cursor:pointer;transition:all .12s}
  .ofc-menu .m-act:hover{background:color-mix(in srgb,var(--ac) 16%,transparent);color:#fff}

  /* mission lifecycle lane */
  .ofc-lane{position:absolute;bottom:12px;left:16px;z-index:4;display:flex;align-items:center;gap:3px;background:rgba(8,8,12,.74);border:1px solid var(--hairline-2);border-radius:12px;padding:6px 8px;backdrop-filter:blur(8px);flex-wrap:wrap;max-width:calc(100% - 32px)}
  .lane-stage{display:inline-flex;align-items:center;gap:6px;border:1px solid transparent;background:transparent;border-radius:8px;padding:5px 9px;cursor:pointer;transition:all .15s}
  .lane-stage:hover{background:rgba(255,255,255,.04)}
  .lane-stage.on{border-color:color-mix(in srgb,var(--lc) 55%,transparent);background:color-mix(in srgb,var(--lc) 12%,transparent)}
  .lane-stage .lc{width:7px;height:7px;border-radius:50%;background:var(--lc);box-shadow:0 0 7px var(--lc)}
  .lane-stage .ll{font-family:var(--font-mono);font-size:10px;letter-spacing:.04em;color:var(--ink-2);text-transform:uppercase}
  .lane-stage .ln{font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink);min-width:14px;text-align:center}
  .lane-arrow{color:var(--ink-4);font-size:13px;padding:0 1px}
  .lane-clear{margin-left:4px;font-family:var(--font-mono);font-size:9px;text-transform:uppercase;letter-spacing:.08em;color:var(--violet-ink);background:none;border:none;cursor:pointer;padding:4px 6px}
  .lane-clear:hover{color:#fff}

  .office-legend{position:absolute;bottom:12px;right:16px;z-index:4;display:flex;gap:13px;background:rgba(8,8,12,.7);border:1px solid var(--hairline-2);border-radius:99px;padding:6px 13px;backdrop-filter:blur(6px)}
  .office-legend span{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-mono);font-size:10px;color:var(--ink-2)}
  .office-legend i{width:8px;height:8px;border-radius:50%;box-shadow:0 0 6px currentColor}

  /* panel */
  .office-panel{width:384px;flex:none;display:flex;flex-direction:column;background:var(--panel);border-left:1px solid var(--hairline-2)}
  .op-roster{display:flex;gap:8px;padding:13px 14px;border-bottom:1px solid var(--hairline);flex-wrap:wrap}
  .op-chip{position:relative;width:38px;height:38px;border-radius:10px;border:1px solid var(--hairline-2);background:var(--panel-2);cursor:pointer;display:grid;place-items:center;transition:all .15s;padding:0}
  .op-chip:hover{background:var(--panel-3)}
  .op-chip.on{border-color:color-mix(in srgb,var(--ac) 60%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--ac) 45%,transparent)}
  .op-chip .av{width:24px;height:24px;border-radius:7px;display:grid;place-items:center;font-family:var(--font-display);font-weight:700;font-size:12px;color:#0b0b10}
  .op-chip .dot{position:absolute;right:3px;bottom:3px;width:9px;height:9px;border-radius:50%;border:2px solid var(--panel-2)}

  /* inspector */
  .op-inspect{border-bottom:1px solid var(--hairline);padding:13px 14px;background:linear-gradient(180deg,color-mix(in srgb,var(--ac) 8%,var(--panel-2)),var(--panel))}
  .ins-head{display:flex;align-items:center;gap:10px}
  .ins-av{width:34px;height:34px;border-radius:9px;display:grid;place-items:center;font-family:var(--font-display);font-weight:700;font-size:15px;color:#0b0b10;flex:none;box-shadow:0 0 12px color-mix(in srgb,var(--ac) 45%,transparent)}
  .ins-id{min-width:0;flex:1;overflow:hidden}
  .ins-name{font-family:var(--font-display);font-weight:600;font-size:14px;line-height:1.05;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .ins-role{font-family:var(--font-mono);font-size:9px;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3);margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .ins-status{flex:none;display:inline-flex;align-items:center;gap:5px;font-family:var(--font-mono);font-size:9px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-2)}
  .ins-status i{width:7px;height:7px;border-radius:50%;background:var(--sc);box-shadow:0 0 7px var(--sc)}
  .ins-x{width:24px;height:24px;border-radius:7px;border:1px solid var(--hairline-2);background:var(--panel-2);color:var(--ink-3);cursor:pointer;display:grid;place-items:center;flex:none}
  .ins-x:hover{color:#fff}
  .ins-stats{display:flex;gap:8px;margin-top:11px}
  .ins-st{flex:1;display:flex;flex-direction:column;gap:2px;background:var(--panel-2);border:1px solid var(--hairline);border-radius:8px;padding:7px 9px;align-items:flex-start}
  .ins-st b{font-family:var(--font-mono);font-size:14px;font-weight:600;line-height:1}
  .ins-st span{font-family:var(--font-mono);font-size:8px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
  .ins-toggle{font-family:var(--font-mono);font-size:9px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-2);background:none;border:none;cursor:pointer;padding:0;text-align:left}
  .ins-toggle.on{color:var(--violet-ink)}
  .ins-assign{display:flex;gap:7px;margin-top:10px}
  .ins-assign input{flex:1;min-width:0;background:var(--panel-2);border:1px solid var(--hairline-2);border-radius:8px;padding:8px 10px;color:var(--ink);font:inherit;font-size:12px}
  .ins-assign input:focus{outline:none;border-color:color-mix(in srgb,var(--ac) 60%,transparent)}
  .ins-assign button{width:34px;flex:none;border-radius:8px;border:none;background:var(--ac);color:#0b0b10;cursor:pointer;display:grid;place-items:center}
  .ins-assign button:hover{filter:brightness(1.12)}

  .hud-btn.cmd{width:auto;padding:0 11px;gap:7px;display:inline-flex;align-items:center;color:#FF9A4D;border-color:rgba(255,106,31,.34);background:rgba(255,106,31,.12)}
  .hud-btn.cmd:hover{background:rgba(255,106,31,.2);color:#FFB877}
  .hud-btn.cmd .cmdglyph{font-family:var(--font-mono);font-size:12px;font-weight:600;line-height:1}
  .hud-btn.cmd .cmdlbl{font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase}

  .op-activity{border-bottom:1px solid var(--hairline);padding:11px 14px 12px;background:color-mix(in srgb,#FF6A1F 4%,transparent)}
  .oa-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:9px}
  .oa-head .lbl{font-family:var(--font-mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-2)}
  .oa-head .cnt{font-family:var(--font-mono);font-size:9px;color:#FF9A4D;border:1px solid rgba(255,106,31,.34);border-radius:5px;padding:1px 6px}
  .oa-list{display:flex;flex-direction:column;gap:8px}
  .oa-item{border:1px solid var(--hairline-2);border-left:2px solid var(--ac);border-radius:0 8px 8px 0;padding:7px 10px;background:var(--panel-2)}
  .oa-item.mine{border-left-color:#FF6A1F;background:color-mix(in srgb,#FF6A1F 8%,var(--panel-2))}
  .oa-top{display:flex;align-items:center;gap:7px;margin-bottom:6px}
  .oa-you{font-family:var(--font-mono);font-size:8px;letter-spacing:.1em;color:#0b0b10;background:#FF6A1F;border-radius:4px;padding:1px 5px;font-weight:600}
  .oa-prio{font-family:var(--font-mono);font-size:7.5px;font-weight:600;letter-spacing:.08em;border-radius:4px;padding:1px 5px}
  .oa-prio.low{color:var(--ink-3);border:1px solid var(--hairline-2)}
  .oa-prio.med{color:#F5B544;border:1px solid rgba(245,181,68,.34)}
  .oa-prio.high{color:#FF6B6B;border:1px solid rgba(255,77,94,.4)}
  .oa-label{flex:1;font-size:12px;color:var(--ink);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .oa-obj{font-size:11px;color:var(--ink-2);line-height:1.45;margin:-1px 0 7px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .oa-foot{display:flex;align-items:center;gap:8px}
  .oa-stage{font-family:var(--font-mono);font-size:8.5px;letter-spacing:.08em;color:var(--ac);flex:none}
  .oa-bar{flex:1;height:4px;border-radius:3px;background:var(--panel-3);overflow:hidden}
  .oa-bar span{display:block;height:100%;background:linear-gradient(90deg,#FF6A1F,#34E27E);box-shadow:0 0 8px rgba(52,226,126,.4);transition:width .5s ease}
  .oa-steps{font-family:var(--font-mono);font-size:9px;color:var(--ink-3);margin-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .oa-next{color:var(--ink-4)}
  .oa-pct{font-family:var(--font-mono);font-size:8.5px;color:var(--ink-3);flex:none;min-width:26px;text-align:right}

  .op-feedhead{display:flex;align-items:center;justify-content:space-between;padding:11px 15px 9px;border-bottom:1px solid var(--hairline)}
  .op-feedhead .lbl{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-2);display:inline-flex;align-items:center;gap:8px}
  .op-feedhead .rec{width:7px;height:7px;border-radius:50%;background:#2FE0A1;box-shadow:0 0 8px #2FE0A1;animation:ofcrec 1.6s ease-in-out infinite}
  @keyframes ofcrec{0%,100%{opacity:.4}50%{opacity:1}}
  .op-feedhead .cnt{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-4)}

  .op-feed{flex:1;overflow-y:auto;padding:12px 14px;display:flex;flex-direction:column;gap:9px;scrollbar-width:thin}
  .op-ev{display:block;width:100%;text-align:left;border:none;border-left:2px solid color-mix(in srgb,var(--tc,#888) 50%,transparent);background:none;padding:3px 8px 3px 11px;cursor:pointer;border-radius:0 6px 6px 0;transition:background .12s}
  .op-ev:hover{background:color-mix(in srgb,var(--tc) 10%,transparent)}
  .op-ev.sel{background:color-mix(in srgb,var(--tc) 13%,transparent);border-left-color:var(--tc)}
  .op-ev .ev-top{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:3px}
  .op-ev .ev-tag{font-family:var(--font-mono);font-size:8.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--tc);background:color-mix(in srgb,var(--tc) 14%,transparent);border:1px solid color-mix(in srgb,var(--tc) 32%,transparent);padding:2px 7px;border-radius:5px}
  .op-ev .ev-tm{font-family:var(--font-mono);font-size:9px;color:var(--ink-4)}
  .op-ev .ev-tx{font-size:12px;color:var(--ink-2);line-height:1.45}

  .op-msg{--ac:#9090A0;align-self:flex-start;max-width:88%;background:var(--panel-2);border:1px solid var(--hairline-2);border-left:2px solid var(--ac);border-radius:9px;padding:7px 10px}
  .op-msg.me{align-self:flex-end;background:color-mix(in srgb,var(--violet) 12%,var(--panel-2));border-left:none;border-right:2px solid var(--violet)}
  .op-msg .who{font-family:var(--font-mono);font-size:8.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--ac);display:flex;justify-content:space-between;gap:10px;margin-bottom:3px}
  .op-msg.me .who{color:var(--violet-ink)}
  .op-msg .who .tm{color:var(--ink-4)}
  .op-msg .bd{font-size:12.5px;color:var(--ink);line-height:1.45}

  .op-quick{display:flex;gap:6px;padding:9px 14px 0;flex-wrap:wrap}
  .qchip{font-family:var(--font-mono);font-size:9.5px;letter-spacing:.02em;color:var(--ink-2);background:var(--panel-2);border:1px solid var(--hairline-2);border-radius:99px;padding:5px 10px;cursor:pointer;transition:all .14s}
  .qchip:hover{color:#fff;border-color:color-mix(in srgb,var(--violet) 50%,transparent);background:var(--panel-3)}

  .op-chatbar{display:flex;gap:8px;padding:11px 14px 13px;background:var(--panel)}
  .op-chatbar input{flex:1;min-width:0;background:var(--panel-2);border:1px solid var(--hairline-2);border-radius:9px;padding:10px 12px;color:var(--ink);font:inherit;font-size:13px}
  .op-chatbar input:focus{outline:none;border-color:color-mix(in srgb,var(--violet) 55%,transparent)}
  .op-send{width:40px;flex:none;border-radius:9px;border:none;background:var(--violet);color:#fff;cursor:pointer;display:grid;place-items:center}
  .op-send:hover{filter:brightness(1.1)}
  @media(max-width:1180px){.office-panel{width:340px}.hud-stats .hstat.util{display:none}}
  @media(max-width:980px){.hud-stats{display:none}}

  /* ============================ MOBILE — stacked ============================
     Office (pixel HQ) on top, chat panel below. Triggers only on phones; the
     desktop floor embeds the office wide, so its row layout is untouched. */
  @media(max-width:640px){
    .office-root{flex-direction:column;min-height:0;height:100%}
    .office-stage{flex:none;height:44vh;min-height:220px;border-bottom:1px solid var(--hairline-2)}
    .office-panel{width:100%;flex:1;min-height:0;border-left:none;
      box-shadow:0 -10px 26px rgba(0,0,0,.4)}

    /* HUD — trim to identity + controls (stats already hidden <980) */
    .ofc-hud{gap:10px;padding:9px 11px}
    .hud-id .ttl{font-size:13px}
    .hud-id .sub{font-size:9px}
    .hud-right{gap:6px}
    .hud-btn{width:30px;height:30px}
    .day-pill{padding:5px 9px;font-size:9px}

    /* mission lane — one scrollable row, no wrap */
    .ofc-lane{left:10px;right:10px;bottom:10px;max-width:none;flex-wrap:nowrap;
      overflow-x:auto;scrollbar-width:none}
    .ofc-lane::-webkit-scrollbar{display:none}
    .office-legend{display:none}

    /* roster — horizontal rail */
    .op-roster{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;padding:11px 12px}
    .op-roster::-webkit-scrollbar{display:none}
    .op-chip{flex:none}

    /* quick chips — scroll, don't wrap into a tall block */
    .op-quick{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
    .op-quick::-webkit-scrollbar{display:none}
    .qchip{flex:none}

    /* chat input — pin to the bottom, kill iOS focus-zoom */
    .op-chatbar{padding:10px 12px calc(12px + env(safe-area-inset-bottom,0px))}
    .op-chatbar input{font-size:16px}
    .ins-assign input{font-size:16px}
  }
  `;
  const el = document.createElement("style"); el.id = "office-styles"; el.textContent = css; document.head.appendChild(el);
})();

Object.assign(window, { OfficeScreen });
