/* steps web — the annotated transcript.
 *
 * The world is a terminal, committed: warm near-black ground with no glow or
 * gradient, hairline pane rules, prompt-styled headings, and ANSI-16 as the
 * status palette — green/red/yellow/blue mean here exactly what they mean in
 * the terminal this product otherwise lives in, so the semantics cost no
 * learning. Two type voices carry the hierarchy: mono for every piece of
 * data, a compact sans for labels and annotations about that data.
 *
 * Single-theme on purpose. This is a terminal's UI; a light rendition would
 * be a different product wearing the same routes.
 */

:root {
  /* Single-theme, but say so: without this the UA paints form controls and
     scrollbars for whatever the OS prefers, light chrome on a dark page. */
  color-scheme: dark;
  --bg: #111310;
  --panel: #171a16;
  --panel2: #1c201b;
  --line: #262b25;
  /* The ground every code, log, and data block sits on: a step down from
     --panel, so a payload reads as something the page is quoting rather than
     as more page. */
  --code-bg: #0c0e0b;
  --line-soft: #1e231d;
  --fg: #d8d5c9;
  --dim: #83887b;
  --faint: #565b50;
  --green: #84c06d;
  --red: #e0645a;
  --yellow: #d9a94a;
  --blue: #7aa4d9;
  --magenta: #b98fcc;
  --cyan: #6fbcb4;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.55;
  min-height: 100vh;
}

a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 1px solid var(--yellow); outline-offset: 1px; }

code { font-family: var(--mono); color: var(--fg); }

/* ---- top status line ---- */
.statusline {
  display: flex;
  align-items: stretch;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 20;
  font-size: 12px;
  flex-wrap: wrap;
}
.statusline .brand { padding: 8px 14px; color: var(--green); border-right: 1px solid var(--line); white-space: nowrap; }
.statusline .brand b { color: var(--fg); font-weight: 600; }
.statusline .brand:hover { text-decoration: none; }
.statusline .brand:hover b { color: var(--green); }
.tabs { display: flex; }
.tab {
  padding: 8px 14px;
  color: var(--dim);
  border-right: 1px solid var(--line-soft);
  white-space: nowrap;
}
.tab:hover { color: var(--fg); text-decoration: none; }
.tab[aria-current="page"] { color: var(--fg); background: var(--bg); box-shadow: inset 0 2px 0 var(--green); }
.tab .badge { color: var(--yellow); margin-left: 6px; }
.statusline .right {
  margin-left: auto;
  padding: 8px 14px;
  color: var(--faint);
  display: flex;
  gap: 16px;
  align-items: center;
  white-space: nowrap;
}
.statusline .ro { color: var(--yellow); }
.statusline kbd {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 0 5px;
}

/* pipeline switcher */
.pipeswitch { position: relative; }
.pipebtn { font: inherit; font-size: 12px; color: var(--dim); background: none; border: 0; cursor: pointer; padding: 0; }
.pipebtn:hover { color: var(--fg); }
.pipemenu {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  background: var(--panel);
  border: 1px solid var(--line);
  min-width: 240px;
  z-index: 30;
}
.pipemenu.open { display: block; }
.pipemenu a {
  display: flex;
  gap: 12px;
  align-items: baseline;
  font-size: 12px;
  color: var(--fg);
  padding: 8px 12px;
  border-bottom: 1px solid var(--line-soft);
}
.pipemenu a:last-child { border-bottom: 0; }
.pipemenu a:hover { background: var(--panel2); text-decoration: none; }
.pipemenu a[aria-selected="true"]::before { content: "› "; color: var(--green); }
.pipemenu .hint { margin-left: auto; color: var(--faint); font-size: 11px; }

/* ---- page frame ---- */
main { max-width: 1000px; margin: 0 auto; padding: 26px 20px 80px; }

/* What a hidden action says instead of vanishing on a read-only server. */
.rohint { font-family: var(--sans); font-size: 12px; color: var(--dim); max-width: 340px; text-align: right; }

/* The reload banner: the file on disk failed to load and the daemon is still
   serving the last configuration that worked. Red-edged rather than a tint,
   because it is not a status of anything on the page — it is a statement that
   the page is out of date with the operator's editor. */
