/* The design system, ported from design/mockups/control-deck.html.
 *
 * One rule explains almost every choice here:
 *
 *   animated spectrum      you can act here
 *   bright white + motion  the machine is at work
 *   one static tint        session identity
 *   dim grey, still        inert
 *
 * Colour is never decoration. If something is coloured the reader can do
 * something to it, and the *treatment* says what kind of thing it is — a ring
 * for a decision, an underline for an action in prose, an underlined value for
 * a dropdown, a chevron for a disclosure. Adding a new treatment means there
 * is a new *kind* of action; adding one for variety's sake breaks the grammar
 * that makes the rest legible.
 *
 * Committed to a single dark theme: this is a room you sit in, and the
 * bright-white-means-working signal only reads against a dark ground. */

:root {
  --bg: #0f1113;
  --well: #0b0d0f;
  --line: #23272c;
  --line-soft: #1a1e22;
  --ink: #c7ccd1;
  --ink-soft: #828a92;
  --ink-dim: #4e565e;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
  --serif: Charter, "Bitstream Charter", Cambria, Georgia, serif;
  /* Six muted hues, always used as a set. A single accent colour would make
     "coloured" mean "this particular thing" instead of "you can act". */
  --sp1: #a86e70; --sp2: #a88a6e; --sp3: #999c6e;
  --sp4: #6ea183; --sp5: #6e91a8; --sp6: #8b79a8;
  --spectrum: linear-gradient(90deg, var(--sp1), var(--sp2), var(--sp3), var(--sp4), var(--sp5), var(--sp6), var(--sp1));
  /* The machine's colour: no hue at all, just more light than anything else.
     Reserved for *activity* — using it for failure would spend the one signal
     that means "something is happening" on something that has stopped. */
  --hot: #f2f6fa;
  /* Failure goes the other way: darker than the dimmest ordinary text, so a
     thing that did not work reads as less, not more. */
  --fail: #3c4146;
  color-scheme: dark;
}

* { box-sizing: border-box; }

/* A column of: top bar, then whatever fills the rest. Pages that are a single
   full-height surface (the control room, one conversation) claim the
   remainder; pages that are documents scroll inside it. */
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
body:has(.room, .fullpage) { height: 100vh; overflow: hidden; }
.fullpage { flex: 1; min-height: 0; display: flex; flex-direction: column; }

/* ---------------------------------------------------------- animations */

@keyframes slide  { to { background-position: 300% 100%; } }
@keyframes drift  { to { background-position: 300% 0; } }
@keyframes sheen  { to { background-position: -200% 0; } }
@keyframes blink  { 50% { opacity: 0; } }
@keyframes breathe { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
@keyframes hue {
  0%,100% { background: var(--sp1); } 17% { background: var(--sp2); }
  33% { background: var(--sp3); }     50% { background: var(--sp4); }
  67% { background: var(--sp5); }     83% { background: var(--sp6); }
}
@keyframes huetext {
  0%,100% { color: var(--sp1); } 17% { color: var(--sp2); }
  33% { color: var(--sp3); }     50% { color: var(--sp4); }
  67% { color: var(--sp5); }     83% { color: var(--sp6); }
}

/* ---------------------------------------------------- action vocabulary */

/* An action inside prose or a flowing row: spectrum underline. */
.abtn, a.ulink {
  background: none; border: none; font: inherit; font-size: 11px;
  color: var(--ink-soft); cursor: pointer; padding: 0 0 3px;
  text-decoration: none;
  background-image: var(--spectrum);
  background-size: 300% 1.5px; background-repeat: repeat-x; background-position: 0 100%;
  animation: slide 18s linear infinite;
}
.abtn:hover, a.ulink:hover { color: var(--ink); background-size: 300% 2.5px; }
.abtn:focus-visible, a.ulink:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: 3px; }

/* A decision or a clear command: a chip ringed by the spectrum. */
.dbtn {
  position: relative; background: var(--well); border: none; font: inherit;
  font-size: 11px; color: var(--ink-soft); padding: 4px 12px; border-radius: 5px;
  cursor: pointer;
}
.dbtn::before {
  content: ""; position: absolute; inset: 0; border-radius: 5px; padding: 1px;
  background: var(--spectrum); background-size: 300% 100%;
  animation: drift 16s linear infinite; opacity: .65;
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
.dbtn:hover { color: var(--ink); }
.dbtn:hover::before { opacity: 1; }
.dbtn:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: 2px; }

