/* App layout on top of the Chalmers DS tokens (ds/tokens.css) and components (ds/components/bundle.css). */
:root {
  /* Sequential data ramp of the 3D view (same stops as viewer.js): fixed across themes, as data colours are. */
  --ramp: linear-gradient(90deg, #efecfb, #c9c1f3, var(--c-purple-light), var(--c-purple), var(--c-purple-dark), #2a1a73);
  --viewer-bg: var(--bg-alt);
  --bubble-user: var(--bg-alt);
  --gutter: var(--sp-5);
}
@media (max-width: 900px) { :root { --gutter: 16px; } }

/* DUCTILE identities, from the DS complement palette: User = lime, Agent (the LLM) = orange, Tool =
   yellow. They are fills, never text colours; text on a fill is --on-entity (#222: 9.5:1 on lime, 5.3:1
   on orange, 11:1 on yellow), in both themes. The -line variants are for thin marks next to text (the
   message edges): 3:1 or more against the page, darkened in the light theme (lime 4.1:1, orange 4.5:1,
   yellow 4.2:1 on white), the plain colours in the dark one (9.5, 5.3, 11:1 on #222). The diagram's
   neutrals follow the paper's figure: beige panels, white boxes, #222 ink, #5a5a5a secondary text and
   purple-dark titles; in the dark theme they map to the dark surfaces and text tokens. */
:root {
  --user: var(--c-lime);
  --agent: var(--c-orange);
  --tool: var(--c-yellow);
  --user-line: color-mix(in srgb, var(--c-lime) 55%, var(--c-black));
  --agent-line: color-mix(in srgb, var(--c-orange) 75%, var(--c-black));
  --tool-line: color-mix(in srgb, var(--c-yellow) 50%, var(--c-black));
  --on-entity: var(--c-black);
  --on-entity-2: #5a5a5a; /* secondary text on white boxes inside the yellow panel: 6.9:1 */
  --arch-panel: var(--c-beige);
  --arch-box: var(--c-white);
  --arch-row: var(--c-beige);
  --arch-ink: var(--c-black);
  --arch-ink-2: #5a5a5a;
  --arch-title: var(--c-purple-dark);
  --hairline: #e3e1db;
}
[data-theme="dark"] {
  --user-line: var(--c-lime);
  --agent-line: var(--c-orange);
  --tool-line: var(--c-yellow);
  --arch-panel: #3a3a3a; /* visible on the dark page (#222) and on dark cards (#2c2c2c) */
  --arch-box: var(--c-black);
  --arch-row: #333333;
  --arch-ink: var(--fg);
  --arch-ink-2: var(--fg-muted);
  --arch-title: var(--c-purple-light);
  --hairline: #3a3a3a;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--fg); font-family: var(--font-sans);
  display: flex; flex-direction: column; min-height: 100vh;
}
[hidden] { display: none !important; }

.topbar {
  display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) var(--gutter);
  border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.brand { display: flex; flex-direction: column; line-height: 1.2; margin-right: auto; }
.brand strong { font-size: 1.15rem; }
.agent-pick { display: inline-flex; align-items: center; gap: var(--sp-2); }
#llm { max-width: 22rem; text-overflow: ellipsis; }
.topbar-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

/* Usage meter next to the brand: Time, Budget and Runs left as gauge cells in one outlined strip, each a
   caption, the value (tabular figures: no jiggle as it ticks) and a 3px fuel bar of the fraction left.
   Amber below 20 % left, red at zero. Amber text is darkened for the light theme (5.6:1 on white), the
   plain yellow in the dark one; red lightened there (4.6:1 on #222). The details open under it. */
:root {
  --usage-warn: color-mix(in srgb, var(--c-orange) 60%, var(--c-black));
  --usage-danger: var(--danger);
}
[data-theme="dark"] {
  --usage-warn: var(--warning);
  --usage-danger: color-mix(in srgb, var(--c-red) 65%, var(--c-white));
}
.brand:has(+ .usage:not([hidden])) { margin-right: 0; }
.usage { position: relative; margin-right: auto; }
.usage-meter { display: flex; align-items: stretch; margin: 0; padding: 0; border: 1px solid var(--border-strong);
  border-radius: 0; background: var(--bg); color: var(--fg); font: inherit; text-align: left; cursor: pointer;
  transition: border-color var(--motion-quick) var(--ease-brand); }
.usage-meter:hover, .usage-meter[aria-expanded="true"] { border-color: var(--fg-subtle); }
.usage-meter:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.usage-cell { display: flex; flex-direction: column; justify-content: center; gap: 2px; min-width: 4.25rem; padding: 4px 10px 6px; }
.usage-cell + .usage-cell { border-left: 1px solid var(--border); }
.usage-cap { display: flex; align-items: center; gap: 4px; font-size: 11px; line-height: 1.2; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--fg-muted); }
.usage-cap svg { width: 11px; height: 11px; flex: none; }
.usage-val { font-size: 14px; line-height: 1.25; font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; white-space: nowrap; }
.usage-short { display: none; } /* phone wording, see the 520px query */
.usage-val small { font-size: 12px; font-weight: var(--fw-regular); color: var(--fg-subtle); }
.usage-bar { display: block; height: 3px; background: var(--track-bg); }
.usage-bar i { display: block; height: 100%; width: 0; background: var(--accent); transition: width var(--motion-quick) var(--ease-brand); }
.usage-cell[data-level="low"] .usage-val { color: var(--usage-warn); }
.usage-cell[data-level="low"] .usage-bar i { background: var(--warning); }
.usage-cell[data-level="out"] .usage-val { color: var(--usage-danger); }
.usage-cell[data-level="out"] .usage-bar { background: color-mix(in srgb, var(--danger) 45%, var(--track-bg)); }
@media (prefers-reduced-motion: reduce) { .usage-meter, .usage-bar i { transition: none; } }
.usage-pop { position: absolute; top: calc(100% + 6px); left: 0; z-index: 40; width: 320px; max-width: calc(100vw - 2 * var(--gutter));
  padding: var(--sp-4); background: var(--surface-card); box-shadow: inset 0 0 0 1px var(--border), var(--shadow-md); }