.held {
  font-family: var(--sans);
  font-size: 12.5px;
  color: var(--fg);
  border: 1px solid #4a2c29;
  border-left: 3px solid var(--red);
  padding: 10px 12px;
  margin: 0 0 14px;
}
.held b { color: var(--red); font-weight: 600; }
.held pre { font-family: var(--mono); font-size: 12px; color: var(--dim); margin: 6px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }

/* Breadcrumbs: the way back up from a detail page. */
.crumbs { font-size: 12px; color: var(--faint); margin: 0 0 12px; overflow-wrap: anywhere; }
.crumbs a { color: var(--dim); }
.crumbs a:hover { color: var(--fg); }
.crumbs .csep { margin: 0 7px; color: var(--line); }
.crumbs .here { color: var(--fg); }

.prompt { color: var(--dim); margin: 0 0 4px; font-size: 13px; font-weight: 400; }
.prompt::before { content: "$ "; color: var(--green); }
.prompt b { color: var(--fg); font-weight: 600; }
/* A workspace path is one unbreakable token tens of characters long, and this
   line carries one. Without a break opportunity it sets the page's min-content
   width and drags the whole document sideways on a phone. */
.metaline { color: var(--faint); font-size: 12px; margin-bottom: 22px; overflow-wrap: anywhere; }
.metaline .sep { margin: 0 8px; color: var(--line); }

.eyebrow {
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 30px 0 8px;
}
.eyebrow .unbold { letter-spacing: 0; text-transform: none; font-weight: 400; }

.pagehead { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 20px; }
/* min-width:0 lets the title block shrink past its content's intrinsic width;
   a flex item defaults to min-content and refuses to. */
.pagehead > div { min-width: 0; }
.pagehead .metaline { margin-bottom: 0; }
.pagehead .actions { margin-left: auto; display: flex; gap: 8px; padding-top: 2px; }
.pagehead .actions form { margin: 0; }

/* ---- tables ---- */
.tablewrap { overflow-x: auto; border: 1px solid var(--line); background: var(--panel); }
table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
th {
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  text-align: left;
  padding: 8px 14px;
  border-bottom: 1px solid var(--line);
}
td { padding: 8px 14px; border-bottom: 1px solid var(--line-soft); white-space: nowrap; }
tr:last-child td { border-bottom: 0; }
td.num, th.num { text-align: right; }
td.dim { color: var(--dim); }
td.faint, .faint { color: var(--faint); }
.res { color: var(--cyan); }

/* ---- status ----
   One glyph per outcome, everywhere a status word appears: color is never
   the only signal. Glyph overrides are scoped to .st so a bare color class
   (a breaker count, a DAG node) does not sprout a second marker. */
.st { white-space: nowrap; }
.st::before { content: "● "; }
.st-passed, .st-succeeded { color: var(--green); }
.st-failed, .st-errored, .st-aborted { color: var(--red); }
.st-running { color: var(--yellow); }
.st-pending { color: var(--yellow); }
.st-skipped { color: var(--faint); }
.st.st-passed::before, .st.st-succeeded::before { content: "✓ "; }
.st.st-failed::before, .st.st-errored::before, .st.st-aborted::before { content: "✗ "; }
.st.st-running::before { content: "◐ "; }
.st.st-pending::before { content: "○ "; }
.st.st-skipped::before { content: "– "; }

.hash { color: var(--blue); }
.hash::before { content: "["; color: var(--faint); }
.hash::after { content: "]"; color: var(--faint); }