/* In flight: colour drains out and the machine's white passes through, so a
   round trip through the agent is visible rather than a frozen button. */
.dbtn.sending, .abtn.sending {
  background: none; color: transparent; pointer-events: none;
  background-image: linear-gradient(90deg, var(--ink-dim), var(--hot), var(--ink-dim));
  background-size: 200% 100%;
  -webkit-background-clip: text; background-clip: text;
  animation: sheen 1.1s linear infinite;
}
.dbtn.sending::before { display: none; }
.dbtn.mute, .abtn.mute {
  background-image: none; color: var(--ink-dim); pointer-events: none; animation: none;
}
.dbtn.mute::before { display: none; }

/* Utilities — reorder, dock, bury: quiet hue-cycling text, no underline. */
.qbtn {
  background: none; border: none; font: inherit; font-size: 9.5px; cursor: pointer;
  padding: 0; color: var(--sp5); animation: huetext 16s linear infinite; opacity: .65;
}
.qbtn:hover { opacity: 1; }
.qbtn:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: 2px; }

/* A dropdown: the label is plain, the current value carries the underline,
   and the whole control is the click target. */
.drop {
  background: none; border: none; font: inherit; font-size: 10.5px;
  color: var(--ink-dim); cursor: pointer; padding: 0;
}
.drop .val {
  color: var(--ink-soft); padding-bottom: 3px;
  background-image: var(--spectrum); background-size: 300% 1.5px;
  background-repeat: repeat-x; background-position: 0 100%;
  animation: slide 18s linear infinite;
}
.drop:hover .val { color: var(--ink); background-size: 300% 2.5px; }
.drop:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: 2px; }

.menu {
  position: fixed; z-index: 60; min-width: 150px;
  background: #14171a; border: 1px solid var(--line); border-radius: 6px;
  padding: 4px; box-shadow: 0 10px 28px rgba(0,0,0,.55);
}
.menu button {
  display: block; width: 100%; text-align: left; background: none; border: none;
  font: inherit; font-size: 11px; color: var(--ink-soft);
  padding: 5px 10px; border-radius: 4px; cursor: pointer; white-space: nowrap;
}
.menu button:hover { background: var(--well); color: var(--ink); }
.menu button.cur { color: var(--ink); }
.menu button.cur::after { content: " ✓"; color: var(--ink-dim); }
.menu .sep { height: 1px; background: var(--line); margin: 4px 2px; }

/* An escalation marker. The row it sits in is itself an action — it opens the
   thing being asked about — so the pip is never colour without a use. */
.pip {
  width: 5px; height: 5px; border-radius: 50%; flex: none;
  background: var(--sp4); animation: hue 9s linear infinite;
}

/* ------------------------------------------------------ the page shell */

.top {
  display: flex; align-items: baseline; gap: 18px;
  padding: 9px 16px; border-bottom: 1px solid var(--line);
  font-size: 10px; text-transform: uppercase; letter-spacing: .16em;
  color: var(--ink-dim);
}
.top .sp { flex: 1; }
.top .here { color: var(--ink-soft); }

main { padding: 16px; flex: 1; }

/* ------------------------------------------- setup, agents, settings pages */

.page { max-width: 640px; margin: 0 auto; padding: 36px 20px 90px; font-size: 13px; line-height: 1.6; }
.page h1 {
  font-family: var(--serif); font-size: 26px; font-weight: 600;
  letter-spacing: -.01em; line-height: 1.3; margin: 0 0 14px; text-wrap: balance;
}
.page h2 {
  font-size: 10px; text-transform: uppercase; letter-spacing: .18em;
  color: var(--ink-dim); margin: 34px 0 12px; font-weight: 600;
}
.page p { margin: 0 0 14px; max-width: 60ch; color: var(--ink-soft); }
.page p.lede { font-family: var(--serif); font-size: 16px; color: var(--ink); }
.page code {
  background: var(--well); border: 1px solid var(--line-soft);
  padding: 1px 6px; border-radius: 4px; font-size: 12px;
}
.page .card { background: #14171a; }
.page label {
  display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--ink-dim); margin: 16px 0 6px;
}
.page input[type=text] { background: var(--well); border-radius: 6px; padding: 8px 10px; }
.page input[type=text]:focus {
  outline: none; border-color: var(--ink-dim);
  box-shadow: 0 0 16px rgba(110,145,168,.22), 0 0 5px rgba(168,110,112,.18);
}