.usage-pop dl { display: grid; grid-template-columns: auto 1fr; gap: 6px var(--sp-4); margin: 0; font-size: var(--fs-small); }
.usage-pop dt { color: var(--fg-muted); }
.usage-pop dd { margin: 0; font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
.usage-pop p { margin: var(--sp-3) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.select-sm { height: 32px; padding-top: 0; padding-bottom: 0; font-size: var(--fs-small); width: auto; }
.ic { width: 18px; height: 18px; flex: none; }
.theme-toggle .ic-sun { display: none; }
[data-theme="dark"] .theme-toggle .ic-sun { display: block; }
[data-theme="dark"] .theme-toggle .ic-moon { display: none; }
.login-eyebrow { color: var(--accent); }

.login { flex: 1; display: grid; place-items: center; padding: var(--sp-6) 16px; }
.login-card { max-width: 820px; width: 100%; display: grid; gap: var(--sp-5); }
.login-head { display: grid; gap: var(--sp-3); }
.login-head .card-body { margin-bottom: 0; }
/* The paper the demo implements: the headline's source, so a prominent link with its byline. */
.paper { margin: 0; display: grid; gap: 2px; max-width: 62ch; }
.paper-link { font-size: 1.0625rem; font-weight: var(--fw-medium); line-height: 1.35; text-underline-offset: 4px; }
.login-intro p { margin: 0 0 var(--sp-2); max-width: 70ch; }
.login-intro p:last-child { margin-bottom: 0; }
.login-arch { margin: 0; }
.login-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }  /* one column: beta, then the form */
.beta-note { margin: 0; padding: var(--sp-2) 0 var(--sp-2) var(--sp-3); border-left: 2px solid var(--accent); }
.beta-note b { font-weight: var(--fw-medium); }
/* Access code: a password field with a show/hide button of the same height. */
.code-row { display: flex; gap: var(--sp-2); align-items: stretch; }
.code-row .input { flex: 1; min-width: 0; }
.code-row .code-toggle { height: auto; width: 2.5rem; }
.code-toggle .ic-eye-off { display: none; }
.code-toggle[aria-pressed="true"] .ic-eye { display: none; }
.code-toggle[aria-pressed="true"] .ic-eye-off { display: block; }
.consent { display: grid; gap: var(--sp-2); }
/* DS check boxes (bundle.css, Forms): .small keeps the app's small label size (.check sets its own); a
   label that wraps keeps the box on its first line; the DS has no disabled look, so add one. */
.check.small { font-size: var(--fs-small); }
.check-wrap { align-items: flex-start; line-height: 1.4; }
.check:has(input:disabled) { color: var(--fg-subtle); cursor: not-allowed; }
.check input:disabled { opacity: 0.5; pointer-events: none; }
.consent-more summary { cursor: pointer; color: var(--fg-muted); }
.consent-more ul { margin: var(--sp-2) 0 0; padding-left: 1.1em; color: var(--fg-muted); display: grid; gap: 2px; }
.privacy { margin: var(--sp-4) 0 0; }

/* The DUCTILE architecture diagram (inline SVG after the paper's figure; colours from tokens). */
.arch-fig { margin: 0; container-type: inline-size; }
.arch { width: 100%; height: auto; display: block; font-family: var(--font-sans); }
.arch-wide { max-width: 728px; }
.arch-narrow { max-width: 400px; }
@container (max-width: 559px) { .arch-wide { display: none; } }
@container (min-width: 560px) { .arch-narrow { display: none; } }
.arch text { font-size: 12px; font-weight: var(--fw-medium); fill: var(--arch-ink); }
.arch text.mid { text-anchor: middle; }
.arch text.end { text-anchor: end; }
.arch .t12 { font-size: 12px; }
.arch .t13 { font-size: 13px; }
.arch .t14 { font-size: 14px; }
.arch .t16 { font-size: 16px; }
.arch text.title { font-size: 13px; font-weight: 700; letter-spacing: 1.04px; fill: var(--arch-title); }
.arch text.title.t12 { font-size: 12px; }
.arch text.title.on-tool { fill: var(--c-purple-dark); } /* on yellow in both themes: 6.1:1 */
.arch text.ink-2 { fill: var(--arch-ink-2); font-weight: 400; }
.arch text.on-fill, .arch text.ink.t14 { fill: var(--on-entity); }
.arch text.on-fill-2 { fill: var(--on-entity-2); font-weight: 400; }
.arch .n-user { fill: var(--user); }
.arch .n-agent { fill: var(--agent); }
.arch .panel-tool { fill: var(--tool); }
.arch .tool-row { fill: var(--c-white); }
.arch .panel-app { fill: var(--arch-panel); }
.arch .box { fill: var(--arch-box); }
.arch .row { fill: var(--arch-row); }
.arch .flow { fill: none; stroke: var(--arch-ink); stroke-width: 1.5; }
.arch .head { fill: var(--arch-ink); }

/* Welcome: how it works. */
.about { margin-top: var(--sp-6); border-top: 1px solid var(--border); padding-top: var(--sp-4); }
.about-title { font-size: var(--fs-body); font-weight: var(--fw-medium); margin: 0 0 var(--sp-3); }
.about-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
.about-steps { margin: 0; padding-left: 1.2em; display: grid; gap: var(--sp-2); }
.about-steps b { font-weight: var(--fw-medium); }
.limits { margin: var(--sp-3) 0 0; }

/* The strip: where the session's time goes. A card pinned above the chat: the phase (eyebrow), what
   is happening, one square tile per turn (coloured by entity; the last one is live), the share-of-time
   bar, the legend and the time per entity. */
.turnstrip {
  --tile: 16px;
  margin: var(--sp-3) var(--gutter) 0; padding: var(--sp-3) var(--sp-4); background: var(--surface-card);
  border: 1px solid var(--border); display: grid; gap: var(--sp-2); min-width: 0;
}
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* The DUCTILE diagram, live (after the open-trs turn animations): the box whose turn it is gets the
   purple outline; requests, tool calls, results and the answer travel the arrows as squares in their
   actor's colour; the context rows count what they hold; the tool box shows the call while it runs. */
.strip-arch .arch { max-width: 560px; margin: 0 auto; }
.arch-live [data-k] { transition: stroke-width .2s; }
.arch-live [data-k].on { stroke: var(--arch-title); stroke-width: 3; }
.arch-live [data-k].flash { stroke: var(--arch-title); stroke-width: 3; }
.arch .count { font-size: 12px; font-weight: 700; text-anchor: end; fill: var(--arch-ink); }
.arch-live .call { font-family: var(--font-mono, ui-monospace, monospace); font-size: 11px; font-weight: 400; fill: var(--c-purple-dark); }
.arch-live .gear { fill: none; stroke: var(--c-black); stroke-width: 3.5; stroke-dasharray: 2.6 2.1; transform-box: fill-box; transform-origin: center; animation: gear 2.4s linear infinite; }
.arch-live .gear-hub { fill: var(--c-black); }
.arch-live .bar { fill: var(--c-purple-dark); }
.arch-live .bar-run { animation: bar-run 1.4s ease-in-out infinite; }
@keyframes gear { to { transform: rotate(360deg); } }
@keyframes bar-run { 0% { transform: translateX(0); } 50% { transform: translateX(150px); } 100% { transform: translateX(0); } }
.arch-live .token { stroke: var(--c-black); stroke-width: 1.5; }
@media (prefers-reduced-motion: reduce) { .arch-live .gear, .arch-live .bar-run { animation: none; } }
.strip-phase { font-size: var(--fs-micro); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--accent); }
.strip-heading { margin: 0; font-weight: var(--fw-medium); line-height: 1.3; }
.strip-row { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
/* Tiles wrap to new rows; past three rows the list scrolls, newest at the bottom. */
.tiles { list-style: none; margin: 0; padding: 2px; display: flex; flex-wrap: wrap; align-content: flex-start; gap: 4px;
  max-height: calc(3 * var(--tile) + 2 * 4px + 4px); overflow-y: auto; min-width: 0; flex: 1; }
.strip-toggle { display: none; flex: none; }
/* Folds the diagram away (the default) or brings it up above the tiles. */
.strip-fold { flex: none; align-self: flex-start; display: inline-grid; place-items: center; width: 28px; height: 28px; padding: 0;
  border: 1px solid var(--border); background: transparent; color: var(--fg); cursor: pointer; }
.strip-fold:hover { background: var(--bg-alt); }
.strip-fold:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.strip-fold svg { transition: transform .2s; }
.strip-fold[aria-expanded="true"] svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .strip-fold svg { transition: none; } }
/* The whole session at a glance: one bar, each entity's share of the time. */
.strip-sum { display: flex; height: 8px; background: var(--bg-alt); overflow: hidden; }
.strip-sum i { display: block; height: 100%; width: 0; transition: width .4s var(--ease-brand, ease); }
.strip-sum .sum-user { background: var(--user); }
.strip-sum .sum-agent { background: var(--agent); }
.strip-sum .sum-tool { background: var(--tool); }
@media (prefers-reduced-motion: reduce) { .strip-sum i { transition: none; } }
.tiles li { display: flex; flex: none; }
.tile { width: var(--tile); height: var(--tile); padding: 0; border: 0; border-radius: 0; cursor: pointer; display: block; background: var(--bg-alt); }
.tile-user { background: var(--user); }
.tile-agent { background: var(--agent); }
.tile-tool { background: var(--tool); }
.tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tile.live { animation: tile-pulse 1.6s ease-in-out infinite; }
@keyframes tile-pulse { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) {
  .tile.live { animation: none; box-shadow: inset 0 0 0 2px var(--on-entity); }
}
.strip-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-4); flex-wrap: wrap; }
.strip-legend { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--sp-4); flex-wrap: wrap; font-size: var(--fs-small); font-weight: var(--fw-medium); }
.strip-legend li { display: inline-flex; align-items: center; gap: 6px; }
.strip-legend b { color: var(--fg-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.strip-scale { font-size: var(--fs-micro); color: var(--fg-muted); }
.key { display: inline-block; width: 12px; height: 12px; }
.key-user { background: var(--user); }
.key-agent { background: var(--agent); }
.key-tool { background: var(--tool); }
.strip-tip { white-space: normal; max-width: min(320px, calc(100vw - 16px)); }
@media (max-width: 600px) {
  /* Phones: a thin row of tiles; "Details" opens the phase, the share bar, the legend and the totals. */
  .turnstrip { --tile: 10px; padding: var(--sp-2) var(--sp-3); gap: var(--sp-1); }
  .tiles { gap: 3px; max-height: calc(2 * var(--tile) + 3px + 4px); }
  .strip-toggle { display: inline-flex; }
  .turnstrip:not(.open) .strip-sum, .turnstrip:not(.open) .strip-foot { display: none; }
  .strip-heading { font-size: var(--fs-small); }
}

/* Message identities: User (the user's messages), Agent (reasoning and text), Tool (tool cards). */
.ent-user::before, .ent-agent::before, .ent-tool > summary::before {
  display: block; font-family: var(--font-sans); font-size: var(--fs-micro); color: var(--fg-muted);
  letter-spacing: .04em; text-transform: uppercase; white-space: normal;
}
.msg.user.ent-user { border-left: 3px solid var(--user-line); }
.msg.user.ent-user::before { content: "User"; margin-bottom: 2px; }
.seg.ent-agent { border-left: 3px solid var(--agent-line); padding-left: var(--sp-3); margin: 4px 0; }
.seg.ent-agent::before { content: "Agent"; margin-bottom: 2px; }
.tool.ent-tool { border-left: 3px solid var(--tool-line); }
.tool.ent-tool > summary::before { content: "Tool"; display: inline; margin-right: 2px; }
.flash { animation: flash 1.6s ease-out; }
@keyframes flash { 0%, 40% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 45%, transparent); } 100% { box-shadow: 0 0 0 3px transparent; } }
@media (prefers-reduced-motion: reduce) { .flash { animation: none; outline: 2px solid var(--accent); outline-offset: 2px; } }

