Files
skills/orchestrator/templates/index.html.j2
T
Kevin Veen-BirkenbachandClaude Opus 5.5 d89fb616b8 feat(orchestrator): S2 agent and node popups with leader line, node search
Requirement 001 phase 6, S2:

- Agent popup: a click on an agent opens one fading <dialog> with face,
  name, earlier names, offices, tasks, claims, subagents, history and
  the composer; Escape or a click outside closes it. The agent drawer
  and the Details side panel are gone.
- Node popup: a click on a node in a graph view enlarges it and marks it
  red, and an SVG leader line ties it to the translucent popup; a click
  elsewhere restores the node. popup.js places the popup right, left,
  below or above the node, caps its height to the room there and
  returns the line.
- Search: in the 3D views a search field with suggestions replaces the
  list of every node, one chip per distinct label.
- Fit: body.fit now applies at every width; without the side panel the
  orbit view otherwise grew a page scrollbar at 390 px.
- Two page modules had silently shadowed each other's functions of the
  same name while this was built; test_no_two_page_modules_declare_the_same_function
  now guards that. Artifact ids carry NUL, which CSS.escape turns into
  U+FFFD, so the node lookup compares dataset values.

- Composer: a message goes to the agent whose popup it was written in.
  deliver() read the global ui.agent after awaiting the upload, so
  closing the popup or opening another agent during an upload sent the
  signed message to null or to the other agent (found by the security
  skeptic, present before, easier now that a backdrop click closes).

Limits: the 3D leader line is placed when the popup opens and does not
follow the camera while the layout settles; the search keeps the first
node per label, so a second repository's main branch is found in the
graph, not through the search.

Evidence: make test 667 OK, ruff and markdownlint clean
(/tmp/s2-make-test-1.log); e2e 19 OK in Chromium and Firefox at 1920,
1366 and 390 px, none skipped, rerun after the composer fix
(/tmp/s2-e2e-4.log); screenshots in /tmp/orchestrator-phase4-shots/;
MEDUSA 22 files, 6 findings (a "PLA" pattern in "templates", the UI
names openAgent and drawAgent) accepted after an independent skeptic
that also found no XSS or selector injection in the popup code.

🎯 Fix: 93 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 89
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 21:18:55 +00:00