.cardrow { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.cardrow b { font-size: 13px; font-weight: 600; color: var(--ink); }
.cardrow .right { margin-left: auto; display: flex; gap: 14px; align-items: baseline; }
.card .sub, .page .sub { color: var(--ink-dim); font-size: 11px; margin-top: 4px; }
.btnrow { display: flex; gap: 18px; align-items: center; margin-top: 24px; flex-wrap: wrap; }

/* A bigger version of the same ring — the same *kind* of action (a clear
   decision), given the weight a primary step in a wizard needs. */
.dbtn.big { font-size: 12.5px; padding: 9px 20px; color: var(--ink); text-decoration: none; }

/* The timeline is the setup's only navigation. Where you are is a fact, so it
   is the one entry with no colour on it. */
.steps { display: flex; gap: 8px; align-items: center; margin-bottom: 28px; font-size: 10px; }
.steps .dotline { flex: none; width: 22px; height: 1px; background: var(--line); }
.stepbtn {
  background: none; border: none; font: inherit; font-size: 10px; cursor: pointer;
  padding: 0 0 2px; color: var(--ink-dim); text-decoration: none;
}
a.stepbtn:hover {
  color: var(--ink-soft); background-image: var(--spectrum);
  background-size: 300% 1px; background-repeat: repeat-x; background-position: 0 100%;
}
.stepbtn.here { color: var(--ink); cursor: default; }

.term {
  background: #0a0c0e; border: 1px solid var(--line); border-radius: 8px;
  padding: 12px 14px; font-size: 11.5px; line-height: 1.7; margin: 14px 0;
  color: var(--ink-soft); overflow-x: auto; white-space: pre-wrap;
}
/* The per-kind matrix. Checkboxes are inputs, not actions, so they are
   outlined rather than coloured; the action was choosing "custom". */
.askmatrix { display: flex; flex-wrap: wrap; gap: 8px 20px; margin: 12px 0 0; }
/* `.page label` is the more specific rule, so these have to be too — otherwise
   the field labels' uppercase and margins leak onto the toggles. */
.page .askmatrix .toggle {
  display: inline-flex; align-items: center; gap: 7px; margin: 0;
  font-size: 11.5px; text-transform: none; letter-spacing: 0;
  color: var(--ink-soft); cursor: pointer;
}
.page .askmatrix .toggle:hover { color: var(--ink); }
.page .askmatrix .toggle input {
  width: auto; margin: 0; accent-color: var(--ink-dim); cursor: pointer;
}

.okmark { color: var(--hot); }
.still { color: var(--ink-dim); }
main.narrow { max-width: 62rem; margin: 0 auto; }

.card {
  border: 1px solid var(--line); border-radius: 8px;
  padding: 14px 16px; margin-bottom: 14px; background: var(--well);
}
.card > h2 {
  margin: 0 0 12px; font-size: 9px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .18em; color: var(--ink-dim);
}
.prose { font-family: var(--serif); font-size: 14px; color: var(--ink-soft); max-width: 62ch; }
.dim { color: var(--ink-dim); }
.mono { font-family: var(--mono); }

label { display: block; font-size: 10px; color: var(--ink-dim); margin: 10px 0 4px; }
input[type=text], input[type=password], select, textarea {
  font: inherit; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line); border-radius: 5px; padding: 6px 8px; width: 100%;
}
input:focus, select:focus, textarea:focus { outline: 1px solid var(--ink-dim); }
.row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }

table { width: 100%; border-collapse: collapse; }
td, th { text-align: left; padding: 6px 4px; border-bottom: 1px solid var(--line-soft); }
th {
  color: var(--ink-dim); font-weight: 500; font-size: 9px;
  text-transform: uppercase; letter-spacing: .14em;
}

/* State words are informational, not actions, so they stay colourless. */
.state { font-size: 9px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-dim); }
.state.ready { color: var(--ink-soft); }
.state.failed { color: var(--fail); }

/* ------------------------------------------------- conversation: shell */

.conversation { display: flex; flex-direction: column; min-height: 0; height: 100%; }