.app {
  --chat-w: 45%;
  flex: 1; display: grid; grid-template-columns: minmax(340px, var(--chat-w)) 8px minmax(320px, 1fr); min-height: 0;
  height: calc(100vh - 110px);
}
/* Drag handle between chat and workspace (keyboard: arrows, Home/End; double-click resets). */
.splitter { cursor: col-resize; background: var(--border); background-clip: content-box; padding: 0 3px; touch-action: none; }
.splitter:hover, .splitter.dragging, .splitter:focus-visible { background-color: var(--accent); padding: 0 2px; outline: none; }
.app.resizing { user-select: none; cursor: col-resize; }
.app.resizing iframe, .app.resizing canvas { pointer-events: none; }
.chat { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.messages { flex: 1; overflow-y: auto; padding: var(--sp-5) var(--gutter); display: flex; flex-direction: column; gap: var(--sp-4); }
.welcome .lead { margin-top: 0; }
/* Welcome cards: the two catalogue models with a sketch, and "describe my own problem". */
.cases { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-3); margin-top: var(--sp-3); }
.case {
  display: flex; flex-direction: column; gap: var(--sp-1); text-align: left; cursor: pointer;
  font: inherit; color: var(--fg); background: var(--surface-card); border: 1px solid var(--border);
  padding: var(--sp-3); transition: border-color .15s var(--ease-brand, ease);
}
.case:hover:not(:disabled), .case:focus-visible { border-color: var(--accent); }
.case:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.case:disabled { opacity: .5; cursor: default; }
.case-title { font-weight: var(--fw-medium); }
.case-text { font-size: var(--fs-small); }
.case-note { font-size: var(--fs-small); color: var(--fg-muted); }
.sketch { width: 100%; height: auto; aspect-ratio: 2 / 1; margin-bottom: var(--sp-2); background: var(--bg-alt); }
.sketch path, .sketch circle { fill: none; stroke: var(--fg); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.sketch .body { fill: color-mix(in srgb, var(--accent) 14%, transparent); }
.sketch .hole { fill: var(--bg-alt); }
.sketch .wall { stroke-width: 2.5; }
.sketch .hatch path { stroke: var(--fg-muted); stroke-width: 1; }
.sketch .load { stroke: var(--accent); stroke-width: 2; }
.sketch .dim { stroke: var(--fg-muted); stroke-width: 1; }
.sketch .lbl { fill: var(--fg); font: italic 18px var(--font-serif, Georgia, serif); }

.msg { max-width: 100%; line-height: var(--lh-body); }
.msg.user { align-self: flex-end; background: var(--bubble-user); padding: var(--sp-2) var(--sp-3); max-width: 85%; white-space: pre-wrap; }
.msg.assistant .md > :first-child { margin-top: 0; }
.msg.assistant .md > :last-child { margin-bottom: 0; }
.msg.assistant .md table { border-collapse: collapse; font-size: var(--fs-small); margin: var(--sp-2) 0; }
.msg.assistant .md th, .msg.assistant .md td { border-bottom: 1px solid var(--border); padding: 4px 8px; text-align: left; }
.msg.assistant .md code { font-family: var(--font-mono); font-size: 0.9em; }
.msg.assistant .md pre { background: var(--bg-alt); padding: var(--sp-2); overflow-x: auto; }
.msg .meta { font-size: var(--fs-micro); color: var(--fg-muted); margin-top: 4px; }
.msg .alert { margin: var(--sp-2) 0; padding: var(--sp-3); }
.msg .alert p { margin: 0; }
.msg .alert .nudge { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
.msg .jobref { margin: 4px 0; }
details.thinking { font-size: var(--fs-small); color: var(--fg-muted); margin-bottom: var(--sp-2); }
details.thinking summary { cursor: pointer; }
details.thinking div { white-space: pre-wrap; padding: 4px 0 0 12px; border-left: 2px solid var(--border); }
.tool {
  font-family: var(--font-mono); font-size: var(--fs-micro); border: 1px solid var(--border);
  padding: 4px 8px; margin: 4px 0; display: block; background: var(--surface-card);
}
.tool summary { cursor: pointer; display: flex; gap: 8px; align-items: center; min-width: 0; color: var(--fg); }
.tool summary .ic { width: 14px; height: 14px; color: var(--accent); }
.tool .res { display: inline-flex; gap: 6px; align-items: center; min-width: 0; overflow: hidden; }
.tool .res .muted { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tool.err { border-color: var(--danger); }
.tool pre { margin: 4px 0 0; white-space: pre-wrap; word-break: break-word; color: var(--fg-muted); }
.tool .io { margin-top: 6px; color: var(--fg-muted); text-transform: uppercase; letter-spacing: .04em; }
.tool pre.out { max-height: 320px; overflow: auto; }
/* status: a square accent dot (accents are never text or background colours) */
.dot { display: inline-block; width: 8px; height: 8px; flex: none; background: var(--fg-subtle); }
.dot.dot-success { background: var(--success); }
.dot.dot-danger { background: var(--danger); }
.dot.dot-warning { background: var(--warning); }
.typing::after {
  content: ""; display: block; width: 8px; height: 16px; margin-top: 4px; background: var(--accent);
  animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .typing::after { animation: none; opacity: 0.6; } }
/* Waiting for the model's first output: seconds so far (steady digits), and why it may take a while. */
.msg .waiting { margin-top: 0; font-size: var(--fs-small); font-variant-numeric: tabular-nums; }
.msg .waiting-why { margin-top: 2px; max-width: 60ch; font-size: var(--fs-micro); }

.composer { padding: var(--sp-3) var(--gutter); border-top: 1px solid var(--border); }
.composer-box { position: relative; }
.composer .textarea { display: block; width: 100%; resize: none; min-height: 52px; max-height: 40vh; padding-right: 52px; }
/* Send sits inside the input, bottom right; while a turn runs it becomes Stop. */
.send-btn {
  position: absolute; right: 8px; bottom: 8px; width: 34px; height: 34px; display: grid; place-items: center;
  border: 0; background: transparent; color: var(--fg); cursor: pointer; padding: 0;
}
.send-btn:hover:not(:disabled) { color: var(--accent); }
.send-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.send-btn:disabled { opacity: 0.4; cursor: default; }
.send-btn .ic { width: 20px; height: 20px; }
.send-btn .ic-stop { display: none; }
.send-btn.stop .ic-send { display: none; }
.send-btn.stop .ic-stop { display: block; width: 22px; height: 22px; }
/* Stop: the square itself is red (no button background). */
.send-btn.stop, .send-btn.stop:hover:not(:disabled) { color: var(--danger); }
.send-btn.stop:hover:not(:disabled) { color: color-mix(in srgb, var(--danger) 80%, var(--c-black)); }
.can-do { margin-top: 0; max-width: 60ch; }
.seat-msg { border-left: 3px solid var(--accent); padding: var(--sp-2) var(--sp-3); background: var(--bg-alt); }
.seat-msg .seat-line { margin: 0; font-size: var(--fs-small); font-weight: var(--fw-medium); }
.seat-msg .btn { margin-top: var(--sp-2); }
.msg .stopped { font-size: var(--fs-micro); color: var(--fg-muted); margin-top: 4px; }
.job header .state { margin-left: auto; }
/* Delete a run: a DS ghost icon button, muted until hovered, then red (it deletes). */
.job header .job-del { color: var(--fg-muted); align-self: center; }
.job header .job-del:hover, .job header .job-del:focus-visible { color: var(--danger); }
.job .expiry { font-size: var(--fs-micro); color: var(--fg-muted); }
dialog.confirm { max-width: min(440px, calc(100vw - 32px)); padding: var(--sp-5); border: 1px solid var(--border); background: var(--surface-card); color: var(--fg); }
dialog.confirm:not([open]) { display: none; }
dialog.confirm::backdrop { background: color-mix(in srgb, var(--fg) 35%, transparent); }
dialog.confirm .row { justify-content: flex-end; gap: var(--sp-2); }

.workspace { display: flex; flex-direction: column; min-height: 0; }
.tabs { display: flex; gap: 0; border-bottom: 1px solid var(--border); padding: 0 calc(var(--gutter) - var(--sp-3)); overflow-x: auto; }
.tabs button {
  background: none; border: 0; border-bottom: 2px solid transparent; color: var(--fg-muted);
  font: inherit; font-size: var(--fs-small); padding: 0 var(--sp-3); min-height: 44px; cursor: pointer; white-space: nowrap;
}
.tabs button[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--accent); font-weight: var(--fw-medium); }
.tabs button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.panel { flex: 1; overflow: auto; padding: var(--sp-4) var(--gutter); min-height: 0; display: flex; flex-direction: column; }
.scroll-x { overflow-x: auto; max-width: 100%; }

.job { border: 1px solid var(--border); padding: var(--sp-3) var(--sp-4); background: var(--surface-card); --surface: var(--surface-card); }
.job.active { border-color: var(--accent); }
.job header { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.job h3 { margin: 0; font-size: var(--fs-body); }
.job .params { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: var(--fs-small); color: var(--fg-muted); margin: var(--sp-2) 0; }
.job .params b { color: var(--fg); font-weight: var(--fw-medium); }
.job pre.log { font-family: var(--font-mono); font-size: 11px; max-height: 120px; overflow: auto; background: var(--bg-alt); padding: 6px 8px; margin: var(--sp-2) 0 0; }
.job .progress-row { margin-top: var(--sp-2); }
.job .actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-2); align-items: center; }
.job .actions a, .job .actions button { font-size: var(--fs-small); }
.state { font-size: var(--fs-micro); }
.jobref { cursor: pointer; }

.viewer-bar { gap: var(--sp-3); align-items: center; flex-wrap: wrap; margin-bottom: var(--sp-2); }
.viewer { flex: 1; min-height: 320px; background: var(--viewer-bg); position: relative; }
.viewer canvas { display: block; width: 100%; height: 100%; }
.viewer .empty { padding: var(--sp-4); }
/* Viewer overlays: axis gizmo colours (conventional X/Y/Z, muted towards the text colour), max marker and label. */
:root {
  --axis-x: color-mix(in srgb, var(--c-red) 70%, var(--fg-muted));
  --axis-y: color-mix(in srgb, var(--c-green) 70%, var(--fg-muted));
  --axis-z: color-mix(in srgb, var(--c-blue) 65%, var(--fg-muted));
  --max-marker: var(--c-orange);
  --max-marker-ring: var(--bg);
  /* Loads (arrows) and supports (tinted faces, markers): red and green from the palette, darkened for
     the light view (5.3:1 and 3.9:1 on the beige viewer background), lightened/plain for the dark one
     (4.2:1 and 5.0:1 on #2c2c2c). */
  --load: color-mix(in srgb, var(--c-red) 85%, var(--c-black));
  --support: color-mix(in srgb, var(--c-green) 70%, var(--c-black));
}
[data-theme="dark"] {
  --load: color-mix(in srgb, var(--c-red) 70%, var(--c-white));
  --support: var(--c-green);
}
.bc-legend {
  position: absolute; left: var(--sp-2); top: var(--sp-2); margin: 0; padding: 4px 8px; list-style: none;
  pointer-events: none; z-index: 1; max-width: calc(100% - 2 * var(--sp-2));
  background: color-mix(in srgb, var(--surface-card) 88%, transparent); color: var(--fg);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--fs-micro); line-height: 1.5;
}
.bc-legend li { display: flex; align-items: center; gap: 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bc-legend .sw { flex: none; display: inline-block; width: 14px; height: 10px; }
.bc-legend .sw-load { height: 3px; background: var(--load); position: relative; }
.bc-legend .sw-load::after {
  content: ""; position: absolute; right: -2px; top: -4px;
  border-left: 7px solid var(--load); border-top: 5.5px solid transparent; border-bottom: 5.5px solid transparent;
}
.bc-legend .sw-support { background: var(--support); border-radius: 2px; }
.max-label {
  position: absolute; left: 0; top: 0; pointer-events: none; white-space: nowrap; z-index: 1;
  background: var(--surface-card); color: var(--fg); border: 1px solid var(--border); border-left: 3px solid var(--max-marker);
  font-size: var(--fs-micro); font-weight: var(--fw-medium); line-height: 1.3; padding: 2px 6px;
  font-variant-numeric: tabular-nums; box-shadow: var(--shadow-sm); border-radius: var(--radius-sm);
}
.colorbar { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-small); margin-top: var(--sp-2); font-variant-numeric: tabular-nums; }
.colorbar .ramp { flex: 1; height: 12px; background: var(--ramp); max-width: 360px; }