566 lines
41 KiB
Django/Jinja

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>{% if state.badges.inbox %}({{ state.badges.inbox }}) {% endif %}Agent Orchestrator</title>
<style nonce="{{ nonce }}">
:root {
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px; --sp-7: 48px;
--fs-2xs: 11px; --fs-xs: 11.5px; --fs-sm: 12.5px; --fs-md: 14px; --fs-lg: 16px; --fs-xl: 18px; --fs-2xl: 22px; --fs-3xl: 34px;
--lh: 1.55; --lh-tight: 1.25;
--radius-sm: 8px; --radius: 14px; --radius-lg: 20px;
--veil: 100%; --card: 100%;
--blur: saturate(150%) blur(22px);
--ease: cubic-bezier(.2, .7, .2, 1);
--head: 104px;
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--glass: color-mix(in srgb, var(--bg) var(--veil), transparent);
--glass-panel: color-mix(in srgb, var(--panel) var(--veil), transparent);
--glass-card: color-mix(in srgb, var(--panel) var(--card), transparent);
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: #05070d; }
body { min-height: 100vh; margin: 0; background: transparent; color: var(--text); font: var(--fs-md)/var(--lh) var(--sans); -webkit-font-smoothing: antialiased; transition: color .8s var(--ease); }
.sky { position: fixed; inset: 0; z-index: -1; display: block; width: 100vw; height: 100vh; pointer-events: none; }
button, input, select { font: inherit; color: inherit; }
code, pre { font-family: var(--mono); font-size: var(--fs-sm); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 22%, transparent); }
.top, .navbar, main, .popup-box, .sheet-box, .palette-box, .toast, .sky-panel, .menu-box { -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur); transition: background-color .8s var(--ease), border-color .8s var(--ease); }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .22s; animation-timing-function: var(--ease); }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; scroll-behavior: auto !important; }
}
.head { position: sticky; top: 0; z-index: 6; }
.top { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) var(--sp-5); background: var(--glass-panel); border-bottom: 1px solid var(--line); }
.brand { display: flex; flex: 1; align-items: center; gap: var(--sp-3); min-width: 0; }
.brand-text { display: grid; line-height: var(--lh-tight); }
.sky-note { color: var(--muted); font-size: var(--fs-xs); white-space: nowrap; }
.logo { width: 24px; height: 24px; border-radius: var(--radius-sm); background: linear-gradient(135deg, var(--accent), var(--violet)); box-shadow: inset 0 0 0 1px rgb(255 255 255 / 18%), var(--shadow); }
h1 { margin: 0; font-size: var(--fs-lg); font-weight: 680; letter-spacing: -.01em; }
.navbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); padding: var(--sp-2) var(--sp-5); background: var(--glass-panel); border-bottom: 1px solid var(--line); }
.tabs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3); }
.tab-group { display: inline-flex; align-items: center; gap: 2px; }
.subtabs { display: inline-flex; gap: 2px; padding-left: var(--sp-1); border-left: 1px solid var(--line); }
.subtabs button { font-size: var(--fs-sm); }
.tabs button { display: inline-flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border: 0; border-radius: 10px; background: transparent; color: var(--muted); font-weight: 560; cursor: pointer; transition: background .15s, color .15s; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.bi { flex: none; width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
.icon-only { min-width: 34px; justify-content: center; font-size: var(--fs-lg); line-height: 1; }
.btn.small.icon-only { min-width: 30px; padding: 4px 8px; font-size: var(--fs-md); }
.bi.caret { width: .7em; height: .7em; opacity: .7; }
.btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); }
.tabs button:hover { background: var(--hover); color: var(--text); }
.tabs button[aria-current="page"] { background: var(--accent-soft); color: var(--accent); }
.badge { min-width: 22px; padding: 0 7px; border-radius: 999px; background: var(--neutral-soft); color: var(--muted); font-size: var(--fs-xs); font-weight: 650; line-height: 20px; text-align: center; font-variant-numeric: tabular-nums; }
.badge[hidden] { display: none; }
.badge.urgent { background: var(--accent); color: var(--on-accent); }
.badge.alarm { background: var(--alarm); color: #fff; }
.tools { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px; }
.banner { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-5); background: var(--alarm); color: #fff; font-weight: 650; }
.banner[hidden] { display: none; }
.banner .text { flex: 1; margin: 0; }
.banner .btn { border-color: rgb(255 255 255 / 70%); background: transparent; color: #fff; }
.menu { position: relative; }
.menu > summary { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--panel); font-weight: 580; cursor: pointer; list-style: none; }
.menu > summary::-webkit-details-marker { display: none; }
.menu-box { position: absolute; top: calc(100% + 6px); z-index: 25; display: grid; gap: var(--sp-3); width: max-content; max-width: min(640px, calc(100vw - 32px)); padding: var(--sp-3) var(--sp-4); background: var(--glass-card); border: 1px solid var(--line-strong); border-radius: var(--radius); box-shadow: var(--shadow-lift); }
.menu-box.end { right: 0; }
.menu-box textarea { min-width: min(460px, calc(100vw - 64px)); }
.menu-box h3 { margin: 0; color: var(--muted); font-size: var(--fs-xs); font-weight: 650; letter-spacing: .04em; text-transform: uppercase; }
.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.classes { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.updated { display: inline-flex; align-items: center; gap: 7px; color: var(--muted); font-size: var(--fs-sm); white-space: nowrap; }
.updated::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }
.updated.offline::before { background: var(--bad); box-shadow: 0 0 0 3px var(--bad-soft); }
body.leitstand { --fs-xs: 13px; --fs-sm: 14px; --fs-md: 16px; --fs-lg: 18px; --fs-xl: 21px; --fs-2xl: 26px; --fs-3xl: 44px; }
.shell { padding: var(--sp-4) var(--sp-4) var(--sp-6); }
main { min-width: 0; min-height: calc(100vh - var(--head) - var(--sp-6) - var(--sp-4)); padding: var(--sp-5) var(--sp-5) 80px; background: var(--glass); border: 1px solid color-mix(in srgb, var(--line) 70%, transparent); border-radius: var(--radius-lg); box-shadow: var(--shadow); }
@media (max-width: 640px) {
.top, .navbar, .banner { gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); }
.shell { padding: var(--sp-2) var(--sp-2) var(--sp-6); }
main { padding: var(--sp-3) var(--sp-3) 88px; border-radius: var(--radius); }
.menu-box { position: fixed; top: auto; right: var(--sp-2); left: var(--sp-2); width: auto; }
.replay { flex-basis: 100%; min-width: 0; }
.sheet { padding: 0; }
.sheet-box { min-height: 100%; border-radius: 0; }
.settings .grid { grid-template-columns: minmax(0, 1fr); }
}
.stack { display: grid; gap: 26px; }
.group-title { display: flex; align-items: center; gap: 10px; margin: 0; font-size: var(--fs-sm); font-weight: 650; color: var(--muted); letter-spacing: .02em; text-transform: uppercase; }
.count { min-width: 20px; padding: 0 7px; border-radius: 999px; background: var(--neutral-soft); color: var(--muted); font-size: var(--fs-xs); line-height: 19px; text-align: center; text-transform: none; }
.card { min-width: 0; padding: var(--sp-4) var(--sp-4); background: var(--glass-card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); transition: background-color .8s var(--ease), border-color .8s var(--ease); }
.card.alarm { border-color: color-mix(in srgb, var(--alarm) 45%, var(--line)); background: linear-gradient(0deg, var(--panel), color-mix(in srgb, var(--bad-soft) 70%, var(--panel))); }
.card.flush { padding: 0; overflow: hidden; }
.card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.muted { color: var(--muted); font-size: var(--fs-sm); }
h2.title { margin: 0 0 2px; font-size: var(--fs-xl); font-weight: 650; letter-spacing: -.01em; overflow-wrap: anywhere; }
h3 { margin: 0; font-size: var(--fs-lg); font-weight: 620; overflow-wrap: anywhere; }
.who { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.text { margin: 8px 0 0; overflow-wrap: anywhere; white-space: pre-wrap; }
.meta { display: flex; flex-wrap: wrap; gap: 6px 22px; margin: 8px 0 0; font-size: var(--fs-sm); }
.meta div { display: flex; gap: 6px; min-width: 0; }
.meta dt { color: var(--muted); }
.meta dd { min-width: 0; margin: 0; overflow-wrap: anywhere; }
.command { display: flex; align-items: center; gap: 10px; margin-top: 4px; padding: 7px 10px; background: var(--sunken); border: 1px solid var(--line); border-radius: 10px; }
.command code { flex: 1; min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; }
pre.notes { max-height: 260px; margin: 12px 0 0; padding: 10px 12px; overflow: auto; background: var(--sunken); border: 1px solid var(--line); border-radius: 10px; white-space: pre-wrap; overflow-wrap: anywhere; }
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 14px; }
.spacer { flex: 1; }
.btn { display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--panel); color: var(--text); font-weight: 580; text-decoration: none; cursor: pointer; transition: background .15s, border-color .15s, transform .05s; }
.btn:hover { background: var(--hover); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn.small { padding: 4px 10px; font-size: var(--fs-sm); }
.btn.ghost { border-color: transparent; background: transparent; color: var(--muted); }
.btn.ghost:hover { background: var(--hover); color: var(--text); }
.btn.primary { background: var(--ok); border-color: var(--ok); color: #fff; }
.btn.primary:hover { background: color-mix(in srgb, var(--ok) 88%, #000); }
.btn.danger { border-color: color-mix(in srgb, var(--bad) 55%, var(--line)); color: var(--bad); }
.btn.danger:hover { background: var(--bad-soft); }
.btn.soft { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
.pill { display: inline-flex; align-items: center; gap: 5px; padding: 1px 9px; border-radius: 999px; font-size: var(--fs-xs); font-weight: 650; line-height: 20px; white-space: nowrap; background: var(--neutral-soft); color: var(--muted); }
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .85; }
.pill[data-tone="ok"] { background: var(--ok-soft); color: var(--ok); }
.pill[data-tone="bad"] { background: var(--bad-soft); color: var(--bad); }
.pill[data-tone="warn"] { background: var(--warn-soft); color: var(--warn); }
.pill[data-tone="info"] { background: var(--info-soft); color: var(--info); }
.pill[data-tone="violet"] { background: var(--violet-soft); color: var(--violet); }
.pill[data-tone="teal"] { background: var(--teal-soft); color: var(--teal); }
.empty { display: grid; justify-items: center; gap: var(--sp-2); padding: var(--sp-7) var(--sp-5); background: var(--glass-card); border: 1px dashed var(--line-strong); border-radius: var(--radius); text-align: center; }
.empty h2 { margin: 6px 0 0; font-size: var(--fs-lg); font-weight: 640; }
.empty p { margin: 0; color: var(--muted); }
.empty-mark { width: 40px; height: 40px; border-radius: 50%; background: radial-gradient(circle, var(--ok) 0 5px, var(--ok-soft) 6px); }
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 10px; }
.chip { display: inline-flex; align-items: center; gap: 6px; max-width: 360px; padding: 5px 12px; overflow: hidden; border: 1px solid var(--line); border-radius: 999px; background: var(--panel); color: var(--muted); font-weight: 560; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.chip:hover { color: var(--text); border-color: var(--line-strong); }
.chip[aria-pressed="true"] { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
.chip.preset { font-weight: 650; }
.chip .x { padding: 0 2px; border: 0; background: none; color: inherit; cursor: pointer; }
.split { display: grid; grid-template-columns: minmax(220px, 320px) minmax(0, 1fr); gap: 14px; align-items: start; }
@media (max-width: 860px) { .split { grid-template-columns: minmax(0, 1fr); } }
.tree { position: sticky; top: 0; max-height: 70vh; padding: 10px 6px; overflow: auto; }
.tree-title { margin: 6px 10px 4px; color: var(--muted); font-size: var(--fs-xs); font-weight: 650; letter-spacing: .04em; text-transform: uppercase; }
.tree-list { margin: 0; padding: 0 0 0 10px; list-style: none; }
.tree > div > .tree-section > .tree-list { padding-left: 0; }
.tree summary { padding: 3px 8px; border-radius: 7px; color: var(--muted); font-size: var(--fs-sm); cursor: pointer; }
.tree summary:hover { background: var(--hover); }
.dir { font-family: var(--mono); font-size: var(--fs-sm); }
.file-entry { display: flex; align-items: center; gap: 8px; width: 100%; padding: 4px 8px; border: 0; border-radius: 7px; background: transparent; text-align: left; cursor: pointer; }
.file-entry:hover { background: var(--hover); }
.file-entry[aria-current="true"] { background: var(--accent-soft); color: var(--accent); }
.file-entry .name { flex: 1; min-width: 0; overflow: hidden; font-family: var(--mono); font-size: var(--fs-sm); text-overflow: ellipsis; white-space: nowrap; }
.letter { display: inline-grid; place-items: center; flex: none; width: 18px; height: 18px; border-radius: 5px; background: var(--neutral-soft); color: var(--muted); font-family: var(--mono); font-size: var(--fs-2xs); font-weight: 700; }
.letter[data-tone="ok"] { background: var(--ok-soft); color: var(--ok); }
.letter[data-tone="bad"] { background: var(--bad-soft); color: var(--bad); }
.letter[data-tone="info"] { background: var(--info-soft); color: var(--info); }
.letter[data-tone="violet"] { background: var(--violet-soft); color: var(--violet); }
.letter[data-tone="warn"] { background: var(--warn-soft); color: var(--warn); }
.stat { display: inline-flex; gap: 6px; font-family: var(--mono); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.stat .add { color: var(--ok); }
.stat .del { color: var(--bad); }
.diff-pane { padding: 0; overflow: hidden; }
.diff-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); background: var(--sunken); }
.diff-head .path { overflow-wrap: anywhere; font-weight: 600; }
.pad { margin: 0; padding: 18px 16px; }
.diff-scroll { overflow: auto; max-height: 70vh; }
table.diff { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: var(--fs-sm); line-height: 1.5; }
table.diff td { padding: 0 10px; vertical-align: top; }
table.diff td.num { width: 1%; min-width: 44px; color: var(--faint); text-align: right; user-select: none; white-space: nowrap; font-variant-numeric: tabular-nums; }
table.diff td.sign { width: 1%; padding: 0 4px; color: var(--faint); user-select: none; }
table.diff td.code { white-space: pre-wrap; overflow-wrap: anywhere; }
table.diff tr.add { background: var(--add-bg); }
table.diff tr.add td.code, table.diff tr.add td.sign { color: var(--add-text); }
table.diff tr.del { background: var(--del-bg); }
table.diff tr.del td.code, table.diff tr.del td.sign { color: var(--del-text); }
table.diff tr.hunk td { padding-top: 4px; padding-bottom: 4px; background: var(--hunk-bg); color: var(--muted); }
table.diff tr.more td { padding: 8px 16px; color: var(--muted); font-style: italic; }
.feed { margin: 0; padding: 0; list-style: none; }
.footnote { margin: 0; padding: 12px 18px; color: var(--muted); font-size: var(--fs-sm); }
.entry { display: grid; grid-template-columns: 170px minmax(0, 1fr); gap: 12px; padding: 10px 18px; border-bottom: 1px solid var(--line); }
@media (max-width: 640px) {
.entry { grid-template-columns: minmax(0, 1fr); padding: 10px 12px; }
.msg-meta { display: flex; flex-wrap: wrap; align-items: center; }
.tabs button { padding: 6px 8px; }
}
.entry:last-child { border-bottom: 0; }
.entry:hover { background: var(--hover); }
.entry.waiting { box-shadow: inset 3px 0 0 var(--warn); }
.entry.alarm { background: color-mix(in srgb, var(--bad-soft) 75%, var(--panel)); }
.entry pre { margin: 4px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.entry.k-transcript pre, .entry.k-cron pre, .entry.k-run pre { color: var(--muted); }
.entry .line-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.msg-meta { display: grid; justify-items: start; align-content: start; gap: 4px; color: var(--muted); font-size: var(--fs-sm); }
.route { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.route .headline { font-weight: 600; overflow-wrap: anywhere; }
.filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 10px; }
.filters select, .filters input, .field { padding: 6px 10px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--panel); }
.filters input[type="search"] { flex: 1; min-width: 200px; }
.graph { display: grid; gap: 14px; }
.controls { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; padding: 10px 14px; }
.segmented { display: inline-flex; padding: 3px; gap: 2px; border-radius: 10px; background: var(--sunken); border: 1px solid var(--line); }
.segmented button { padding: 4px 11px; border: 0; border-radius: 8px; background: transparent; color: var(--muted); font-size: var(--fs-sm); font-weight: 580; cursor: pointer; }
.segmented button[aria-selected="true"], .segmented button[aria-pressed="true"] { background: var(--panel); color: var(--text); box-shadow: var(--shadow); }
.replay { display: flex; flex: 1; align-items: center; gap: 10px; min-width: 280px; }
.replay input[type="range"] { flex: 1; accent-color: var(--accent); }
.window-label { color: var(--muted); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; white-space: nowrap; }
.stage-card { padding: 8px; }
.stage svg { display: block; width: 100%; height: auto; max-height: calc(100vh - var(--head) - 120px); }
body.fit { display: flex; flex-direction: column; height: 100vh; }
body.fit .shell, body.fit main, body.fit .graph, body.fit .stage-card, body.fit .stage { display: flex; flex: 1; flex-direction: column; min-height: 0; }
body.fit main { padding-bottom: var(--sp-5); }
body.fit .stage svg, body.fit .stage canvas.space, body.fit .graph3d { flex: 1; height: auto; min-height: 0; max-height: none; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; padding: 6px 10px 4px; color: var(--muted); font-size: var(--fs-sm); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.swatch { display: inline-block; width: 18px; height: 4px; border-radius: 2px; background: var(--c); }
.panel-title { margin: 0; font-size: var(--fs-xl); font-weight: 650; overflow-wrap: anywhere; }
.popup-box h3 { display: flex; align-items: center; gap: 8px; margin: 18px 0 8px; color: var(--muted); font-size: var(--fs-xs); font-weight: 650; letter-spacing: .04em; text-transform: uppercase; }
.mini { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.mini li { display: grid; gap: 3px; padding: 9px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--sunken); font-size: var(--fs-sm); overflow-wrap: anywhere; }
.mini .row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.roles { color: var(--accent); font-size: var(--fs-sm); font-weight: 600; }
.t-direct { --c: var(--direct); }
.t-broadcast { --c: var(--broadcast); }
.t-alarm { --c: var(--alarm); }
.t-security { --c: var(--security); }
.t-grant { --c: var(--grant); }
.t-spawn { --c: var(--violet); }
svg.chart { font-family: inherit; }
svg .ring { fill: none; stroke: var(--line-strong); stroke-dasharray: 2 7; }
svg .edge { fill: none; stroke: var(--c); stroke-linecap: round; opacity: .55; transition: opacity .15s; }
svg .edge:hover { opacity: 1; }
svg .tip { fill: var(--c); }
svg .halo { fill: none; stroke: var(--c); opacity: .35; }
svg .node { cursor: pointer; }
svg .node circle { fill: var(--panel); stroke: var(--line-strong); stroke-width: 1.5; transition: stroke .15s; }
svg .node:hover circle, svg .node:focus-visible circle { stroke: var(--accent); }
svg .node:focus-visible { outline: none; }
svg .node.k-operator circle { fill: var(--accent); stroke: color-mix(in srgb, var(--accent) 60%, var(--panel)); stroke-width: 6; }
svg .node.k-chair circle { fill: var(--accent-soft); stroke: var(--accent); stroke-width: 2; }
svg .node.k-subagent circle { fill: var(--violet-soft); stroke: var(--violet); }
svg .node.claimed circle { stroke: var(--ok); stroke-width: 2.2; }
svg .label { fill: var(--text); font-size: var(--fs-sm); font-weight: 560; paint-order: stroke; stroke: var(--panel); stroke-width: 4px; stroke-linejoin: round; }
svg .initial { fill: var(--muted); font-size: var(--fs-sm); font-weight: 700; pointer-events: none; }
svg .k-operator .initial { fill: var(--on-accent); font-size: var(--fs-xl); }
svg .k-chair .initial { fill: var(--accent); font-size: var(--fs-lg); }
svg .group-arc { fill: none; stroke: var(--line-strong); stroke-width: 7; stroke-linecap: round; }
svg .group-arc.k-operator, svg .group-arc.k-chair { stroke: var(--accent); }
svg .tick { stroke: var(--c); stroke-linecap: round; opacity: .7; }
svg .lane { fill: transparent; }
svg .lane.odd { fill: var(--sunken); }
svg .lane-label { fill: var(--text); font-size: var(--fs-sm); font-weight: 560; cursor: pointer; }
svg .grid { stroke: var(--line); }
svg .axis { fill: var(--muted); font-size: var(--fs-2xs); }
svg .now { stroke: var(--accent); stroke-dasharray: 3 4; }
svg .mark { stroke: var(--c); fill: var(--c); opacity: .75; }
svg .mark line, svg .mark path { fill: none; stroke-width: 1.6; stroke-linecap: round; }
svg .mark:hover { opacity: 1; }
svg .mark:hover line, svg .mark:hover path { stroke-width: 2.6; }
svg .pulse { fill: var(--c); filter: drop-shadow(0 0 4px var(--c)); }
svg .pulse-ring { fill: none; stroke: var(--c); stroke-width: 2.5; }
svg .node.a-repo circle, svg .node.sun circle { fill: color-mix(in srgb, var(--warn) 70%, var(--panel)); stroke: var(--warn); stroke-width: 3; }
svg .node.a-worktree circle { fill: var(--sunken); stroke: var(--muted); }
svg .node.a-worktree.dirty circle { fill: var(--warn-soft); stroke: var(--warn); }
svg .node.satellite circle { fill: var(--accent); stroke: none; }
svg .node.cargo circle { fill: var(--teal); stroke: none; }
svg .node.tone-ok circle { fill: var(--ok-soft); stroke: var(--ok); }
svg .node.tone-warn circle { fill: var(--warn-soft); stroke: var(--warn); }
svg .node.tone-bad circle { fill: var(--bad-soft); stroke: var(--bad); }
svg .node.tone-info circle { fill: var(--info-soft); stroke: var(--info); }
svg .node.tone-violet circle { fill: var(--violet-soft); stroke: var(--violet); }
svg .node.picked circle { fill: var(--alarm); stroke: var(--alarm); transform: scale(1.6); transform-box: fill-box; transform-origin: center; }
svg .lane-label.picked { fill: var(--alarm); font-size: var(--fs-lg); font-weight: 750; }
.linkish.picked { color: var(--alarm); transform: scale(1.15); }
svg .edge.merge { stroke-dasharray: 5 5; }
svg .lane-mark { stroke-width: 1.2; }
svg .lane-mark.tone-ok { fill: var(--ok); stroke: var(--ok); }
svg .lane-mark.tone-bad { fill: var(--bad); stroke: var(--bad); }
svg .lane-mark.tone-info { fill: var(--info); stroke: var(--info); }
svg .lane-mark.tone-neutral { fill: var(--muted); stroke: var(--muted); }
input[type="datetime-local"] { padding: 3px 6px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--panel); font-size: var(--fs-sm); }
.custom { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.avatar { display: inline-grid; place-items: center; flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--sunken); border: 1px solid var(--line); font-size: var(--fs-lg); line-height: 1; }
.avatar.big { width: 52px; height: 52px; font-size: var(--fs-3xl); }
.linkish { padding: 0; border: 0; background: none; color: inherit; font-weight: 650; text-align: left; cursor: pointer; overflow-wrap: anywhere; }
.linkish:hover { color: var(--accent); text-decoration: underline; }
.popup { position: fixed; inset: 0; z-index: 25; width: auto; height: auto; max-width: none; max-height: none; margin: 0; padding: 0; overflow: hidden; border: 0; background: transparent; color: var(--text); }
.fade { animation: fade .2s var(--ease); }
.leader { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.leader line { stroke: var(--alarm); stroke-width: 2; stroke-linecap: round; }
.popup-box { position: absolute; display: flex; flex-direction: column; gap: var(--sp-2); width: min(440px, calc(100% - 2 * var(--sp-4))); max-height: calc(100% - 2 * var(--sp-4)); padding: var(--sp-4); overflow: auto; background: var(--glass-card); border: 1px solid var(--line-strong); border-radius: var(--radius); box-shadow: var(--shadow-lift); opacity: .94; }
.popup-head { display: flex; flex: none; align-items: center; gap: 12px; }
.popup-body { flex: 0 1 auto; min-height: 7em; overflow: auto; }
.popup-form { display: grid; flex: none; gap: 8px; padding-top: 12px; border-top: 1px solid var(--line); }
.node-search { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.node-search .chips { margin-bottom: 0; }
textarea { width: 100%; min-height: 84px; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--panel); color: var(--text); font: inherit; resize: vertical; }
.bubble { display: grid; gap: 3px; margin: 0 0 8px; padding: 8px 11px; border-radius: 12px; background: var(--sunken); border: 1px solid var(--line); font-size: var(--fs-sm); overflow-wrap: anywhere; white-space: pre-wrap; }
.bubble.mine { margin-left: 34px; background: var(--accent-soft); border-color: transparent; }
.bubble.theirs { margin-right: 34px; }
.toasts { position: fixed; right: 18px; bottom: 18px; z-index: 40; display: grid; gap: 10px; width: min(440px, calc(100vw - 36px)); }
.toast { padding: var(--sp-3) var(--sp-4); background: var(--glass-card); border: 1px solid var(--line-strong); border-left: 4px solid var(--ok); border-radius: 12px; box-shadow: var(--shadow-lift); cursor: pointer; }
.toast.bad { border-left-color: var(--bad); }
.toast.wait { border-left-color: var(--warn); cursor: default; }
.toast pre { max-height: 180px; margin: 6px 0 0; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }
.undo-row { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.palette, .sheet { position: fixed; inset: 0; z-index: 50; display: grid; justify-items: center; align-items: start; padding: 10vh var(--sp-4) var(--sp-4); overflow: auto; background: rgb(0 0 0 / 32%); animation: fade .18s var(--ease); }
.sheet { z-index: 30; padding-top: 5vh; }
.palette[hidden], .sheet[hidden] { display: none; }
.palette-box, .sheet-box { animation: rise .22s var(--ease); }
@keyframes fade { from { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(8px) scale(.99); } }
.palette-box { width: min(620px, calc(100vw - 32px)); overflow: hidden; background: var(--glass-card); border: 1px solid var(--line-strong); border-radius: var(--radius); box-shadow: var(--shadow-lift); }
.palette-box input { width: 100%; padding: 14px 16px; border: 0; background: transparent; font-size: var(--fs-lg); outline: none; }
.palette-row { display: flex; align-items: center; gap: 6px; padding-right: 10px; border-bottom: 1px solid var(--line); }
.palette-row input { flex: 1; min-width: 0; }
.mic[aria-pressed="true"] { background: var(--bad-soft); color: var(--bad); }
.palette-list { max-height: 55vh; margin: 0; padding: 6px; overflow: auto; list-style: none; }
.palette-list li { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; cursor: pointer; }
.palette-list li[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); }
.palette-list .muted { margin-left: auto; }
.palette-plan { display: grid; gap: 8px; padding: 12px 16px 16px; }
.palette-plan pre { margin: 0; padding: 8px 10px; background: var(--sunken); border-radius: 8px; white-space: pre-wrap; overflow-wrap: anywhere; }
.sheet-box { width: min(760px, 100%); background: var(--glass-card); border: 1px solid var(--line-strong); border-radius: var(--radius); box-shadow: var(--shadow-lift); }
.sheet-box.wide { width: min(1400px, 100%); }
.sheet-head { display: flex; align-items: center; gap: 10px; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.sheet-body { display: grid; gap: 14px; padding: 16px 18px 20px; }
.options { display: grid; gap: 6px; margin-top: 8px; }
.option { display: grid; gap: 2px; padding: 8px 11px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--panel); text-align: left; cursor: pointer; }
.option:hover { background: var(--accent-soft); border-color: var(--accent); }
.option.recommended { border-color: var(--ok); box-shadow: inset 3px 0 0 var(--ok); }
.option span { color: var(--muted); font-size: var(--fs-sm); }
.inbox-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.inbox-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.inbox-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.item { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2) var(--sp-3); padding: var(--sp-3); border: 1px solid var(--line); border-radius: 12px; background: var(--glass-card); }
.item.cursor { outline: 2px solid var(--accent); outline-offset: 1px; }
.item.green { box-shadow: inset 3px 0 0 var(--ok); }
.item.red { box-shadow: inset 3px 0 0 var(--bad); }
.item.held { opacity: .6; }
.item input[type="checkbox"] { margin-top: 4px; accent-color: var(--accent); }
.head-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 4px; }
.item-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.check { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: var(--fs-sm); cursor: pointer; }
.order-list { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.order-list li { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--sunken); cursor: grab; }
.order-list li.dragging { opacity: .5; }
.order-list .rank { min-width: 22px; color: var(--muted); font-variant-numeric: tabular-nums; }
.board { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); gap: 14px; align-items: start; }
.repos { display: grid; gap: 10px; }
.repo { padding: 0; overflow: hidden; }
.repo > summary { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 11px 16px; font-weight: 620; cursor: pointer; }
.branch-row { display: grid; gap: 6px; padding: 9px 16px 9px 30px; border-top: 1px solid var(--line); }
.branch-name { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.wt { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 7px 10px; border-radius: 8px; background: var(--sunken); font-size: var(--fs-sm); }
.wt code { overflow-wrap: anywhere; }
.rule-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; }
.rule-form { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; align-items: end; }
.rule-form label, .sound-row label { display: grid; gap: 4px; color: var(--muted); font-size: var(--fs-sm); }
.sound-row { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(120px, 220px) auto; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--line); }
.settings { display: grid; gap: var(--sp-5); }
.settings [hidden] { display: none; }
.settings section { display: grid; gap: var(--sp-3); }
.settings h3 { margin: 0; color: var(--muted); font-size: var(--fs-xs); font-weight: 650; letter-spacing: .04em; text-transform: uppercase; }
.settings .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--sp-3); align-items: end; }
.settings label { display: grid; gap: var(--sp-1); color: var(--muted); font-size: var(--fs-sm); }
.settings label.check { display: inline-flex; }
.settings input[type="color"] { width: 100%; height: 36px; padding: 2px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--panel); }
.settings input[type="range"] { accent-color: var(--accent); }
.stream-row { display: grid; gap: var(--sp-2); padding: var(--sp-3); border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--sunken); }
.days { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.sheet-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
.keys { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; margin: 0; }
.keys dt { font-family: var(--mono); font-weight: 650; }
.keys dd { margin: 0; color: var(--muted); }
.space-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.stage canvas.space { display: block; width: 100%; height: clamp(360px, 68vh, 820px); border-radius: var(--radius-sm); cursor: grab; touch-action: none; }
.stage canvas.space:active { cursor: grabbing; }
.space-note { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; padding: 8px 10px 0; color: var(--muted); font-size: var(--fs-sm); }
body.sky-look .shell { visibility: hidden; }
body.sky-look .sky { z-index: 5; pointer-events: auto; cursor: grab; touch-action: none; }
body.sky-look .sky:active { cursor: grabbing; }
.sky-panel { position: fixed; bottom: var(--sp-5); left: 50%; z-index: 8; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; max-width: calc(100vw - 24px); padding: 8px 12px; transform: translateX(-50%); background: var(--glass-card); border: 1px solid var(--line-strong); border-radius: var(--radius); box-shadow: var(--shadow-lift); }
.sky-panel[hidden] { display: none; }
.compass { min-width: 220px; font-weight: 620; font-variant-numeric: tabular-nums; text-align: center; }
.states { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.state { display: inline-flex; align-items: center; gap: 4px; padding: 1px 8px; border-radius: 999px; background: var(--neutral-soft); color: var(--muted); font-size: var(--fs-xs); font-weight: 650; line-height: 20px; white-space: nowrap; }
.state[data-tone="ok"] { background: var(--ok-soft); color: var(--ok); }
.state[data-tone="bad"] { background: var(--bad-soft); color: var(--bad); }
.state[data-tone="warn"] { background: var(--warn-soft); color: var(--warn); }
.state[data-tone="info"] { background: var(--info-soft); color: var(--info); }
.state[data-tone="violet"] { background: var(--violet-soft); color: var(--violet); }
.wt-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; width: 100%; }
.leaves { display: grid; gap: 4px; width: 100%; margin: 0; padding: 0 0 0 18px; list-style: none; }
.leaf { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: var(--fs-sm); }
.hint { color: var(--muted); font-size: var(--fs-xs); }
.delete-all { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.dry-run { margin: 4px 0 0; padding: 8px 10px; background: var(--sunken); border-radius: 8px; font-family: var(--mono); font-size: var(--fs-sm); white-space: pre-wrap; overflow-wrap: anywhere; }
pre.notes { margin: 0; padding: 8px 10px; background: var(--sunken); border-radius: 8px; font-size: var(--fs-sm); white-space: pre-wrap; overflow-wrap: anywhere; }
.spawn-tree { display: grid; gap: 4px; margin: 0; padding: 0 0 0 18px; list-style: none; }
.spawn-tree.root { padding-left: 0; }
.spawn-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 5px 8px; border-radius: 8px; }
.spawn-row:hover { background: var(--hover); }
.graph3d { position: relative; width: 100%; height: clamp(360px, 68vh, 820px); overflow: hidden; border-radius: var(--radius-sm); cursor: grab; touch-action: none; }
.graph3d:active { cursor: grabbing; }
.graph3d .scene-nav-info, .graph3d .graph-info-msg { display: none; }
.graph3d .scene-container { position: relative; }
.float-tooltip-kap { position: absolute; z-index: 9; padding: 4px 8px; border-radius: 6px; background: var(--glass-card); color: var(--text); font-size: var(--fs-sm); white-space: nowrap; pointer-events: none; box-shadow: var(--shadow); }
{% include "style-hierarchy.css" %}
{% include "style-inbox.css" %}
{% include "style-ui.css" %}
{% include "style-tasks.css" %}
</style>
</head>
<body>
{{ icons }}
<canvas class="sky" id="sky" aria-hidden="true"></canvas>
<div class="head" id="head">
<header class="top">
<div class="brand"><span class="logo" aria-hidden="true"></span><div class="brand-text"><h1>Agent Orchestrator</h1><span class="sky-note" id="sky-note"></span></div></div>
<div class="tools">
<button type="button" class="btn small ghost icon-only" id="palette-open" title="Commands (Ctrl+K)" aria-label="Commands"><svg class="bi" aria-hidden="true" focusable="false"><use href="#bi-command"></use></svg></button>
<button type="button" class="btn small ghost icon-only" id="settings-open" title="Settings and ambience" aria-label="Settings"><svg class="bi" aria-hidden="true" focusable="false"><use href="#bi-gear"></use></svg></button>
</div>
</header>
<div class="navbar">
<nav class="tabs" id="tabs" aria-label="Navigation"></nav>
<span class="spacer"></span>
<details class="menu" id="time"></details>
<span class="updated" id="updated" aria-live="polite"></span>
</div>
<div class="banner" id="mayday" role="alert" hidden></div>
</div>
<div class="shell">
<main id="main"></main>
</div>
<dialog class="popup fade" id="popup" aria-label="Details"><svg class="leader" aria-hidden="true"><line></line></svg><div class="popup-box"></div></dialog>
<div class="sheet" id="sheet" hidden></div>
<div class="toasts" id="toasts" aria-live="polite"></div>
<div class="palette" id="palette" hidden></div>
<div class="sky-panel" id="sky-panel" role="group" aria-label="View of the sky" hidden></div>
<script nonce="{{ nonce }}" id="state" type="application/json">{{ state | tojson }}</script>
<script nonce="{{ nonce }}">
{% include "ambience.js" %}
</script>
<script nonce="{{ nonce }}">
{% include "voice.js" %}
{% include "nav.js" %}
{% include "popup.js" %}
</script>
<script nonce="{{ nonce }}">
{# Jinja drops each file's last newline and trim_blocks the one after the tag: the blank lines keep consecutive modules on separate lines #}
{% include "space-view.js" %}
{% include "space-scene.js" %}
{% include "space-paint.js" %}
{% include "space-pick.js" %}
{% include "space.js" %}
</script>
<script nonce="{{ nonce }}">
(() => {
"use strict";
{% include "page-constants.js" %}
{% include "page-state.js" %}
{% include "page-dom.js" %}
{% include "page-api.js" %}
{% include "page-passkey.js" %}
{% include "page-board.js" %}
{% include "page-screens.js" %}
{% include "page-inbox.js" %}
{% include "page-console.js" %}
{% include "page-deny.js" %}
{% include "page-rule-request.js" %}
{% include "page-review.js" %}
{% include "page-filters.js" %}
{% include "page-stream.js" %}
{% include "page-graph-layout.js" %}
{% include "page-graph-charts.js" %}
{% include "page-space-steer.js" %}
{% include "page-spawn.js" %}
{% include "page-hierarchy.js" %}
{% include "page-agent-order.js" %}
{% include "page-graph3d.js" %}
{% include "page-artifacts.js" %}
{% include "page-tree.js" %}
{% include "page-flow.js" %}
{% include "page-cleanup.js" %}
{% include "page-offices.js" %}
{% include "page-tasks.js" %}
{% include "page-tasks-prio.js" %}
{% include "page-time.js" %}
{% include "page-pulses.js" %}
{% include "page-music.js" %}
{% include "page-sky.js" %}
{% include "page-radio.js" %}
{% include "page-radioview.js" %}
{% include "page-composer.js" %}
{% include "page-settings.js" %}
{% include "page-speech.js" %}
{% include "page-alerts.js" %}
{% include "page-rules.js" %}
{% include "page-keyboard.js" %}
{% include "page-popup.js" %}
{% include "page-agent.js" %}
{% include "page-palette.js" %}
{% include "page-load.js" %}
{% include "page-boot.js" %}
})();
</script>
</body>
</html>