.sbar {
  display: flex; gap: 16px; align-items: baseline; padding: 8px 16px;
  border-bottom: 1px solid var(--line); font-size: 11px; flex-wrap: wrap; flex: none;
}
.sbar b { color: var(--ink-soft); font-weight: 500; font-size: 12px; }
.sbar .stat { margin-left: auto; color: var(--ink-dim); display: inline-flex; gap: 6px; align-items: center; }

.ctx { display: inline-flex; align-items: center; gap: 5px; }
.ctxbar { width: 34px; height: 3px; background: var(--well); border-radius: 2px; overflow: hidden; }
.ctxbar i { display: block; height: 100%; background: var(--ink-dim); }

/* The machine is working: no hue, just light and motion. */
.busy { display: inline-flex; align-items: center; gap: 6px; color: var(--ink-soft); }
.busy .dot {
  width: 5px; height: 5px; border-radius: 50%; background: var(--hot);
  animation: breathe 2.2s ease-in-out infinite;
}

.scroll { flex: 1; overflow-y: auto; padding: 14px 0 8px; min-height: 0; }

/* --------------------------------------------- conversation: transcript */

/* Two registers: a serif for anything anyone *said*, the mono for machinery.
   The distinction is what lets the eye skip the plumbing. */
.you {
  font-family: var(--serif); font-size: 15px; color: var(--ink-soft);
  margin: 0 18px 12px; max-width: 60ch; white-space: pre-wrap;
}
.say {
  font-family: var(--serif); font-size: 15px; color: var(--ink);
  margin: 10px 18px; max-width: 60ch; line-height: 1.6; white-space: pre-wrap;
}
.say:empty { display: none; }
.say code, .dsay code, .prose code {
  font-family: var(--mono); font-size: 12px; background: var(--well);
  border: 1px solid var(--line-soft); padding: 1px 4px; border-radius: 3px;
}

.turnline {
  display: flex; align-items: center; gap: 10px; color: var(--ink-dim);
  font-size: 9.5px; text-transform: uppercase; letter-spacing: .14em;
  margin: 14px 18px 10px;
}
.turnline::after { content: ""; flex: 1; height: 1px; background: var(--line-soft); }
.turnend { margin: 4px 18px 12px; color: var(--ink-dim); font-size: 10px; }

/* Plumbing: one line each, expandable, never competing with prose. */
.machine { margin: 2px 18px; }
.machine summary {
  list-style: none; cursor: pointer; color: var(--ink-dim); font-size: 11px;
  display: flex; gap: 8px; align-items: baseline; padding: 2px 0;
}
.machine summary::-webkit-details-marker { display: none; }
.machine summary::before {
  content: "▸"; font-size: 10px; flex: none; align-self: center;
  color: var(--sp5); animation: huetext 12s linear infinite; transition: transform .15s;
}
.machine[open] summary::before { transform: rotate(90deg); }
.machine summary:hover { color: var(--ink-soft); }
.machine .st { font-size: 9px; text-transform: uppercase; letter-spacing: .1em; flex: none; }
.machine .st.fail { color: var(--fail); }
.machine .ttl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.machine .mdetail {
  color: var(--ink-dim); font-size: 11px; padding: 4px 0 6px 16px;
  white-space: pre-wrap; word-break: break-word; margin: 0;
  max-height: 22rem; overflow: auto;
}
/* A diff reads as what was added being *there* and what was removed being
   gone — so additions take the machine's white and deletions fade out. */
.mdetail .add { color: var(--hot); }
.mdetail .del { color: var(--ink-dim); text-decoration: line-through; }
/* The plan is the one machine block that opens by default, so it gets room to
   be read rather than the dense single line the others use. */
.machine.plan summary { color: var(--ink-soft); }
.steps-plan { list-style: none; margin: 4px 0 8px; padding: 0 0 0 16px; }
.steps-plan .step {
  display: flex; gap: 8px; align-items: baseline;
  color: var(--ink-soft); font-size: 12px; padding: 2px 0;
}
.steps-plan .step .mark { color: var(--ink-dim); flex: none; width: 1ch; }
/* Done is settled, so it recedes; the step being worked on is the only one
   the machine is actually touching, so it gets the machine's light. */
.steps-plan .step.completed { color: var(--ink-dim); }
.steps-plan .step.in_progress { color: var(--ink); }
.steps-plan .step.in_progress .mark { color: var(--hot); }