.charts { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: var(--sp-5) var(--sp-4); }
.chart-card { margin: 0; min-width: 0; }
.chart-card h4 { margin: 0 0 4px; font-size: var(--fs-small); font-weight: var(--fw-medium); }
.chart-card svg { width: 100%; height: auto; overflow: visible; }
.chart-card .line { fill: none; stroke: var(--chart-brand-1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart-card .pt { fill: var(--chart-brand-1); stroke: var(--surface-card); stroke-width: 2; }
.chart-card .ref { stroke: var(--fg-muted); stroke-dasharray: 4 4; stroke-width: 1; }
.chart-card .grid { stroke: var(--border); stroke-width: 1; }
.chart-card text { fill: var(--fg-muted); font-size: 11px; font-family: var(--font-sans); }
.chart-card text.val { fill: var(--fg); paint-order: stroke; stroke: var(--bg); stroke-width: 4px; stroke-linejoin: round; }
.chart-card .hit { fill: transparent; cursor: crosshair; }
.chart-card .cross { stroke: var(--fg-muted); stroke-width: 1; }
.tip {
  position: fixed; pointer-events: none; background: var(--bg-invert); color: var(--fg-invert);
  font-size: var(--fs-micro); padding: 4px 8px; z-index: 10; white-space: nowrap;
  border-radius: var(--radius-sm); box-shadow: var(--shadow-md); font-variant-numeric: tabular-nums;
}

table.results { border-collapse: collapse; width: 100%; font-size: var(--fs-small); font-variant-numeric: tabular-nums; }
table.results th, table.results td { padding: 6px 10px; border-bottom: 1px solid var(--border); text-align: right; }
table.results th:first-child, table.results td:first-child { text-align: left; }
table.results th { font-weight: var(--fw-medium); color: var(--fg-muted); }
.kv { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(160px, 100%), 1fr)); gap: var(--sp-3); margin-bottom: var(--sp-4); }
.kv div { border-left: 2px solid var(--accent); padding-left: var(--sp-2); }
.kv b { display: block; font-size: 1.2rem; font-variant-numeric: tabular-nums; }
.kv span { font-size: var(--fs-micro); color: var(--fg-muted); }
.notes { font-size: var(--fs-small); color: var(--fg-muted); }
#table h4 { margin: var(--sp-4) 0 var(--sp-2); font-weight: var(--fw-medium); }