/* ---- controls ---- */
.btn {
  font: inherit;
  font-size: 12px;
  color: var(--fg);
  background: var(--panel2);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 4px 12px;
  cursor: pointer;
}
.btn:hover { border-color: var(--dim); }
.btn.primary { color: var(--green); border-color: #33452d; }
.btn.primary:hover { border-color: var(--green); }
.btn.danger { color: var(--red); border-color: #4a2c29; }
.btn.danger:hover { border-color: var(--red); }

.viewtoggle { display: inline-flex; border: 1px solid var(--line); margin-left: 12px; vertical-align: 2px; }
.viewtoggle button { font: inherit; font-size: 11px; color: var(--dim); background: none; border: 0; cursor: pointer; padding: 2px 10px; }
.viewtoggle button[aria-pressed="true"] { color: var(--fg); background: var(--panel2); }

/* ---- dependency graph ----
   Server-laid-out SVG; the pane scrolls sideways like every wide table. */
/* Which of the two views is showing lives on <body>, not on the views
   themselves: both are swapped by the page refresh, and a `hidden` attribute
   or an inline style set by the toggle would be replaced by the server's
   every 2.5 seconds — the graph would snap back to hidden under a reader
   who had chosen it. */
body:not([data-view="graph"]) #jobs-graph { display: none; }
body[data-view="graph"] #jobs-list { display: none; }

/* The placeholder is always in the DOM, so it is what :last-child matches on a
   finished run — and .step:last-child is the rule that drops the transcript's
   trailing hairline. Hand it to the last row a reader can actually see.
   Scoped to a placeholder that really is last, because the stream appends
   AFTER it: unscoped, a run being watched lost the hairline from whichever
   row happened to precede the placeholder, mid-list. */
#run-empty:not(:only-child) { display: none; }
.step:has(+ #run-empty:last-child) { border-bottom: 0; }

.dagwrap {
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 14px 16px 6px;
  overflow-x: auto;
}
.dagwrap .rail { color: var(--faint); font-size: 11px; }
svg.dag { display: block; }
.dagedge { fill: none; stroke: var(--faint); stroke-width: 1.5; }
.dagedge:hover { stroke: var(--fg); }
.dagnode rect { fill: var(--panel2); stroke: var(--faint); rx: 3px; }
.dagnode:hover rect { stroke: var(--fg); }
.dagnode:hover { text-decoration: none; }
.dagnode text { font-family: var(--mono); font-size: 12px; fill: var(--fg); }
.dagnode .dagstatus { font-size: 11px; fill: var(--dim); }
.dagnode.st-passed rect { stroke: var(--green); }
.dagnode.st-passed .dagstatus { fill: var(--green); }
.dagnode.st-failed rect, .dagnode.st-errored rect, .dagnode.st-aborted rect { stroke: var(--red); }
.dagnode.st-failed .dagstatus, .dagnode.st-errored .dagstatus, .dagnode.st-aborted .dagstatus { fill: var(--red); }
.dagnode.st-running rect, .dagnode.st-pending rect { stroke: var(--yellow); }
.dagnode.st-running .dagstatus, .dagnode.st-pending .dagstatus { fill: var(--yellow); }
.dagnode.st-none .dagstatus { fill: var(--faint); }
.dagnode.running rect { animation: dagpulse 1.6s ease-in-out infinite; }
@keyframes dagpulse { 50% { stroke-opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) {
  .dagnode.running rect { animation: none; }
}
.deps { font-size: 12.5px; color: var(--dim); line-height: 2; }
.deps .arrow { color: var(--faint); }

/* ---- transcript ---- */
.transcript { border: 1px solid var(--line); background: var(--panel); }
.step { border-bottom: 1px solid var(--line-soft); }
.step:last-child { border-bottom: 0; }
.stephead {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 14px 9px 11px;
  cursor: pointer;
  border-left: 3px solid transparent;
}
.stephead:hover { background: var(--panel2); }

/* The status rail is a TICK, not a stripe.
 *
 * As a full-height border it butted against the next sibling's, and four
 * passed steps in a row read as one continuous green bar — which the eye then
 * took for a grouping rail, in exact competition with the depth rail beside
 * it. Inset top and bottom, each row owns its own mark, and the only
 * continuous vertical lines left on the page are the ones that mean
 * containment. */
.stephead { position: relative; }
.stephead::before {
  content: "";
  position: absolute;
  left: -3px;
  top: 6px;
  bottom: 6px;
  width: 3px;
  background: transparent;
}
.step.passed  > .stephead::before { background: var(--green); }
.step.failed  > .stephead::before { background: var(--red); }
.step.running > .stephead::before { background: var(--yellow); }
.step.skipped > .stephead::before { background: var(--line); }

/* The rail tick's readable twin: same outcome as a glyph, so a row's status
   survives colorblindness and screen readers. */
.stmark { flex: none; width: 14px; text-align: center; }
.step.passed  > .stephead > .stmark { color: var(--green); }
.step.failed  > .stephead > .stmark { color: var(--red); }
.step.running > .stephead > .stmark { color: var(--yellow); }
.step.skipped > .stephead > .stmark { color: var(--faint); }

/* ---- depth ----
 *
 * A container step (get:, across:, in_parallel:, race:, try:, do:, ensemble:)
 * HOLDS the steps that ran inside it. The rail vocabulary is the one
 * .subtrace already uses for a sub-agent's turns: one hairline guide per
 * ancestor, indented to the kind column.
 *
 * Rails are deliberately NOT colored by depth. Color on this page is ANSI-16
 * status semantics, and a rotating hue per level would be a second color
 * language arguing with the first. The rail instead lights yellow along the
 * ACTIVE path — the branch holding something still running — which is the
 * question a reader actually has while a job is in flight. A failed branch is
 * left alone: the rollup counts already carry red up every ancestor, and
 * doing both is shouting. */
.substeps { margin-left: 22px; border-left: 1px solid color-mix(in srgb, var(--faint) 42%, transparent); }
.step.active > .substeps { border-left-color: color-mix(in srgb, var(--yellow) 55%, transparent); }
.step.container:not(.open) > .substeps { display: none; }

/* ---- rollup ----
 * A folded container still has to answer "where does this stand", because the
 * rows that would otherwise answer are folded away with it. */
.rollup {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--faint);
  display: inline-flex;
  gap: 7px;
  align-items: baseline;
  flex-wrap: wrap;
}
.rollup b { font-weight: 600; }
.rollup .r-pass { color: var(--green); }
.rollup .r-fail { color: var(--red); }
.rollup .r-run  { color: var(--yellow); }
.rollup .r-skip { color: var(--faint); }
.rollup .r-sep  { color: var(--faint); }

/* The rollup and the duration are one group. display:contents on a wide
   screen, so the row lays out exactly as it did before this existed; on a
   narrow one the group becomes the row's second line instead of being
   squeezed against a name it will always lose to. */
.headmeta { display: contents; }

/* A running step counts. The blinking ▍ says "alive"; it does not say "six
   minutes in", which is the difference between a page you can leave and a
   page you have to watch. */
.dur .live { color: var(--yellow); font-variant-numeric: tabular-nums; }

/* ---- keyboard ---- */
.step.sel > .stephead { background: var(--panel2); box-shadow: inset 0 0 0 1px var(--line); }
.keyhint {
  font-family: var(--sans);
  font-size: 11px;
  color: var(--faint);
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-bottom: 0;
  background: var(--panel);
}
.keyhint kbd {
  font-family: var(--mono);
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 0 4px;
}
/* A pointer has no keys to press, and the hint would be the first thing on
   the page for a reader who cannot act on it. */
@media (hover: none) { .keyhint { display: none; } }
.stephead .kind {
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  width: 74px;
  flex: none;
  color: var(--dim);
}
.step.skipped .stephead .kind { color: var(--faint); }
.stephead .name { font-weight: 600; }
.step.skipped .stephead .name { color: var(--dim); font-weight: 400; }
.stephead .note { color: var(--faint); }
/* Beats .stephead .note on specificity, which the bare .spendwarn rule does
   not — without this the "stopped early" badge renders in the same faint grey
   as the ordinary verdict note beside it, and the distinction it exists for
   never reaches the screen. */
.stephead .spendwarn { color: var(--yellow); }
.stephead .dur { margin-left: auto; color: var(--dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.stephead .chev { color: var(--faint); width: 12px; flex: none; }
.chev-icon::before { content: "▸"; }
.step.open > .stephead .chev-icon::before { content: "▾"; }
.stepbody { display: none; padding: 4px 14px 14px 88px; }
.step.open > .stepbody { display: block; }
.stepbody.flush { padding-left: 14px; }

.log {
  background: var(--code-bg);
  border: 1px solid var(--line-soft);
  padding: 10px 12px;
  overflow-x: auto;
  color: var(--dim);
  font-size: 12px;
  line-height: 1.6;
  margin: 8px 0 0;
  white-space: pre-wrap;
}
.log .err { color: var(--red); }

.turn { display: flex; gap: 10px; padding: 6px 0; border-bottom: 1px dashed var(--line-soft); }
.turn:last-of-type { border-bottom: 0; }
.turn .who {
  flex: none;
  width: 74px;
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding-top: 2px;
}
.turn.model .who { color: var(--magenta); }
.turn.tool .who { color: var(--cyan); }
.turn.system .who { color: var(--yellow); }
.turn.user .who { color: var(--blue); }
.turn .what { color: var(--dim); min-width: 0; flex: 1; overflow-wrap: anywhere; }
/* The tool being called is the row's subject; everything else on the row is
   about it. */
.turn .what > code { color: var(--fg); font-weight: 600; margin-right: 8px; }
.turn .what .say { white-space: pre-wrap; }
/* What the model said is content, not annotation — the only turn text a
   reader is here to read. */
.turn.model .what .say { color: var(--fg); }
.turn.system .what .say, .turn.user .what .say { color: var(--fg); }
.turn.nested { opacity: 0.85; }
.turn.nested .who::before { content: "└ "; color: var(--faint); }

.subtrace { margin: 4px 0 4px 84px; padding: 6px 12px; border-left: 1px solid var(--line); }

/* ---- JSON, wherever it appears ----
 *
 * One vocabulary for every payload on the site: a tool call's arguments, a
 * tool result, a node's content map, a fenced ```json block in an agent's
 * answer. The token colors are the same ANSI-16 semantics the rest of the UI
 * runs on and the same ones the "steps" chroma style hands fenced code
 * (docs.go) — keys blue because they are structure, strings green, numbers
 * yellow, and punctuation dim so the shape recedes behind the values.
 *
 * The values used to be --faint, which is 2.5:1 on this panel. Reading a
 * trajectory was guesswork; every class below clears 5:1.
 */
.j-key  { color: var(--blue); }
.j-str  { color: var(--green); }
.j-num  { color: var(--yellow); }
.j-lit  { color: var(--magenta); }
.j-punc { color: var(--dim); }
/* A document that arrived escaped inside a string, shown as the document it
   is. Foreground weight because it is the thing the row was opened for. */
.j-doc  { color: var(--fg); }

/* Inline: small enough to stay on the row it belongs to. */
.jsonline { overflow-wrap: anywhere; }

/* Folded: bulky enough that leaving it open would bury the conversation
   around it. A <details>, so it works with scripting off and the live stream
   gets the same element the server renders. */
/* display:inline, deliberately, on an element whose default is block: the
   summary then sits on the row it annotates, while the <pre> it reveals still
   lays out as a block — starting at the data column rather than indented to
   wherever the summary happened to end, and free to use the full width. */
.jsonbox { display: inline; }
.jsonbox > summary {
  font-family: var(--sans);
  font-size: 11px;
  color: var(--dim);
  cursor: pointer;
  list-style: none;
  display: inline;
  padding: 1px 0;
}
.jsonbox > summary::-webkit-details-marker { display: none; }
/* The same chevron a step head uses: one disclosure vocabulary on the page. */
.jsonbox > summary::before { content: "▸"; font-family: var(--mono); color: var(--faint); margin-right: 5px; }
.jsonbox[open] > summary::before { content: "▾"; }
.jsonbox > summary:hover { color: var(--fg); }
.jsonbox > summary:hover::before { color: var(--dim); }

pre.json {
  background: var(--code-bg);
  border: 1px solid var(--line-soft);
  border-radius: 3px;
  padding: 10px 12px;
  margin: 6px 0 0;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.6;
  color: var(--dim);
  tab-size: 2;
}
/* A fenced block inside an answer carries its language, top-right, out of the
   way of the first line of code. The label sits OUTSIDE the <pre>: these
   blocks are patches and configs a reader copies, and absolute positioning
   removes a span from the flow but not from the selection. */
.codeblock { position: relative; margin: 0 0 10px; }
pre.json.code { padding-top: 12px; margin: 0; }
.codelang {
  position: absolute;
  top: 4px;
  right: 8px;
  font-family: var(--sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* --dim, not --faint: at 9.5px this is small text, and --faint is 2.8:1 on
     this ground. */
  color: var(--dim);
}

/* A step's own output is a <pre> now that it may be highlighted, so it needs
   the margin a <div> got for free. */
pre.log { margin: 8px 0 0; font-family: var(--mono); }


/* The step's answer, as a row: same gutter label and same data column as the
   conversation above it, separated by a rule because it is the conclusion of
   that conversation rather than another turn in it. */
.turn.answer { margin-top: 10px; padding-top: 12px; border-top: 1px solid var(--line); border-bottom: 0; }
.turn.answer .who { color: var(--fg); }
.response { color: var(--fg); min-width: 0; flex: 1; }
/* .prose is the same body mid-conversation, where the model's running
   commentary is an annotation rather than the conclusion. */
.response .say, .prose .say { white-space: pre-wrap; margin: 0 0 10px; overflow-wrap: anywhere; }
.turn.model .prose, .turn.system .prose, .turn.user .prose { color: var(--fg); min-width: 0; }
.response > :last-child, .prose > :last-child { margin-bottom: 0; }
/* Qualified past pre.json.code, which would otherwise keep its own bottom
   margin on the answers most likely to end in a code block. */
.response > .codeblock:last-child, .prose > .codeblock:last-child { margin-bottom: 0; }
.agentmeta { color: var(--faint); font-size: 12px; margin-top: 8px; }

/* ---- rendered agent prose ----
 *
 * Models write markdown, and prose.go renders it (see that file for what the
 * renderer refuses to do with model-authored text). Everything here is about
 * keeping a document subordinate to the page it is quoted into: an agent's
 * heading levels are its own business, but on this page they are all
 * annotations of one step, so they are set as labels rather than as a second
 * outline competing with the run's. */
.md { color: var(--fg); min-width: 0; }
.md > :first-child { margin-top: 0; }
.md > :last-child { margin-bottom: 0; }
.md h1, .md h2 {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 18px 0 6px;
}
.md h3, .md h4, .md h5, .md h6 {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 700;
  color: var(--fg);
  margin: 16px 0 5px;
}
.md p { margin: 0 0 10px; overflow-wrap: anywhere; }
.md strong { color: var(--fg); font-weight: 700; }
.md ul, .md ol { margin: 0 0 10px; padding-left: 20px; }
.md li { margin: 3px 0; }
.md li::marker { color: var(--faint); }
.md li > p { margin: 0; }
/* Inline code is a token in a sentence, not a block: cyan, so a file name or
   a symbol reads as data the way every other identifier on the page does. */
.md :not(pre) > code {
  background: var(--code-bg);
  border: 1px solid var(--line-soft);
  border-radius: 2px;
  padding: 0 4px;
  font-size: 12px;
  color: var(--cyan);
  overflow-wrap: anywhere;
}
.md blockquote {
  margin: 0 0 10px;
  padding-left: 12px;
  border-left: 2px solid var(--line);
  color: var(--dim);
}
.md hr { border: 0; border-top: 1px solid var(--line); margin: 14px 0; }
/* A model-authored table can be any width; it scrolls inside its own box
   rather than pushing the page sideways. */
.md table { border-collapse: collapse; margin: 0 0 10px; font-size: 12px; display: block; overflow-x: auto; }
.md th, .md td { border: 1px solid var(--line); padding: 4px 9px; text-align: left; }
.md th {
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--dim);
  font-weight: 600;
}
.md a { color: var(--blue); }
.md del { color: var(--faint); }

.cursor { display: inline-block; width: 7px; background: var(--yellow); color: transparent; animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .cursor { animation: none; } }

/* ---- failure triage ---- */
.errblock {
  border: 1px solid #4a2c29;
  background: #191110;
  color: var(--red);
  padding: 10px 14px;
  font-size: 12.5px;
  margin: 0 0 18px;
  white-space: pre-wrap;
}
.errblock .lbl { color: var(--dim); }
.diffnote { color: var(--dim); font-size: 12px; margin: -8px 0 18px; }
.diffnote .chg { color: var(--yellow); }
.diffnote::before { content: "Δ "; color: var(--yellow); }

.callout {
  border: 1px solid var(--line);
  border-left: 3px solid var(--yellow);
  background: var(--panel);
  padding: 10px 14px;
  color: var(--dim);
  font-size: 12px;
  margin-top: 22px;
}
.callout b { color: var(--fg); font-weight: 600; }

/* ---- node detail ---- */
/* The node page's payloads are the shared JSON block at reading size: this
   page IS the payload, where a transcript row only quotes one. Selector
   qualified past pre.json deliberately — these elements carry BOTH classes,
   and at equal specificity the shared block would win on every property. */
pre.json.contentmap { border-color: var(--line); padding: 12px 16px; margin: 0; font-size: 12.5px; line-height: 1.7; }
.chain { color: var(--dim); font-size: 12.5px; }
.chain .rail { color: var(--faint); }

/* ---- sparkline ---- */
.spark { vertical-align: -2px; margin-left: 10px; }
.spark rect { fill: #4d7040; }
.spark rect.bad { fill: #8a4038; }

/* ---- approvals ---- */
.approval { border: 1px solid var(--line); background: var(--panel); padding: 14px; margin-bottom: 10px; }
.approval .msg { font-weight: 600; margin: 2px 0; }
.approval .meta { color: var(--faint); font-size: 12px; }
.approval.decided { color: var(--dim); }
.approval .stamp { font-weight: 600; }
.decide { display: flex; gap: 8px; margin-top: 12px; align-items: center; flex-wrap: wrap; }
.decide input[type="text"] {
  flex: 1;
  min-width: 120px;
  font: inherit;
  font-size: 12px;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 4px 10px;
}
.decide input[type="text"]::placeholder { color: var(--faint); }

/* ---- jump palette ---- */
.palette-backdrop { position: fixed; inset: 0; background: rgba(8, 9, 8, 0.72); display: none; z-index: 50; }
.palette-backdrop.open { display: block; }
.palette {
  position: fixed;
  top: 14vh;
  left: 50%;
  transform: translateX(-50%);
  width: min(560px, 92vw);
  background: var(--panel);
  border: 1px solid var(--line);
  z-index: 51;
  display: none;
}
.palette.open { display: block; }
.palette input {
  width: 100%;
  font: inherit;
  font-size: 14px;
  color: var(--fg);
  background: var(--bg);
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 12px 14px;
  outline: none;
}
.palette input::placeholder { color: var(--faint); }
.palette ul { list-style: none; margin: 0; padding: 6px 0; max-height: 300px; overflow-y: auto; }
.palette li { padding: 7px 14px; cursor: pointer; display: flex; gap: 12px; align-items: baseline; }
.palette li:hover, .palette li.sel { background: var(--panel2); }
.palette li .kind {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  width: 62px;
  flex: none;
}
.palette li .hint { margin-left: auto; color: var(--faint); font-size: 12px; }

/* A tree costs horizontal space and a phone has none, so the indent shrinks
 * to a thumbnail's width and the kind label gives up its fixed column — the
 * depth rail is already doing the alignment that column was doing. Nothing is
 * hidden: a step at depth three on a phone shows the same name, rollup,
 * elapsed and hash it shows on a desktop, on two lines instead of one. */
@media (max-width: 640px) {
  .stepbody { padding-left: 14px; }
  .subtrace { margin-left: 12px; }
  .substeps { margin-left: 9px; }

  .stephead { flex-wrap: wrap; gap: 6px 9px; padding: 8px 10px 8px 9px; }
  .stephead .kind { width: auto; }
  /* A cell name like reviewer [dim=assertion-fixture-fidelity] has no spaces
     to break at, so it needs permission to break anywhere — otherwise it sets
     the row's minimum width and pushes the whole page sideways. */
  .stephead .name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
  .stephead .note { flex-basis: 100%; margin-left: 18px; }

  .headmeta {
    display: flex;
    flex-basis: 100%;
    align-items: baseline;
    gap: 10px;
    margin-left: 18px;
    min-width: 0;
  }
  .headmeta .dur { margin-left: auto; white-space: normal; text-align: right; }

  .turn { flex-wrap: wrap; gap: 2px 10px; }
  .turn .who { width: auto; }
}

/* A step is addressable: the anchor stays out of the way until the row is
 * hovered or focused, so "look at this step" is a pastable URL rather than
 * a description of where to click. */
.stephead .anchor {
  color: var(--faint);
  opacity: 0;
  text-decoration: none;
  font-weight: 400;
}
.stephead:hover .anchor,
.stephead .anchor:focus-visible { opacity: 1; }
.stephead .anchor:hover { color: var(--fg); }
.step { scroll-margin-top: 3.2rem; }
.step:target > .stephead { background: var(--panel2); box-shadow: inset 0 0 0 1px var(--line); }

/* The trigger-to-run waiting room. Deliberately sparse: it exists only for
 * the seconds between a click and a run id, and anything more would be
 * furniture the reader never gets to use. */
.waiting {
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 18px 20px;
}
.waitline { margin: 0 0 6px; color: var(--fg); }
.waiting p:last-child { margin-bottom: 0; }

/* A step's own output, as it came out. Slightly brighter than the log block
 * around it: this is the thing a reader opened the step to see, not the
 * annotation about it. */
.log.output { color: var(--fg); }

/* Spend: what a run's agent steps cost.
   Sits above the transcript because "what did this cost" is a question asked
   of the whole run, not of one step -- and because the cache percentage is
   the only place prompt caching reports whether it did anything. */
.spend { margin: 1rem 0; border: 1px solid var(--line); border-radius: 4px; }
.spendhead { display: flex; flex-wrap: wrap; gap: .75rem; align-items: baseline;
             padding: .5rem .75rem; border-bottom: 1px solid var(--line); }
.spendtotal { font-weight: 600; }
.spendmeta { color: var(--dim); font-size: .9em; }
/* Marked, not hidden: an absent price is a fact about the provider, and
   rendering it as $0.00 would say the run was free. */
.unpriced { font-style: italic; }
.spendwarn { color: var(--yellow); font-size: .9em; }
/* Its own scroll container: five nowrap columns are wider than a phone, and a
   table that cannot scroll drags the whole document sideways instead. */
.spendscroll { overflow-x: auto; }
.spendtable { width: 100%; min-width: 480px; border-collapse: collapse; font-size: .9em; }
.spendtable th { text-align: left; color: var(--dim); font-weight: 500; padding: .35rem .75rem; }
.spendtable td { padding: .35rem .75rem; border-top: 1px solid var(--line); }
.spendtable .num { text-align: right; font-variant-numeric: tabular-nums; }
.spendtable .model { color: var(--dim); }
/* The machines panel shares the spend panel's furniture on purpose: both
   answer a question about the whole run rather than one step, and inventing a
   second visual language for the second one would only make them look
   unrelated. It needs a wider floor -- seven columns, and an aws:// address
   plus an image is long. */
.placement .spendtable { min-width: 720px; }

/* /docs — the embedded documentation, rendered server-side. Prose pages in
 * a transcript UI: same ground, same rules, sans for the reading voice.
 * Code blocks carry the app's own palette via the "steps" chroma style
 * (internal/web/docs.go), never a stock theme. */
.docsnav { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; margin: 10px 0 8px; font-family: var(--sans); font-size: 12px; }
.docsnav a, .docstoc a { color: var(--dim); }
.docsnav a:hover, .docstoc a:hover { color: var(--fg); }
.docsnav a[aria-current="page"] { color: var(--green); }
.docsgroup { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.docsgrouptitle { color: var(--faint); text-transform: uppercase; letter-spacing: .06em; font-size: 10px; }
.docstoc { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 0 0 18px; padding: 6px 10px; border: 1px solid var(--line-soft); border-radius: 4px; font-family: var(--sans); font-size: 12px; }
.docs { max-width: 880px; font-family: var(--sans); font-size: 14px; line-height: 1.6; }
/* Prose keeps a readable measure; code and tables may use the full column. */
.docs p, .docs ul, .docs ol, .docs blockquote { max-width: 72ch; }
.docs h1, .docs h2, .docs h3, .docs h4 { font-family: var(--mono); font-weight: 600; line-height: 1.25; scroll-margin-top: 3.2rem; }
.docs h1 { font-size: 1.4em; }
.docs h2 { font-size: 1.15em; margin-top: 1.8em; border-bottom: 1px solid var(--line-soft); padding-bottom: .25em; }
.docs h3 { font-size: 1em; margin-top: 1.4em; }
.docs h1 code, .docs h2 code, .docs h3 code, .docs h4 code { overflow-wrap: anywhere; }
.docs pre { border: 1px solid var(--line); border-radius: 4px; padding: 10px 12px; overflow-x: auto; font-size: .92em; }
.docs code { font-family: var(--mono); font-size: .95em; }
.docs :not(pre) > code { background: var(--panel2); padding: 1px 4px; border-radius: 3px; overflow-wrap: anywhere; }
/* display:block turns the table into its own scroll container, so a wide
 * conformance matrix pans inside the column instead of dragging the whole
 * document sideways on a phone. */
.docs table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; font-size: .92em; }
.docs th, .docs td { border: 1px solid var(--line); padding: 5px 9px; text-align: left; vertical-align: top; }
.docs th { color: var(--dim); font-weight: 500; }
.docs blockquote { border-left: 2px solid var(--line); margin-left: 0; padding-left: 14px; color: var(--dim); }
.docs img { max-width: 100%; }