.machine.think .mdetail {
  font-family: var(--serif); font-size: 13px; font-style: italic;
  color: var(--ink-soft); max-width: 56ch;
}

/* Errors are not plumbing — they stay in the transcript rather than the
   session log — but they are still something that *failed*, so they are quiet
   and marked by a rule rather than made bright. */
.notice {
  /* Darker than the prose around it, not brighter — but still an error
     somebody has to read, so it stops at legible rather than going all the way
     down to the failure tone the marker and rule use. */
  margin: 6px 18px; font-size: 11px; color: var(--ink-soft); white-space: pre-wrap;
  border-left: 2px solid var(--fail); padding-left: 8px;
}

/* --------------------------------------------- conversation: decisions */

.decide { margin: 16px 18px; max-width: 60ch; }
.ckind {
  font-size: 9px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-soft); display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
}
.reqdetail summary { list-style: none; cursor: pointer; }
.reqdetail summary::-webkit-details-marker { display: none; }
.reqdetail .go {
  margin-left: auto; opacity: 0; transition: opacity .15s; color: var(--ink-soft);
  text-transform: none; letter-spacing: .02em;
}
.reqdetail summary:hover .go, .reqdetail[open] .go { opacity: 1; }
.reqdetail pre {
  font-size: 10.5px; color: var(--ink-dim); background: var(--well);
  border: 1px solid var(--line-soft); border-radius: 5px; padding: 8px 10px;
  overflow-x: auto; margin: 0 0 9px;
}
.decide .dsay {
  font-family: var(--serif); font-size: 15px; margin: 0 0 9px; line-height: 1.6;
  white-space: pre-wrap;
}
/* What the decision is about. Bounded so a long plan does not push the
   options off the screen — the buttons have to stay reachable — but tall
   enough that the plan is read rather than glimpsed. */
.about {
  font-size: 11.5px; color: var(--ink-soft); white-space: pre-wrap;
  word-break: break-word; margin: 0 0 12px; padding: 10px 12px;
  background: var(--well); border: 1px solid var(--line-soft); border-radius: 6px;
  max-height: 24rem; overflow: auto;
}
.about .add { color: var(--hot); }
.about .del { color: var(--ink-dim); text-decoration: line-through; }

.acts { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; }
/* A decision is made once: the card stops accepting clicks the moment one
   lands, before the answer has been anywhere near the agent. Only until it
   comes back, though — see the watchdog in conversation.js. */
.decide.answered { pointer-events: none; }
/* When it does not come back. A fact about the machinery, not something to be
   acted on — the action is the options, which have just been handed back — so
   it is quiet, like every other failure. */
.stuck { color: var(--ink-dim); font-size: 10.5px; margin-top: 8px; }
.decide.done .acts, .decide.done .pip { display: none; }
.resolved { display: none; color: var(--ink-dim); font-size: 10.5px; }
.decide.done .resolved { display: block; }

/* A form the agent asked for. Fields are inputs, not actions, so they are
   outlined rather than coloured; only the submit chip is an action. */
.askform { margin-top: 4px; }
.askform label { font-size: 10.5px; color: var(--ink-soft); }
.askform .fielddesc { color: var(--ink-dim); font-size: 10px; margin-bottom: 3px; }
.askform textarea { font-family: var(--serif); font-size: 13px; resize: vertical; }
.askform select[multiple] { height: auto; min-height: 4.5rem; }
.askform .acts { margin-top: 10px; }

/* ---------------------------------------- conversation: queue, composer */

.queued {
  margin: 0 16px 8px; padding: 7px 10px; border: 1px dashed var(--line);
  border-radius: 6px; font-size: 10.5px; color: var(--ink-dim);
  display: flex; gap: 6px 14px; align-items: baseline; flex-wrap: wrap; flex: none;
}
.queued:empty { display: none; }
.queued .qtext {
  font-family: var(--serif); font-size: 13px; font-style: italic; color: var(--ink-soft);
}

.composer { border-top: 1px solid var(--line); padding: 10px 16px 12px; flex: none; }
/* Full saturation at rest — the composer is always available, so it is always
   coloured; focus adds light rather than turning colour on. */