.deck-bar { justify-content: space-between; margin-bottom: var(--sp-2); }
pre.deck { font-family: var(--font-mono); font-size: 12px; background: var(--bg-alt); padding: var(--sp-3); overflow: auto; flex: 1; margin: 0; }
pre.deck .slot { background: color-mix(in srgb, var(--c-purple-light) 35%, transparent); }

.foot { padding: var(--sp-2) var(--gutter); border-top: 1px solid var(--border); }

@media (max-width: 900px) {
  /* Stacked: the page scrolls as a whole instead of fitting the viewport. */
  html, body { height: auto; }
  .app { grid-template-columns: minmax(0, 1fr); height: auto; flex: none; }
  .splitter { display: none; }
  .workspace { min-height: auto; }
  .chat { border-right: 0; border-bottom: 1px solid var(--border); height: 70vh; height: 70dvh; }
  .topbar { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
  .viewer { min-height: 300px; }
  .panel { overflow: visible; }
}
@media (max-width: 600px) {
  .topbar { gap: var(--sp-2); }
  .topbar-actions { order: 3; width: 100%; }
  .topbar-actions label[for="llm"] { display: none; }
  .agent-pick { flex: 1 1 100%; min-width: 0; }
  #llm { min-width: 0; max-width: 100%; }
  .topbar-actions .select-sm { flex: 1 1 100%; }
}
@media (max-width: 520px) {
  /* The usage meter keeps value and bar, and takes the room between the brand and the theme button
     (never wrapping them); its details span the page width (app.js keeps them on screen). */
  .usage { flex: 1 1 0; min-width: 0; }
  .usage-meter { width: 100%; max-width: 16rem; }
  .usage-cell { flex: 1 0 auto; min-width: 0; padding: 5px 8px 6px; }
  .usage-cell:first-child { flex-shrink: 1; } /* only the time's words give way */
  .usage-val { overflow: hidden; text-overflow: ellipsis; }
  .usage-cap, .usage-eta, .usage-long { display: none; }
  .usage-short { display: inline; }
  .usage-pop { width: calc(100vw - 2 * var(--gutter)); }
}

/* Your local model: the address with its "Find models" button. */
.local-url-row { display: flex; gap: var(--sp-2); }
.local-url-row .input { flex: 1; min-width: 0; }
#local-dialog { max-width: min(560px, calc(100vw - 32px)); }
#local-dialog code { overflow-wrap: anywhere; }
.server-tabs { display: flex; flex-wrap: wrap; gap: 6px; }
.server-tabs .chip[aria-selected="true"] { background: var(--btn-primary-bg); color: var(--btn-primary-fg); border-color: var(--btn-primary-bg); }
.server-tabs .chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.server-steps { border-left: 2px solid var(--accent); padding: 2px 0 2px var(--sp-3); }
.server-steps p, .server-steps ul { margin: 0 0 var(--sp-2); }
.server-steps > :last-child { margin-bottom: 0; }
.server-steps ul { padding-left: 1.2em; }
.cmd { display: flex; align-items: flex-start; gap: var(--sp-2); background: var(--bg-alt); padding: 6px 6px 6px 10px; margin: 0 0 var(--sp-2); }
.cmd code { flex: 1; min-width: 0; padding: 0; background: none; white-space: pre-wrap; overflow-wrap: anywhere; }
.cmd .cmd-copy { flex: none; min-height: 0; padding: 2px 8px; }
#local-dialog { max-height: calc(100dvh - 32px); overflow-y: auto; }

/* Beta badge and the update banner (maintenance mode, docs/DEPLOYMENT.md "Updating") */
.beta-badge { margin-left: var(--sp-1); vertical-align: middle; font-size: 10px; padding: 1px 6px; }
/* Brand purple, full width, above everything: nobody should miss it. A moving stripe says "in progress". */
.update-banner { position: sticky; top: 0; z-index: 50; margin: 0; padding: var(--sp-4) var(--sp-5);
  background: var(--fill-brand); color: var(--on-fill-brand); box-shadow: 0 4px 16px rgb(0 0 0 / 0.25);
  grid-template-columns: auto 1fr; align-items: center; overflow: hidden; flex: none; }
.update-banner[hidden] { display: none; }
.update-banner .dot { width: 14px; height: 14px; margin-top: 0; background: currentColor; animation: upd-pulse 1.2s ease-in-out infinite; }
.update-banner b { font-size: 1.15rem; margin-bottom: 4px; }
.update-banner #update-text { display: block; font-size: 1rem; line-height: 1.45; }
.update-banner::after { content: ""; position: absolute; left: 0; bottom: 0; height: 4px; width: 30%;
  background: currentColor; opacity: 0.6; animation: upd-slide 1.6s linear infinite; }
@keyframes upd-pulse { 50% { opacity: 0.35; } }
@keyframes upd-slide { from { transform: translateX(-100%); } to { transform: translateX(340%); } }
@media (prefers-reduced-motion: reduce) { .update-banner .dot, .update-banner::after { animation: none; } }
body.updating .composer textarea, body.updating #prompt { opacity: 0.6; }