.fieldwrap { position: relative; padding: 1px; border-radius: 7px; }
.fieldwrap::before {
  content: ""; position: absolute; inset: 0; border-radius: 7px;
  background: var(--spectrum); background-size: 300% 100%;
  animation: drift 16s linear infinite; opacity: .9;
}
.fieldwrap:focus-within {
  box-shadow: 0 0 22px rgba(110,145,168,.28), 0 0 7px rgba(168,110,112,.22);
}
.composer textarea {
  position: relative; display: block; width: 100%;
  background: var(--well); border: none; border-radius: 6px;
  color: var(--ink); font-family: var(--serif); font-size: 14px; padding: 8px 10px;
  resize: none; height: 54px;
}
.composer textarea:focus { outline: none; }
.composer .hint { color: var(--ink-dim); font-size: 10px; margin-top: 6px; }

.ghost { color: var(--ink-dim); font-family: var(--serif); font-style: italic; margin: 24px 18px; }
/* The empty-state line is part of the transcript, so it has to disappear the
   moment the transcript has anything in it — including content that arrived by
   streaming, which never re-renders the surrounding markup. */
.scroll:has(.you, .say, .machine, .decide, .notice, .turnend) .ghost { display: none; }

/* The session log: plumbing about the plumbing. */
.syslog { margin: 8px 16px 0; flex: none; }
.syslog summary {
  list-style: none; cursor: pointer; color: var(--ink-dim); font-size: 10px;
  text-transform: uppercase; letter-spacing: .12em;
  display: flex; gap: 8px; align-items: center;
}
.syslog summary::-webkit-details-marker { display: none; }
.syslog summary::before {
  content: "▸"; font-size: 10px; color: var(--sp5);
  animation: huetext 12s linear infinite; transition: transform .15s;
}
.syslog[open] summary::before { transform: rotate(90deg); }
.syslog .lines { max-height: 12rem; overflow: auto; padding: 6px 0 0 16px; }
.syslog .lines div { color: var(--ink-dim); font-size: 10.5px; padding: 1px 0; }

.cmdlist { max-height: 14rem; overflow: auto; padding: 6px 0 0 16px; }
.cmdlist div { padding: 1px 0; color: var(--ink-dim); font-size: 10.5px; }

/* ------------------------------------------------------ reduced motion */

/* Motion carries meaning here, so removing it must not remove the meaning:
   everything keeps its colour, and the machine's white stays lit rather than
   breathing. */
@media (prefers-reduced-motion: reduce) {
  .abtn, a.ulink, .dbtn::before, .dbtn.sending, .abtn.sending, .qbtn,
  .drop .val, .pip, .fieldwrap::before, .machine summary::before,
  .syslog summary::before, .busy .dot {
    animation: none !important;
  }
  .pip { background: var(--sp4); }
  .qbtn, .machine summary::before, .syslog summary::before { color: var(--sp5); }
  .busy .dot { opacity: 1; }
}

/* ======================================================== the control room
 *
 * Three tiers of attention, all user-controlled. Fixed-width strips, because
 * things that resize when you interact with them destroy the spatial memory
 * that makes a dozen sessions manageable — where a session *is* on screen is
 * as much of a handle as what it is called. */

.room { flex: 1; min-height: 0; display: flex; flex-direction: column; }

.stage { display: flex; flex: 1; min-height: 0; overflow-x: auto; }

.chan {
  flex: 0 0 300px; display: flex; flex-direction: column;
  /* Identity: one hue per session, at a saturation low enough to read as
     "which one is this" rather than as a status. */
  background: hsl(var(--h) 11% 11%);
  border-right: 1px solid var(--line-soft);
  transition: flex-basis .38s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}

.chead {
  width: 100%; text-align: left; background: none; border: none;
  color: inherit; font: inherit; padding: 10px 14px 8px; cursor: pointer;
  display: flex; align-items: baseline; gap: 8px; flex: none;
}
.chead:hover { background: rgba(0,0,0,.25); }
.chead:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: -1px; }
/* The name zooms the session, so it carries the action treatment. */
.cname {
  font-weight: 600; letter-spacing: .02em; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; padding-bottom: 3px;
  background-image: var(--spectrum);
  background-size: 300% 1px; background-repeat: repeat-x; background-position: 0 100%;
  animation: slide 34s linear infinite;
}
.chead:hover .cname { background-size: 300% 2px; color: #e2e6ea; }
.cstate {
  margin-left: auto; font-size: 9px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-dim); white-space: nowrap;
}
.chan[data-needs] .cstate, .chan[data-state="working"] .cstate { color: var(--ink-soft); }

/* The one mark that appears purely because the session wants something. */
.sig {
  height: 1px; flex: none; opacity: 0; transition: opacity .5s;
  background: var(--spectrum); background-size: 300% 100%;
  animation: drift 16s linear infinite;
}
.chan[data-needs] .sig { opacity: .85; }
.chan:not([data-needs]) .chead { border-bottom: 1px solid var(--line); margin-bottom: -1px; }

.brief {
  font-family: var(--serif); font-size: 14.5px; line-height: 1.5;
  color: var(--ink); margin: 0; padding: 12px 14px; flex: none;
}
.chan[data-state="idle"] .brief, .chan[data-state="working"] .brief { color: var(--ink-soft); }

.call { padding: 0 14px 14px; flex: none; }
button.ckind {
  background: none; border: none; padding: 0; font: inherit; cursor: pointer;
  width: 100%; text-align: left;
}
.ckind .go {
  margin-left: auto; opacity: 0; transition: opacity .15s; color: var(--ink-soft);
  text-transform: none; letter-spacing: .02em;
}
button.ckind:hover .go, button.ckind:focus-visible .go { opacity: 1; }
button.ckind:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: 2px; }
.cbody { margin-bottom: 9px; overflow-wrap: break-word; }

/* Only this zone breathes while the session works: a whole strip pulsing is
   too much when there are eight of them. */
.machinezone { margin-top: auto; flex: none; border-top: 1px solid var(--line-soft); }
.chan[data-state="working"] .machinezone { animation: alive 4.4s ease-in-out infinite; }
@keyframes alive { 0%, 100% { background: transparent; } 50% { background: hsl(var(--h) 14% 15%); } }
/* Dead: no colour, no motion, and dimmer than everything around it. It wants
   a decision about whether you are finished with it. */
.chan[data-state="dead"], .chan[data-state="idle"] { background: hsl(var(--h) 6% 8%); }
.chan[data-state="dead"] :is(.brief, .tail, .srow > span) { opacity: .45; }
.chan[data-state="dead"] .cname { background-image: none; animation: none; }
.chan[data-state="dead"] .chead:hover .cname { background-image: var(--spectrum); }

.srow {
  display: flex; gap: 10px; padding: 7px 14px 5px; color: var(--ink-dim);
  font-size: 10px; white-space: nowrap; overflow: hidden;
}
.tail {
  padding: 4px 14px 8px; overflow: hidden; display: flex;
  flex-direction: column; justify-content: flex-end; gap: 3px; height: 84px;
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 30%);
          mask-image: linear-gradient(to bottom, transparent, black 30%);
}
.tl { color: var(--ink-dim); font-size: 10.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Activity: a grey track with a soft white highlight passing through it. */
.scan { height: 2px; margin: 0 14px 10px; border-radius: 1px; background: var(--line); position: relative; overflow: hidden; }
.scan i {
  position: absolute; top: 0; bottom: 0; width: 38%; left: 31%;
  background: linear-gradient(90deg, transparent, rgba(242,246,250,.5), transparent);
  opacity: 0;
}
.chan[data-state="working"] .scan i { opacity: 1; animation: sweep 3.6s ease-in-out infinite alternate; }
@keyframes sweep { from { left: -20%; } to { left: 82%; } }

/* A question answered without leaving the room. Compact, because the strip is
   narrow and the answer is usually one word. */
.strip-ask { margin-top: 4px; }
.strip-ask label { font-size: 9px; text-transform: uppercase; letter-spacing: .12em; margin: 6px 0 3px; }
.strip-ask input[type=text], .strip-ask select, .strip-ask textarea {
  font-size: 11px; padding: 4px 6px;
}
.strip-ask .acts { margin-top: 8px; }

.ctlrow { display: flex; gap: 14px; padding: 2px 14px 10px; align-items: baseline; }
.ctlrow .spacer { margin-left: auto; }

/* ---------- focus: the strip widens in place ----------
 * Zooming is a change of scale, not a change of page: the others stay on
 * screen as slivers so the room never stops being the room. */
.stage.focused .chan:not(.big) { flex-basis: 46px; }
.stage.focused .chan:not(.big) :is(.brief, .machinezone, .cbody, .acts, .resolved, .ckind span:not(.pip), .cstate) { display: none; }
.stage.focused .chan:not(.big) .chead {
  flex-direction: column; align-items: center; gap: 6px; padding: 10px 4px;
  border-bottom: none; margin-bottom: 0;
}
.stage.focused .chan:not(.big) .cname {
  writing-mode: vertical-rl; font-size: 10.5px; font-weight: 500;
  color: var(--ink-soft); letter-spacing: .06em; max-height: 220px;
  background-image: none; padding-bottom: 0;
  animation: huetext 14s linear infinite;
}
.stage.focused .chan:not(.big)[data-state="working"] .chead::after {
  content: ""; width: 5px; height: 5px; border-radius: 50%; flex: none;
  background: var(--hot); animation: breathe 2.2s ease-in-out infinite; margin-top: 2px;
}
.stage.focused .chan:not(.big) .call { padding: 0 0 14px; margin-top: auto; display: flex; justify-content: center; }
.stage.focused .chan.big { flex: 1 1 0; min-width: 520px; }

.full { display: none; flex: 1; min-height: 0; flex-direction: column; }
.chan.big .full { display: flex; }
.chan.big :is(.brief, .machinezone, .call, .sig) { display: none; }

/* ---------- the dock: the complete map ---------- */
.dock {
  height: 40px; display: flex; align-items: center; gap: 6px; padding: 0 12px;
  border-top: 1px solid var(--line); overflow-x: auto; flex: none;
}
.dlabel, .glabel {
  font-size: 9px; text-transform: uppercase; letter-spacing: .16em;
  color: var(--ink-dim); margin-right: 6px; flex: none;
}
.chip {
  background: hsl(var(--h) 11% 11%); border: 1px solid var(--line-soft); border-radius: 4px;
  font: inherit; font-size: 10.5px; color: var(--ink-soft);
  padding: 4px 10px; cursor: pointer; flex: none;
  display: inline-flex; align-items: center; gap: 7px; position: relative; overflow: hidden;
}
.chip:hover { color: var(--ink); border-color: var(--ink-dim); }
.chip:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: 2px; }
.chip .kd { width: 5px; height: 5px; border-radius: 50%; flex: none; background: var(--line); }
/* Off the stage and asking for something: the chip says so where it is,
   rather than promoting itself and rearranging the room. */
.chip.needs::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: var(--spectrum); background-size: 300% 100%;
  animation: drift 16s linear infinite; opacity: .85;
}
.chip.needs .kd { animation: hue 9s linear infinite; }
.chip.work .kd { background: var(--hot); animation: breathe 2.2s ease-in-out infinite; }
.chip.dead { background: hsl(var(--h) 6% 8%); color: var(--ink-dim); }
.chip.dead .kd { background: #2b3036; border-radius: 1px; }
.chip.on { border-color: var(--ink-dim); color: var(--ink); }
.chip.on::after { content: "▴"; font-size: 8px; color: var(--ink-dim); }

.newsess { display: inline-flex; gap: 6px; align-items: center; margin-left: auto; flex: none; }
.newsess input { width: 12rem; padding: 3px 7px; font-size: 10.5px; }

/* ---------- graveyard: not "done for now" — done ---------- */
.grave {
  height: 32px; display: flex; align-items: center; gap: 8px; padding: 0 12px;
  border-top: 1px solid var(--line); overflow-x: auto; flex: none;
}
.gtab {
  background: none; border: 1px solid var(--line-soft); border-radius: 3px;
  font: inherit; font-size: 10.5px; color: var(--ink-dim);
  padding: 2px 9px; cursor: pointer; flex: none;
}
.gtab:hover { animation: huetext 12s linear infinite; border-color: var(--line); }
.gtab:focus-visible { outline: 1px solid var(--ink-soft); outline-offset: 2px; }

.rail {
  height: 26px; display: flex; align-items: center; gap: 16px; padding: 0 12px;
  border-top: 1px solid var(--line); color: var(--ink-dim); font-size: 10px; flex: none;
}
.rail .tag { margin-left: auto; letter-spacing: .1em; text-transform: uppercase; font-size: 9px; }

@media (prefers-reduced-motion: reduce) {
  .sig, .scan i, .cname, .chip::before, .chip .kd, .gtab:hover,
  .chan[data-state="working"] .machinezone, .chead::after {
    animation: none !important;
  }
  .chan { transition: none; }
  .chan[data-state="working"] .scan i { opacity: 1; }
  .chip.work .kd { opacity: 1; }
}
