/* ==========================================================================================
   The workbench's own stylesheet: where things go, and the look of what is its alone.
   Colour, type, shape and depth come from design/tokens.css; what a button, chip, badge, card
   or field looks like comes from design/components.css, a later layer that wins over this one.
   ========================================================================================== */
@layer legacy, components;
@layer legacy {

:root {
  --header-h: 66px;
  --drawer-w: 320px;
  --rail-w: 22rem;
  --rail-strip: 3.6rem;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  height: 100%;
  background: var(--wash);
  color: var(--ink);
  font: var(--text-base)/1.55 var(--font-ui);
  /* The closed sheets wait just past the screen's edge. Counted as page width, they made a
     phone lay the page out 800px wide and shrink it to fit; clipped, the page is the phone's
     width. (clip, where known, so the body does not become a scroll box of its own.) */
  overflow-x: hidden;
}
@supports (overflow: clip) {
  html, body { overflow-x: clip; }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.app {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  height: 100dvh;
  background: var(--wash);
}

.app[data-lang="zh"] {
  font-family: var(--font-ui);
}

.product-header {
  position: relative;
  z-index: 30;
  display: grid;
  grid-template-columns: 240px minmax(420px, 1fr) auto;
  align-items: center;
  gap: 20px;
  /* A literal, not `var(--header-h)`: that variable is measured from this element, so letting it
     also set the height here would hold the header at whatever it measured at the last width. */
  min-height: 66px;
  padding: 0 24px;
  background: rgba(250, 252, 251, 0.97);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 rgba(20, 45, 50, 0.02);
  backdrop-filter: blur(18px);
}

.product-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.evo-logo {
  width: 38px;
  height: 38px;
  flex: none;
}

.suite-name {
  color: var(--ink);
  /* The wordmark is the one serif in the product; every heading and sentence is the UI face. */
  font: 720 var(--text-lg)/1.05 var(--font-display);
  letter-spacing: -0.02em;
}

.suite-sub {
  margin-top: 3px;
  color: var(--muted);
  font-size: var(--text-xs);
  letter-spacing: 0.45px;
}

.top-nav {
  display: flex;
  align-self: center;
  justify-content: center;
  gap: 4px;
  height: 40px;
  padding: 3px;
  overflow: auto;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--wash);
}

.top-nav a {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 32px;
  padding: 0 13px;
  border-radius: var(--r-s);
  color: var(--subtle);
  text-decoration: none;
  font-size: var(--text-xs);
  font-weight: 650;
  white-space: nowrap;
}

.top-nav a:hover {
  color: var(--ink-2);
  background: var(--surface-2);
}

.top-nav a.active {
  color: var(--teal-ink);
  background: var(--surface);
  box-shadow: 0 1px 4px rgba(24, 58, 62, 0.08);
}

/* A tab appears when its page has something on it; one that arrives during a run eases in. */
.top-nav a[hidden] { display: none; }
/* Tabs that do not fit wait in the More menu at the end of the strip. */
.top-nav a.is-overflow { display: none; }
/* Crowded, the tabs drop their step numbers before any tab goes into More. */
.product-header.is-crowded .top-nav .nav-number { display: none; }
.nav-more {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 4px;
  height: 32px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--r-s);
  background: none;
  color: var(--muted);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}
.nav-more[hidden] { display: none; }
.nav-more:hover, .nav-more[aria-expanded="true"] { background: var(--surface); color: var(--ink); }
.nav-more:focus-visible { outline: 2px solid var(--teal); outline-offset: -2px; }
.nav-more-caret { font-size: var(--text-xs); }
.nav-more-menu {
  position: fixed;
  z-index: 80;
  display: flex;
  flex-direction: column;
  min-width: 180px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: 0 14px 36px rgba(24, 58, 62, 0.16);
}
.nav-more-menu[hidden] { display: none; }
.nav-more-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border: 0;
  border-radius: var(--r-s);
  background: none;
  color: var(--ink-2);
  font: 600 var(--text-sm)/1.2 var(--font-ui);
  text-align: start;
  cursor: pointer;
}
.nav-more-item:hover, .nav-more-item:focus-visible { background: var(--teal-wash); color: var(--teal-ink); outline: none; }
.nav-more-item .nav-number { color: var(--subtle); font-size: var(--text-xs); }
.top-nav a.is-arriving { animation: tab-arrive 0.7s ease-out; }
@keyframes tab-arrive {
  0% { opacity: 0; transform: translateY(-4px) scale(0.96); box-shadow: 0 0 0 0 rgba(42, 130, 107, 0); }
  60% { opacity: 1; transform: none; box-shadow: 0 0 0 4px rgba(42, 130, 107, 0.18); }
  100% { box-shadow: 0 0 0 0 rgba(42, 130, 107, 0); }
}

.nav-number {
  color: var(--faint);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

.top-nav a.active .nav-number { color: var(--teal); }

.header-actions {
  display: flex;
  justify-self: end;
  align-items: center;
  gap: 9px;
}

.language-switch {
  display: flex;
  padding: 3px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--wash);
}

.language-switch button {
  min-width: 38px;
  padding: 5px 8px;
  border: 0;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--subtle);
  font: 650 var(--text-xs)/1.2 var(--font-ui);
  cursor: pointer;
}

.language-switch button.active {
  color: var(--teal-deep);
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(27, 68, 68, 0.08);
}

.header-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface);
}

.header-meta small {
  display: block;
  color: var(--faint);
  font-size: var(--text-xs);
  letter-spacing: 1.4px;
}

.header-meta b {
  color: var(--ink-2);
  font-size: var(--text-xs);
  font-weight: 650;
}

/* How much of the board is busy, next to the run chip that names the run on screen. */
.slot-meter {
  padding: 2px 7px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-pill);
  background: var(--wash);
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: 650;
  letter-spacing: 0.2px;
  white-space: nowrap;
}

.slot-meter[hidden] { display: none; }

/* The RUN chip is the switcher's handle: the same slot in the header, now a control. */
.run-switch {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.run-switch:hover b,
.run-switch[aria-expanded="true"] b { color: var(--teal); }

.run-switch-caret {
  color: var(--faint);
  font-size: var(--text-xs);
}

.run-list-backdrop {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  z-index: 25;
}

.run-list-backdrop[hidden] { display: none; }

.run-list {
  position: fixed;
  top: calc(var(--header-h) + 6px);
  right: 24px;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: min(26rem, calc(100vw - 32px));
  max-height: min(30rem, 70vh);
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: 0 12px 32px rgba(23, 39, 48, 0.16);
}

.run-list[hidden] { display: none; }

.run-list-head {
  padding: 2px 4px 6px;
  color: var(--faint);
  font: 700 var(--text-xs)/1 var(--font-ui);
  letter-spacing: 0.14em;
}

.run-list ul {
  margin: 0;
  padding: 0;
  overflow: auto;
  list-style: none;
}

/* Starting a new analysis is the one action in this panel that is not a run, so it is drawn as
   an action row rather than a run row. */
.run-new {
  width: 100%;
  margin: 0 0 6px;
  padding: 8px 10px;
  border: 1px dashed var(--teal);
  border-radius: var(--r-s);
  background: var(--wash);
  color: var(--teal);
  font: 700 var(--text-xs)/1 var(--font-ui);
  text-align: left;
  cursor: pointer;
}

.run-new:hover { background: var(--teal-wash); }

.run-row-wrap {
  display: flex;
  align-items: stretch;
  gap: 6px;
}

.run-row-wrap + .run-row-wrap { margin-top: 4px; }

/* The run's name on the first line, its state on the second: the name is a person's name for it
   now ("登革病毒 · Nextstrain dengue/all/genome"), not a short id, and beside it the state was
   squeezed to nothing. */
.run-row {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px 8px;
  padding: 8px 10px;
  border: 1px solid transparent;
  border-radius: var(--r-s);
  background: var(--surface-2);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.run-row:hover { border-color: var(--teal); }

.run-row.is-current {
  background: var(--wash);
  border-color: var(--teal);
  cursor: default;
}

.run-row-id {
  min-width: 0;
  color: var(--ink);
  font: 650 var(--text-sm)/1.35 var(--font-ui);
  overflow-wrap: anywhere;
}

.run-row-label {
  min-width: 0;
  overflow: hidden;
  color: var(--muted);
  font-size: var(--text-xs);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.run-row-badges {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.run-badge {
  padding: 2px 6px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  color: var(--subtle);
  font: 650 var(--text-xs)/1.4 var(--font-ui);
}

.run-badge.is-board { background: var(--teal); color: var(--surface); }
.run-badge.is-current { background: var(--line-soft); color: var(--teal-ink); }
.run-badge.is-queued { background: var(--amber-wash); color: var(--amber-ink); }
.run-badge.is-gate { background: var(--red-wash); color: var(--red); }
.run-badge.is-unreadable { background: var(--surface-3); color: var(--subtle); }
.run-badge.is-archived { background: var(--surface-3); color: var(--muted); }

.run-row-release {
  align-self: center;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--amber-ink);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.run-row-release:hover {
  border-color: var(--amber);
  color: var(--amber);
}

.run-list-empty {
  padding: 8px 6px;
  color: var(--faint);
  font-size: var(--text-xs);
}

/* The assistant sits beside the pages rather than inside one, so switching pages cannot unmount
   it. Only one `.page` is ever displayed (`.page[hidden]` is `display: none !important`), so
   auto-placement keeps it in the second column whatever page it is. */
.content {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
}

/* Collapsed to a strip, and absent entirely on the chat page, which is the full conversation. */
body[data-rail="collapsed"] .content {
  grid-template-columns: var(--rail-strip) minmax(0, 1fr);
}

body[data-page="chat"] .content {
  grid-template-columns: minmax(0, 1fr);
}

body[data-page="chat"] .assistant-rail {
  display: none;
}

/* The assistant: a card beside the page rather than over it. It keeps the weight of a floating
   window — rounded, shadowed, arriving with a short rise — while staying in the layout, so what
   it says about the report on screen cannot drift from the report on screen. */
.assistant-rail {
  grid-column: 1;
  grid-row: 1 / -1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  margin: 16px 0 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: 0 10px 30px rgba(23, 39, 48, 0.07);
  overflow: hidden;
  animation: rail-in 180ms ease-out both;
}

/* Page 01 keeps the rail out of the layout — the whole conversation is the page. A pending
   decision lives only in the rail's 待办 tab, so the transcript marker's jump brings the rail
   in as an overlay from the right rather than pretending the card is somewhere it is not. */
body[data-page="chat"][data-rail-peek="open"] .assistant-rail {
  display: flex;
  position: fixed;
  top: var(--header-h);
  right: 0;
  bottom: 0;
  left: auto;
  z-index: 50;
  width: min(26rem, 92vw);
  margin: 0;
  border-radius: 18px 0 0 18px;
  box-shadow: -18px 0 44px rgba(23, 39, 48, 0.16);
  transform: none;
  animation: none;
}

/* A collapsed rail peeking in over page 01 still has to work: the collapse belongs to the
   layout the peek is not part of, so the head and body come back for the overlay's duration. */
body[data-rail="collapsed"][data-rail-peek="open"] .rail-head,
body[data-rail="collapsed"][data-rail-peek="open"] .rail-body { display: flex; }

body[data-rail="collapsed"][data-rail-peek="open"] .rail-expand { display: none; }

@keyframes rail-in {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to { opacity: 1; transform: none; }
}

/* With the rail in the layout the page's gutter only has to be a gutter: a generous one would
   read as a second, empty column between the two. Set as the token, so every page (and the
   report inside a page's frame) takes the same one. */
body[data-rail="expanded"] {
  --page-gutter: var(--space-6);
}

.rail-head {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}

/* The rail's two halves: 待办 is what the run is waiting on, 助手 is the conversation. The tabs
   are the head's identity now — there is no second title for the same column. */
.rail-tabs {
  display: flex;
  flex: 0 0 auto;
  gap: 4px;
  min-width: 0;
}

.rail-tab {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border: 1px solid transparent;
  border-radius: var(--r-s);
  background: transparent;
  color: var(--ink-2);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.rail-tab:hover { color: var(--teal); }

.rail-tab.is-active {
  border-color: var(--teal-line);
  background: var(--surface-3);
  color: var(--teal);
}

.rail-tab-badge {
  padding: 1px 6px;
  border-radius: var(--r-pill);
  background: var(--amber);
  color: var(--surface);
  font: 700 var(--text-xs)/1.4 var(--font-ui);
}

.rail-tab-badge[hidden] { display: none; }

.rail-context {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 400;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rail-collapse,
.rail-expand {
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

/* An icon, not a word: the tabs and the page's name need the head's width more. */
.rail-collapse { flex: 0 0 auto; display: inline-grid; place-items: center; width: 26px; height: 26px; padding: 0; }
.rail-collapse svg { width: 14px; height: 14px; }
[dir="rtl"] .rail-collapse svg { scale: -1 1; }

.rail-collapse:hover { border-color: var(--teal); color: var(--teal); }

/* The strip's button is the whole card, so the default ring would draw around the card rather
   than around the control inside it. */
.rail-collapse:focus-visible,
.rail-expand:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: -3px;
}

/* Collapsed, the rail keeps a strip of itself: a way back, and a reminder that the conversation
   is still there. */
.rail-expand {
  display: none;
  flex: 1;
  align-items: center;
  justify-content: center;
  padding: 10px 6px;
  border-radius: var(--r-m);
  writing-mode: vertical-rl;
  letter-spacing: 0.12em;
}

body[data-rail="collapsed"] .rail-head,
body[data-rail="collapsed"] .rail-body { display: none; }

body[data-rail="collapsed"] .rail-expand { display: flex; }
/* The strip is not one of the icon buttons (web/design/components.css): it is shown by the rail's
   state, not by `hidden`, and it is the height of the rail. */
.rail-expand:hover { border-color: var(--teal); background: var(--teal-wash); color: var(--teal-ink); }

body[data-rail="collapsed"] .assistant-rail { margin-left: 12px; }

.rail-body {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
}

/* The two tab panels share the body. Each is the column the body was, so switching tabs changes
   what fills it, never the shape of it. */
.rail-assistant {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 10px;
}

.rail-assistant[hidden] { display: none; }

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

.rail-inbox[hidden] { display: none; }

.rail-inbox-list {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 8px;
  overflow: auto;
}

.rail-inbox-empty {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 1.6;
}

.rail-panels {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  gap: 8px;
}

.rail-transcript {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 8px;
  overflow: auto;
}

.rail-intro {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 1.6;
}

.rail-panels {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  gap: 6px;
}

/* Folded away by default: the rail is a column of conversation first, and the run's numbers are
   what the reader opens when the question is about them. */
.rail-panel {
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface-2);
  overflow: hidden;
}

.rail-panel.is-open { background: var(--surface); }

.rail-panel-head {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  font: 650 var(--text-xs)/1.3 var(--font-ui);
  text-align: left;
  cursor: pointer;
}

.rail-panel-head:hover { color: var(--teal); }

.rail-panel-caret {
  color: var(--faint);
  font-size: var(--text-xs);
  transition: transform 0.16s ease;
}

.rail-panel-head[aria-expanded="true"] .rail-panel-caret { transform: rotate(180deg); }

.rail-panel-body {
  max-height: 15rem;
  padding: 0 10px 9px;
  overflow: auto;
}

.rail-panel-body[hidden] { display: none; }

.rail-fact {
  display: flex;
  gap: 8px;
  margin: 0 0 4px;
  font-size: var(--text-xs);
  line-height: 1.45;
}

.rail-fact-label {
  flex: 0 0 38%;
  color: var(--subtle);
}

.rail-fact-value {
  flex: 1;
  min-width: 0;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.rail-panel-empty {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-xs);
  line-height: 1.5;
}

.rail-ledger {
  margin: 0;
  padding-left: 16px;
  font-size: var(--text-xs);
}

.rail-bubble {
  max-width: 92%;
  padding: 8px 10px;
  border-radius: var(--r-m);
  font-size: var(--text-sm);
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.rail-bubble.user {
  align-self: flex-end;
  background: var(--surface-3);
  color: var(--teal-ink);
}

.rail-bubble.assistant {
  background: var(--wash);
  color: var(--ink);
}

.rail-bubble.error {
  background: var(--red-wash);
  color: var(--red);
}

.rail-bubble.marker {
  align-self: center;
  background: transparent;
  color: var(--muted);
  font-size: var(--text-xs);
  text-align: center;
}

/* The same cards on the rail's narrower column. They keep their shape and their controls and
   give up the padding and the type size the main column can afford; without this they would
   overflow a 22rem rail and push their own buttons off the right edge. Decision cards live in
   the rail's 待办 tab now — the inbox is their only home, so it is the column they fit. */
.rail-transcript .deliberation,
.rail-transcript .plan-card,
.rail-inbox .decision-card,
.rail-transcript .upload-card {
  max-width: 100%;
  padding: 10px 11px 8px;
  /* A failure note names a bare identifier (median_gap_fraction_above_high). There is no space
     to wrap at, so it would widen the card instead of the card wrapping it. */
  overflow-wrap: anywhere;
}

.rail-transcript .plan-card h2,
.rail-inbox .decision-card h2,
.rail-transcript .upload-card h2 {
  margin: 0 0 6px;
  font-size: var(--text-md);
}

.rail-transcript .delib-explain,
.rail-transcript .delib-root {
  margin-bottom: 6px;
  font-size: var(--text-xs);
}

.rail-transcript .delib-stage {
  padding: 2px 6px;
  font-size: var(--text-xs);
}

.rail-transcript .delib-branch {
  gap: 6px;
  margin-bottom: 6px;
  padding: 7px 8px;
}

.rail-transcript .decision-choices,
.rail-inbox .decision-choices {
  gap: 6px;
}

.rail-inbox .figure-gallery img {
  max-width: 100%;
}

.rail-choices {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  gap: 6px;
}

.rail-choices[hidden] { display: none; }

.rail-choice-chip {
  padding: 6px 10px;
  border: 1px solid var(--teal);
  border-radius: var(--r-pill);
  background: var(--wash);
  color: var(--teal);
  font: 650 var(--text-xs)/1.3 var(--font-ui);
  cursor: pointer;
}

.rail-choice-chip:hover { background: var(--teal-wash); }

.rail-composer { flex: 0 0 auto; }

/* The header's way in to the sheet, below the breakpoint only. */
.rail-drawer {
  display: none;
  align-items: center;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.rail-drawer[aria-expanded="true"] {
  border-color: var(--teal);
  color: var(--teal);
}

.rail-backdrop {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  z-index: 20;
  background: rgba(23, 39, 48, 0.26);
}

.rail-backdrop[hidden] { display: none; }

.page {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: var(--page-top) var(--page-gutter) 28px;
}

.chat-page {
  align-items: center;
  padding: 20px 24px 24px;
}

.chat-stage {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  width: 100%;
  max-width: 42rem;
  flex: 1;
  min-height: 0;
}

.chat-page[data-mode="session"] .chat-stage,
.chat-page[data-mode="gate"] .chat-stage {
  max-width: min(1500px, 100%);
  grid-template-columns: minmax(0, 1fr) clamp(20rem, 26vw, 30rem);
}

.chat-page[data-mode="running"] {
  align-items: stretch;
  padding: 18px clamp(24px, 3vw, 48px) 22px;
}

.chat-page[data-mode="running"] .chat-stage {
  max-width: min(1500px, 100%);
  margin: 0 auto;
  width: 100%;
  grid-template-columns: minmax(0, 1fr);
}

.chat-column {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: 0 10px 30px rgba(23, 39, 48, 0.05);
  overflow: hidden;
}

.inspector {
  display: none;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  gap: 12px;
}

.chat-page[data-mode="session"] .inspector {
  display: flex;
}

/* Inspector as a right-hand sheet below 1100px; the rules live in the 1100px block. */
.inspector-toggle {
  display: none;
  align-items: center;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.inspector-toggle[aria-expanded="true"] {
  border-color: var(--teal);
  color: var(--teal);
}

.inspector-backdrop {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  z-index: 20;
  background: rgba(23, 39, 48, 0.26);
}

.inspector-backdrop[hidden] { display: none; }

/* ---- the files drawer: a run's files, one pull away ---------------------------------------
   A right-side overlay like the narrow-screen sheets, but available at every width: the files
   belong to the run, not to any one page. The transform is the closed state; `body[data-files]`
   is the open one, so the drawer slides rather than appearing. */
.files-open {
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.files-open:not([hidden]) { display: inline-flex; }

.files-open[hidden] { display: none; }

.files-open:hover,
.files-open[aria-expanded="true"] {
  border-color: var(--teal);
  color: var(--teal);
}

.files-backdrop {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  z-index: 35;
  background: rgba(23, 39, 48, 0.26);
}

.files-backdrop[hidden] { display: none; }

.files-drawer {
  position: fixed;
  top: var(--header-h);
  right: 0;
  bottom: 0;
  z-index: 45;
  display: flex;
  flex-direction: column;
  width: min(100vw, max(420px, 40vw));
  border-left: 1px solid var(--line);
  background: var(--surface);
  box-shadow: -18px 0 44px rgba(23, 39, 48, 0.14);
  transform: translateX(calc(100% + 72px));
  transition: transform 0.26s ease;
}

body[data-files="open"] .files-drawer { transform: none; }

.files-head {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}

.files-tabs {
  display: flex;
  gap: 4px;
}

.files-tab {
  padding: 5px 10px;
  border: 1px solid transparent;
  border-radius: var(--r-s);
  background: transparent;
  color: var(--ink-2);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.files-tab:hover { color: var(--teal); }

.files-tab.is-active {
  border-color: var(--teal-line);
  background: var(--surface-3);
  color: var(--teal);
}

.files-close {
  padding: 4px 9px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.files-close:hover {
  border-color: var(--teal);
  color: var(--teal);
}

.files-body {
  display: flex;
  flex: 1;
  min-height: 0;
}

.files-list-pane {
  display: flex;
  flex: 1;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  overflow: auto;
  padding: 12px 14px;
}

.files-groups {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.files-group {
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface-2);
  overflow: hidden;
}

.files-group > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  color: var(--ink-2);
  font: 650 var(--text-xs)/1.3 var(--font-ui);
  cursor: pointer;
  list-style: none;
}

.files-group > summary::-webkit-details-marker { display: none; }

.files-group > summary:hover { color: var(--teal); }

.files-group-count {
  color: var(--faint);
  font-weight: 400;
}

.files-group-rows {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 6px 6px;
  background: var(--surface);
}

.files-empty {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 1.6;
}

.file-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px;
  border-radius: var(--r-s);
  font-size: var(--text-sm);
}

.file-row:hover { background: var(--wash); }

.file-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  color: var(--ink);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-row.is-dir .file-name { font-weight: 650; }

.file-stage {
  flex: 0 0 auto;
  padding: 1px 6px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  color: var(--teal);
  font: 650 var(--text-xs)/1.5 var(--font-ui);
}

.file-meta {
  flex: 0 0 auto;
  color: var(--faint);
  font-size: var(--text-xs);
  white-space: nowrap;
}

.file-actions {
  display: flex;
  flex: 0 0 auto;
  gap: 4px;
}

.file-action {
  padding: 3px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-xs)/1.3 var(--font-ui);
  text-decoration: none;
  cursor: pointer;
}

.file-action:hover {
  border-color: var(--teal);
  color: var(--teal);
}

.files-tree {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 8px;
}

.files-tree[hidden] { display: none; }

.files-crumb {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px;
  font-size: var(--text-xs);
}

.files-crumb button {
  padding: 2px 6px;
  border: 0;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--teal);
  font: 650 var(--text-xs)/1.4 var(--font-ui);
  cursor: pointer;
}

.files-crumb button:hover { background: var(--surface-3); }

.files-crumb-sep { color: var(--faint); }

.files-dir-list {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 2px;
  overflow: auto;
}

.files-preview {
  display: flex;
  flex: 0 0 46%;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  border-left: 1px solid var(--line);
  background: var(--surface-2);
}

.files-preview[hidden] { display: none; }

.files-preview-head {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
}

.files-preview-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-size: var(--text-sm);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.files-preview-size {
  flex: 0 0 auto;
  color: var(--faint);
  font-size: var(--text-xs);
}

.files-preview-download {
  flex: 0 0 auto;
  color: var(--teal);
  font: 650 var(--text-xs)/1.4 var(--font-ui);
}

.files-preview-close {
  flex: 0 0 auto;
  padding: 2px 7px;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
}

.files-preview-body {
  flex: 1;
  min-height: 0;
  margin: 0;
  padding: 10px 12px;
  overflow: auto;
  color: var(--ink);
  font: var(--text-xs)/1.55 var(--font-mono);
  white-space: pre-wrap;
  word-break: break-all;
}
.files-preview-body.is-table { padding: 0; white-space: normal; word-break: normal; }
.files-table {
  border-collapse: separate;
  border-spacing: 0;
  font: var(--text-xs)/1.45 var(--font-ui);
  font-variant-numeric: tabular-nums;
}
.files-table th,
.files-table td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--line-soft);
  text-align: start;
  white-space: nowrap;
}
.files-table th {
  position: sticky;
  top: 0;
  background: var(--surface-2);
  color: var(--ink-2);
  font-weight: var(--weight-medium);
}
.files-table tbody tr:hover { background: var(--teal-wash); }
.files-table-more { margin: 0; padding: 10px 12px; color: var(--muted); font: var(--text-xs)/1.5 var(--font-ui); }

/* The talk stays open while a run executes: the board reports the run, the chat stays usable.
   Only "use example data" is meaningless once a run is under way. */
.chat-page[data-mode="running"] #use-example {
  display: none;
}

.chat-page[data-mode="running"] .run-board {
  display: flex;
  flex: 0 0 auto;
  max-height: 46vh;
  overflow-y: auto;
}

.chat-page[data-mode="running"] .transcript,
.chat-page[data-mode="running"] .composer-dock {
  display: flex;
}

.run-board {
  display: none;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  padding: 22px 28px 20px;
  overflow: hidden;
}

.run-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.run-kicker {
  margin: 0 0 8px;
  color: var(--teal);
  font: 700 var(--text-xs)/1 var(--font-ui);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

#run-headline {
  margin: 0 0 6px;
  font: 600 var(--text-4xl)/1.2 var(--font-ui);
}

.run-count {
  margin: 0;
  color: var(--muted);
}

/* Elapsed and remaining time for the running step, shown next to the progress it belongs to. */
.run-eta {
  margin: 4px 0 0;
  color: var(--blue);
  font: 650 var(--text-xs)/1.4 "SFMono-Regular", Menlo, monospace;
  font-variant-numeric: tabular-nums;
}

.run-eta[hidden] { display: none; }

/* Independent-review badge in the run-board header; state comes from the
   reviews registry and the tooltip carries node, verdict, and the first checks. */
.review-badge {
  display: inline-block;
  margin: 6px 0 0;
  padding: 3px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--muted);
  font: 700 var(--text-xs)/1.6 var(--font-ui);
  cursor: default;
}
.review-badge[hidden] { display: none; }
.review-badge.is-running { color: var(--blue); border-color: var(--blue-line); background: var(--blue-wash); animation: evt-review-pulse 1.6s ease-in-out infinite; }
.review-badge.is-consistent { color: var(--teal-deep); border-color: var(--teal-line); background: var(--teal-wash); }
.review-badge.is-partial { color: var(--amber-ink); border-color: var(--amber-line); background: var(--amber-wash); }
.review-badge.is-inconsistent,
.review-badge.is-failed { color: var(--red-ink); border-color: var(--red-line); background: var(--red-wash); }
@keyframes evt-review-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
/* "Skills validated" evidence chip beside the brand name, on the name's own line, so the brand
   stays two lines tall and fits the header; tooltip-only. */
.suite-name-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.validation-badge {
  display: inline-block;
  flex: none;
  padding: 0 7px;
  border: 1px solid var(--teal-line);
  border-radius: var(--r-pill);
  background: var(--teal-wash);
  color: var(--teal-deep);
  font: 700 var(--text-xs)/1.7 var(--font-ui);
  letter-spacing: 0.3px;
  cursor: default;
}
.validation-badge[hidden] { display: none; }

/* Collapsible rule citation at the bottom of a gate card. */
.decision-card .rule-source {
  margin-top: 10px;
  border-top: 1px dashed var(--line);
  padding-top: 6px;
  font-size: var(--text-xs);
  color: var(--muted);
}
.decision-card .rule-source summary {
  cursor: pointer;
  font-weight: 650;
  color: var(--blue);
}
.decision-card .rule-source-body p { margin: 6px 0 4px; }
.decision-card .rule-source-body a { color: var(--teal); word-break: break-all; }
.decision-card .principle-block { margin-top: 8px; padding-top: 6px; border-top: 1px solid var(--line); }
.decision-card .principle-head { font-weight: 600; color: var(--ink); }
.decision-card .principle-coverage, .decision-card .principle-provenance { color: var(--muted); font-size: var(--text-sm); }
/* The questions a result opens: one line each, what the run shows and how to go further under it. */
.concl-reviewer .reviewer-list { display: grid; margin: 0; border-top: 1px solid var(--line-soft); }
.concl-reviewer .reviewer-question { border-bottom: 1px solid var(--line-soft); }
.concl-reviewer .reviewer-ask {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 9px 0;
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: 600;
  line-height: 1.5;
  list-style: none;
  cursor: pointer;
}
.concl-reviewer .reviewer-ask::-webkit-details-marker { display: none; }
.concl-reviewer .reviewer-ask::before,
.concl-fold > summary::after {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: translateY(-2px) rotate(-45deg);
  transition: transform 0.15s ease;
}
.concl-reviewer .reviewer-question[open] > .reviewer-ask::before,
.concl-fold[open] > summary::after { transform: translateY(-3px) rotate(45deg); }
.concl-reviewer .reviewer-ask:hover { color: var(--teal-ink); }
.concl-reviewer .reviewer-question > p { margin: 0 0 6px 14px; color: var(--ink-2); font-size: var(--text-sm); line-height: 1.55; }
.concl-reviewer .reviewer-question > p:last-child { margin-bottom: 10px; }
.concl-reviewer .reviewer-principle, .concl-reviewer .principle-provenance { color: var(--muted); font-size: var(--text-sm); }
.concl-reviewer .principle-provenance { margin: 8px 0 0; font-size: var(--text-xs); }

.bubble-link {
  color: var(--teal);
  font-weight: 650;
}

.run-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 16px 0 14px;
}

.run-progress-track {
  flex: 1;
  height: 8px;
  overflow: hidden;
  border-radius: var(--r-pill);
  background: var(--line-soft);
}

.run-progress-fill {
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--teal), var(--teal));
  transition: width 0.4s ease;
}

.run-progress-label {
  min-width: 3.2em;
  color: var(--teal);
  font: 700 var(--text-sm)/1 var(--font-ui);
  text-align: right;
}

.run-split {
  display: grid;
  grid-template-columns: minmax(240px, 0.95fr) minmax(280px, 1.15fr);
  /* Both panes keep a height that shows a border, a title and a few lines. Stacked on a narrow
     screen they would otherwise be squeezed to nothing by the board's cap, and a pane with no
     height shows neither its list nor its log. The board scrolls whatever this costs. */
  grid-auto-rows: minmax(120px, auto);
  gap: 18px;
  min-height: 0;
  flex: 1;
}

@media (max-width: 860px) {
  .run-split {
    grid-template-columns: 1fr;
  }
}

.run-error {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: var(--r-s);
  background: var(--red-wash);
  color: var(--red);
  font-size: var(--text-sm);
  white-space: pre-wrap;
}

.run-steps {
  margin: 0;
  padding: 0;
  overflow: auto;
  list-style: none;
}

.run-detail {
  display: flex;
  min-height: 0;
  flex-direction: column;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--wash);
  /* The panel contains its own log: a log taller than the panel would otherwise draw outside
     the border, and against the board's cap that reads as a sliced panel. */
  overflow: hidden;
}

.run-detail-kicker {
  margin: 0 0 4px;
  color: var(--teal);
  font: 700 var(--text-xs)/1 var(--font-ui);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

#run-detail-title {
  margin: 0 0 10px;
  font: 600 var(--text-lg)/1.3 var(--font-ui);
}

.run-log {
  flex: 1;
  /* Fills the panel and scrolls inside it, so the panel's border always closes. */
  min-height: 0;
  margin: 0;
  overflow: auto;
  color: var(--ink-2);
  font: var(--text-xs)/1.5 var(--font-mono);
  white-space: pre-wrap;
  word-break: break-word;
}

.run-steps li {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 8px 6px;
  border-bottom: 1px solid var(--surface-3);
  color: var(--subtle);
  cursor: pointer;
}

.run-steps li.active-log {
  background: var(--wash);
  border-radius: var(--r-s);
}

.run-steps li .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--line);
}

.run-steps li.complete { color: var(--ink); }
.run-steps li.complete .dot { background: var(--teal); }
.run-steps li.running { color: var(--teal); font-weight: 700; }
.run-steps li.running .dot {
  background: var(--teal);
  animation: pulse 1s ease-in-out infinite;
}
.run-steps li.failed { color: var(--red); }
.run-steps li.failed .dot { background: var(--red); }

.run-steps li .node-badge {
  font-size: var(--text-xs);
  line-height: 1.6;
  padding: 0 7px;
  border-radius: var(--r-s);
  background: var(--blue-wash);
  color: var(--teal);
  border: 1px solid var(--line);
  white-space: nowrap;
}

.page[hidden] { display: none !important; }

/* Every page's title, the workbench's own and the reports' alike: the UI face, one size. */
.page-title {
  margin: 0 0 12px;
  color: var(--ink);
  font: var(--weight-strong) var(--text-3xl)/var(--leading-tight) var(--font-ui);
  letter-spacing: -0.01em;
}

.placeholder {
  margin: 0;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--muted);
  font: var(--text-base)/1.55 var(--font-ui);
}

/* A report page whose artefact the run has not written yet. The page is otherwise blank, so the
   card is centred rather than pinned to a corner: a lone block at the top of a white page reads
   as something that failed to load, and a reader who has never run this cannot tell whether they
   are meant to wait or to do something. */
/* `hidden` is only `display: none` from the UA sheet, so a rule that gives the card a layout
   would otherwise keep it on screen after the report it stands in for has been written. */
.stage-next[hidden] {
  display: none;
}

.stage-next {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 28px 24px;
  text-align: center;
}

.stage-next > * {
  max-width: 40rem;
}

.stage-next-kicker {
  margin: 0;
  color: var(--teal);
  font: 650 var(--text-xs)/1.4 "SFMono-Regular", Menlo, monospace;
  letter-spacing: 0.04em;
}

.stage-next-line {
  margin: 0;
  color: var(--ink);
  font: 700 var(--text-2xl)/1.35 var(--font-ui);
}

.stage-next-why {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-base);
  line-height: 1.6;
}

.stage-next-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.stage-next-go {
  padding: 9px 18px;
  border: 1px solid var(--teal);
  border-radius: var(--r-pill);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-base)/1.2 inherit;
  cursor: pointer;
}

.stage-next-go:hover {
  background: var(--teal-deep);
}

.stage-next-here {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-sm);
}

.stage-page,
.preview-page {
  padding: 0;
}

.stage-frame,
#preview-frame {
  flex: 1;
  width: 100%;
  min-height: 0;
  border: 0;
  background: var(--surface);
}

/* A report page is one of the workbench's pages: the workbench draws its head (title, what the
   page answers, the page's sections as tabs) and the report below keeps to its content, on the
   same ground and from the same left edge (workbench/app.py, _embedded). */
.stage-frame { background: var(--wash); }
.stage-head {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  padding: var(--page-top) var(--page-gutter) var(--space-3);
}
.stage-head .page-title { margin: 0; }
.stage-sub {
  margin: 0;
  max-width: 60rem;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: var(--leading);
}
.stage-head :is(.stage-tabs, .trees-switch) { margin-top: var(--space-2); }

/* The preview is a page like the others: its head carries the title, the section tabs and the
   export, and the manuscript below sits on the page's ground. */
.stage-head-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3) var(--space-6);
  flex-wrap: wrap;
  width: 100%;
}
.stage-head-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.preview-stage {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.preview-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.preview-toolbar a {
  color: var(--teal-deep);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

/* One reading column for the conversation: the messages, the next-step card under them and the
   composer share a width and a left edge. The messages ran from the page's left edge while the
   card and the composer were centred at two other widths, three edges in one view. */
.chat-page { --chat-col: 52rem; }

.transcript {
  flex: 1;
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 20px 20px 12px;
  padding-inline: max(20px, calc((100% - var(--chat-col)) / 2));
}
/* A short conversation sits on the composer, as a messenger's does, instead of at the top with
   an empty field between it and where the next word is typed. A long one scrolls as before: an
   auto margin in a scrolling column only takes space that is spare. */
.chat-page:not([data-mode="welcome"]) .transcript::before { content: ""; flex: none; margin-top: auto; }

.empty-state {
  margin: auto;
  max-width: 26rem;
  text-align: center;
  padding: 12px 8px 24px;
}

.empty-kicker {
  margin: 0 0 8px;
  color: var(--teal);
  font: 700 var(--text-xs)/1 var(--font-ui);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* The welcome's title is a page title, one size up: the UI face in every language (the display
   face leant in italics only suited Latin, and Japanese, Korean or Arabic came out slanted). */
.empty-state h1 {
  margin: 0 0 10px;
  color: var(--ink);
  font: var(--weight-strong) var(--text-4xl)/1.25 var(--font-ui);
  letter-spacing: -0.01em;
}

.empty-state p {
  margin: 0 0 16px;
  color: var(--muted);
  font-size: var(--text-base);
}

.choice-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.starter-chip,
.choice-chip,
.monitor-chip {
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-sm)/1.2 var(--font-ui);
  cursor: pointer;
}

.starter-chip:hover,
.choice-chip:hover,
.monitor-chip:hover {
  border-color: var(--teal);
  color: var(--teal);
  background: var(--teal-wash);
}

.composer-dock {
  padding: 0 20px 14px;
  background: linear-gradient(180deg, rgba(255,255,255,0), var(--surface) 18px);
}

.choice-row {
  justify-content: flex-start;
  padding: 0 4px 10px;
}

/* One composer shape everywhere (page 01 and the rail): a pill holding the text and the send
   button. The button is exactly one line of text tall, so on one line the two share a centre
   line; a longer message grows the box upward and the button stays on its last line. */
.composer,
.rail-composer {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 6px 6px 6px 16px;
  border: 1px solid var(--line);
  border-radius: 23px;
  background: var(--wash);
}

.composer {
  width: min(100%, var(--chat-col, 52rem));
  margin: 0 auto;
}

.composer textarea,
.rail-composer textarea {
  box-sizing: border-box;
  flex: 1;
  min-width: 0;
  height: 34px;
  min-height: 34px;
  max-height: 120px;
  padding: 7px 0;
  overflow-y: hidden;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: var(--text-base);
  line-height: 20px;
  resize: none;
  outline: none;
}

.composer button,
.rail-composer button {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  height: 34px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--r-l);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-base)/1 var(--font-ui);
  cursor: pointer;
}

.bubble {
  max-width: min(680px, 92%);
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  white-space: pre-wrap;
  word-break: break-word;
}

.bubble.user {
  align-self: flex-end;
  background: var(--teal-wash);
  border-color: var(--teal-line);
}

.bubble.assistant { align-self: flex-start; }

.bubble.question {
  align-self: flex-start;
  border-left: 3px solid var(--teal);
}

.bubble.error {
  align-self: stretch;
  background: var(--amber-wash);
  border-color: var(--amber);
}

.bubble.marker {
  align-self: center;
  max-width: 100%;
  padding: 5px 12px;
  border-style: dashed;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--muted);
  font-size: var(--text-xs);
  text-align: center;
}

@keyframes marker-flash {
  0%, 55% { background: var(--amber-wash); border-color: var(--amber); }
  100% { background: transparent; }
}

/* The card's way back to the conversation it came from. */
.decision-context {
  margin: 0 0 8px;
  padding: 3px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-xs)/1.4 var(--font-ui);
  cursor: pointer;
}

.decision-context:hover {
  border-color: var(--teal);
  color: var(--teal);
}

.decision-card.is-done .decision-context { display: none; }

.run-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  padding: 8px 0 0;
}

.run-actions button {
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-xs)/1 var(--font-ui);
  cursor: pointer;
}

.run-actions button:hover {
  border-color: var(--teal);
  color: var(--teal);
}

#change-input {
  border-color: var(--amber);
  color: var(--amber);
}

.thinking {
  display: flex;
  align-items: center;
  gap: 10px;
  align-self: flex-start;
  padding: 10px 14px;
  border: 1px dashed var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  color: var(--muted);
  font-size: var(--text-sm);
}

.thinking-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--teal);
  animation: pulse 1s ease-in-out infinite;
}

.thinking-dot:nth-child(2) { animation-delay: 0.15s; }
.thinking-dot:nth-child(3) { animation-delay: 0.3s; }

@keyframes pulse {
  0%, 100% { opacity: 0.25; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1); }
}

.step-progress {
  align-self: stretch;
  padding: 0 4px;
  color: var(--teal);
  font: 700 var(--text-xs)/1.4 var(--font-ui);
}

.deliberation {
  align-self: stretch;
  padding: 12px 14px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}

.step-card.is-done {
  opacity: 0.72;
}

.step-card.is-done .delib-branch {
  cursor: default;
}

/* Once answered, the card shows what was chosen; the recommendation it led with steps back. */
.delib-branch.is-chosen,
.step-card.is-done .delib-branch.is-chosen {
  border-color: var(--teal);
  background: var(--teal-wash);
  box-shadow: 0 0 0 1px var(--teal);
}
.step-card.is-done .delib-branch.pick:not(.is-chosen) { box-shadow: none; background: var(--surface-2); border-color: var(--line); }
.step-card.is-done .delib-branch:hover:not(.is-chosen) { border-color: var(--line); background: var(--surface-2); }

.delib-kicker {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}

.delib-stage {
  padding: 3px 8px;
  border-radius: var(--r-pill);
  background: var(--teal-wash);
  color: var(--teal);
  font: 700 var(--text-xs)/1.4 var(--font-ui);
}

.delib-stage.is-live {
  animation: stageflash 1.2s ease;
}

@keyframes stageflash {
  from { background: var(--teal); color: var(--surface); }
  to { background: var(--teal-wash); color: var(--teal); }
}

.delib-explain {
  margin: 0 0 10px;
  color: var(--muted);
  font-size: var(--text-sm);
}

.delib-root {
  font-size: var(--text-sm);
  color: var(--muted);
  margin-bottom: 8px;
}

.delib-branch {
  display: grid;
  grid-template-columns: 14px 1fr auto;
  gap: 8px;
  align-items: center;
  width: 100%;
  margin: 0 0 8px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface-2);
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
  opacity: 0;
  transform: translateY(6px);
  animation: branch-in 0.35s ease forwards;
}

.delib-branch:hover {
  border-color: var(--teal);
  background: var(--teal-wash);
}

.delib-branch.pick {
  border-color: var(--teal);
  background: var(--teal-wash);
  box-shadow: 0 0 0 1px var(--teal);
}

.delib-twig {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--line);
}

.delib-branch.pick .delib-twig {
  background: var(--teal);
  border-color: var(--teal);
}

@keyframes branch-in {
  to { opacity: 1; transform: none; }
}

.plan-card {
  align-self: stretch;
  max-width: min(720px, 100%);
  padding: 14px 16px;
  border: 1px solid var(--teal);
  border-radius: var(--r-m);
  background: var(--teal-wash);
}

.plan-card h2 {
  font: 700 var(--text-lg)/1.2 var(--font-ui);
  margin: 0 0 8px;
}

.plan-card ol {
  margin: 8px 0;
  padding-left: 18px;
}

.plan-runtime {
  margin: 8px 0 0;
  color: var(--muted);
  font: var(--text-base)/1.45 var(--font-ui);
}

.plan-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  margin: 12px 0 0;
}

.plan-confirm {
  padding: 9px 16px;
  border: 1px solid var(--teal);
  border-radius: var(--r-l);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-sm)/1 var(--font-ui);
  cursor: pointer;
}

.plan-confirm[hidden] { display: none; }

.plan-confirm:disabled {
  opacity: 0.45;
  cursor: default;
}

.plan-superseded {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: var(--text-sm);
}

.login-card button {
  padding: 8px 14px;
  border: 0;
  border-radius: var(--r-l);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-sm)/1 var(--font-ui);
  cursor: pointer;
}

/* As tall as its entries, not as tall as the column: an empty frame reads as missing content.
   A long log still scrolls inside the column. */
.inspector-log {
  flex: 0 1 auto;
  min-height: 0;
  overflow: auto;
  padding: 14px 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--surface);
}

.ledger-kicker {
  margin-bottom: 10px;
  color: var(--teal);
  font: 700 var(--text-xs)/1 var(--font-ui);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

#ledger-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

#ledger-list li {
  position: relative;
  padding: 8px 0 8px 16px;
  border-left: 2px solid var(--line);
  color: var(--ink-2);
  font-size: var(--text-sm);
}

#ledger-list li::before {
  content: "";
  position: absolute;
  left: -5px;
  top: 14px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--teal);
}

#ledger-list .ledger-q {
  display: block;
  color: var(--muted);
  font-size: var(--text-xs);
}

@media (max-width: 860px) {
  .chat-page { padding: 8px 10px calc(10px + env(safe-area-inset-bottom)); }
  .composer { width: 100%; }
}

.composer button:disabled { opacity: 0.55; cursor: default; }

#quadrant-monitor {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--surface);
}

#quadrant-monitor.amber {
  border-color: var(--amber);
  background: var(--amber-wash);
}

#quadrant-monitor .monitor-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.monitor-kicker {
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 1.4px;
}

.monitor-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: minmax(4.75rem, auto);
  gap: 8px;
}

.monitor-grid section {
  min-height: 0;
  padding: 8px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface-2);
  overflow: hidden;
  cursor: pointer;
}

.monitor-grid section:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 1px;
}

.monitor-expand {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--muted);
  font: 700 var(--text-xs)/1 var(--font-ui);
  text-align: right;
  cursor: pointer;
}

.monitor-grid h3 {
  margin: 0 0 6px;
  font: 500 var(--text-xs)/1.3 var(--font-ui);
  white-space: nowrap;
}

.monitor-grid ul,
.monitor-blockers {
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--muted);
  font-size: var(--text-xs);
}

.monitor-grid li,
.monitor-blockers li {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.monitor-grid section.expanded {
  grid-column: 1 / -1;
  overflow: auto;
  max-height: 16rem;
  background: var(--surface);
  border-color: var(--teal);
  cursor: default;
}

.monitor-grid section.expanded .monitor-expand {
  position: sticky;
  bottom: 0;
  background: var(--surface);
  padding-top: 4px;
}

.monitor-grid section.expanded li {
  overflow: visible;
  text-overflow: unset;
  white-space: normal;
  padding: 2px 0;
}

.delib-branch div {
  min-width: 0;
  overflow: hidden;
}

/* The row under the conversation holds what a reply offers to click (a confirmation, the ways
   in after a greeting, a question's options when no question card drew them). It was once hidden
   outright, which left "点一个选项" pointing at nothing. */
.choice-row[hidden] { display: none; }
.choice-row { width: min(100%, 52rem); margin: 0 auto; box-sizing: border-box; }
.choice-row .choice-chip.is-suggested { border-color: var(--teal); color: var(--teal-deep); background: var(--teal-wash); }
.choice-row .choice-chip { max-width: 100%; white-space: normal; text-align: left; line-height: 1.4; }
.choice-row .choice-chip.is-quiet { border-color: transparent; background: none; color: var(--muted); }

.monitor-status {
  font: 650 var(--text-sm)/1.3 var(--font-ui);
  color: var(--ink);
}

#quadrant-monitor[data-status="ready"] .monitor-status { color: var(--teal); }
#quadrant-monitor[data-status="running"] .monitor-status { color: var(--blue); }
#quadrant-monitor[data-status="stopped"] .monitor-status { color: var(--muted); }

/* ---- sign in -------------------------------------------------------------------------------
   The form is the page. Above it, the workbench's own logo and name; below it, three true
   sentences about what signing in leads to; behind it, faint as a watermark, a tree growing in
   from the corner with one lineage traced in teal to its tip. On entry the trace draws once and
   the column rises; after that nothing moves unless the reader does something.

   Everything pressed often is easy to press: 48px fields and button, a 44px reveal button inside
   the password field, a full-height row for the account link, a roomy language switch. */
.login-gate {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  overflow-y: auto;
  background: var(--wash);
  background:
    radial-gradient(900px 620px at 8% 92%, rgba(42, 130, 107, 0.07), transparent 70%),
    radial-gradient(760px 540px at 94% 6%, rgba(82, 127, 152, 0.07), transparent 70%),
    radial-gradient(110% 80% at 50% 36%, var(--surface) 0%, var(--wash) 62%);
}

.login-gate[hidden] { display: none; }

/* Signed in: the gate fades into the workbench that is already loading behind it. */
.login-gate.is-leaving { opacity: 0; pointer-events: none; transition: opacity 320ms ease; }

/* The watermark keeps to the edges: masked out around the form, so no line runs behind text.
   The `mask` shorthand on purpose: the static-asset key scan would flag the longhand's name. */
.login-motif {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  -webkit-mask: radial-gradient(ellipse 38% 55% at 50% 47%, transparent 45%, #000 100%);
  mask: radial-gradient(ellipse 38% 55% at 50% 47%, transparent 45%, #000 100%);
}

.login-motif-branches path { fill: none; stroke: var(--cover); stroke-linecap: round; }
.login-motif-trace { fill: none; stroke: var(--teal); stroke-opacity: 0.6; stroke-width: 1.4; stroke-linecap: round; stroke-dasharray: 1; }
.login-motif-tip { fill: var(--teal); }
.login-motif-halo { fill: none; stroke: var(--teal); stroke-opacity: 0.22; }
.login-motif-dots circle { fill-opacity: 0.4; }

.login-lang {
  position: fixed;
  top: max(16px, env(safe-area-inset-top));
  right: max(16px, env(safe-area-inset-right));
  z-index: 1;
  background: rgba(255, 255, 255, 0.85);
}

.login-lang button { min-width: 48px; min-height: 34px; padding: 6px 12px; font-size: var(--text-base); }

/* Centred with auto margins, so a window shorter than the column still scrolls to all of it. */
.login-main {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: min(432px, 100%);
  margin: auto;
  padding: 72px 16px max(48px, env(safe-area-inset-bottom));
}

.login-brand { display: flex; align-items: center; gap: 12px; }

.login-mark {
  width: 38px;
  height: 38px;
  fill: none;
  stroke: var(--teal);
  stroke-width: 2.4;
  stroke-linecap: round;
}

.login-brand h1 {
  margin: 0;
  color: var(--ink);
  font: 500 var(--text-4xl)/1 var(--font-display);
  letter-spacing: -0.01em;
}

.login-tagline {
  margin: 14px 0 12px;
  color: var(--muted);
  font-size: var(--text-md);
  line-height: 1.5;
  text-align: center;
}
.login-evidence {
  margin: 0 auto 30px;
  max-width: 30rem;
  color: var(--muted);
  font-size: var(--text-base);
  line-height: 1.6;
  text-align: center;
  opacity: 0.82;
  text-wrap: balance;
}
/* Where the numbers come from, said right under them, a step quieter. */
.login-evidence small { display: block; margin-top: 4px; font-size: var(--text-sm); opacity: 0.8; }

.login-card {
  width: 100%;
  padding: 32px 32px 26px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(23, 39, 48, 0.04), 0 8px 24px rgba(23, 39, 48, 0.05), 0 24px 56px rgba(23, 39, 48, 0.06);
}

#login-prompt {
  margin: 0 0 22px;
  color: var(--ink);
  font-size: var(--text-xl);
  font-weight: 600;
  line-height: 1.4;
}

.login-card label {
  display: block;
  margin: 0 0 8px;
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: 600;
}

.login-card input {
  width: 100%;
  height: 48px;
  margin: 0 0 18px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-lg);
  transition: border-color 120ms ease, box-shadow 120ms ease, background-color 120ms ease;
}

.login-card input:hover { border-color: var(--line-strong); }

.login-card input:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 4px rgba(42, 130, 107, 0.14);
}

.login-card input[aria-invalid="true"] { border-color: var(--red-line); background: var(--surface); }
.login-card input[aria-invalid="true"]:focus { border-color: var(--red); box-shadow: 0 0 0 4px rgba(169, 93, 82, 0.14); }

/* A field with its icon, and for passwords the reveal button, drawn inside the one outline. */
.login-input { position: relative; margin: 0 0 18px; }
.login-input input { margin: 0; padding-left: 44px; }
.login-input.has-reveal input { padding-right: 52px; }

.login-input-icon {
  position: absolute;
  top: 50%;
  left: 15px;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: var(--subtle);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: translateY(-50%);
  pointer-events: none;
  transition: stroke 120ms ease;
}

.login-input:focus-within .login-input-icon { stroke: var(--teal); }
.login-input:has(input[aria-invalid="true"]) .login-input-icon { stroke: var(--red); }

.login-card .login-reveal {
  position: absolute;
  top: 2px;
  right: 2px;
  bottom: 2px;
  display: grid;
  place-items: center;
  width: 44px;
  padding: 0;
  border: 0;
  border-radius: var(--r-s);
  background: transparent;
  color: var(--subtle);
  cursor: pointer;
  transition: color 120ms ease, background-color 120ms ease;
}

.login-card .login-reveal:hover { color: var(--ink); background: rgba(23, 39, 48, 0.05); }
.login-card .login-reveal:focus-visible { outline: 2px solid var(--teal); outline-offset: -3px; }
.login-reveal svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.login-reveal .login-eye-off,
.login-reveal[aria-pressed="true"] .login-eye { display: none; }
.login-reveal[aria-pressed="true"] .login-eye-off { display: block; }

.login-caps {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: -10px 0 16px;
  color: var(--amber-ink);
  font-size: var(--text-base);
}

.login-caps svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; }

.login-hint { display: block; margin: -10px 0 16px; color: var(--muted); font-size: var(--text-sm); line-height: 1.45; }
.login-field { display: block; }
.login-hint[hidden], .login-field[hidden], .login-error[hidden], .login-caps[hidden],
.login-closed[hidden], .login-card .login-toggle[hidden] { display: none; }

.login-error {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  margin: 0 0 16px;
  padding: 10px 12px;
  border: 1px solid rgba(169, 93, 82, 0.22);
  border-radius: var(--r-m);
  background: rgba(169, 93, 82, 0.06);
  color: var(--red-ink);
  font-size: var(--text-base);
  line-height: 1.45;
}

.login-error::before {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23A95D52' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='6.2'/%3E%3Cpath d='M8 4.8v3.6M8 11.1v.1'/%3E%3C/svg%3E") center / 16px no-repeat;
}

.login-card #login-submit {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 48px;
  margin: 4px 0 0;
  border-radius: var(--r-m);
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: 0.01em;
  box-shadow: 0 1px 2px rgba(23, 39, 48, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.14);
  transition: background-color 140ms ease, box-shadow 140ms ease, transform 90ms ease;
}

.login-card #login-submit::after {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8h10M9 4l4 4-4 4'/%3E%3C/svg%3E") center / 16px no-repeat;
  transition: transform 160ms ease;
}

.login-card #login-submit:hover { background: var(--teal); box-shadow: 0 6px 16px rgba(42, 130, 107, 0.24); }
.login-card #login-submit:hover::after { transform: translateX(3px); }
.login-card #login-submit:active { transform: scale(0.985); }
.login-card #login-submit:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; }
.login-card #login-submit:disabled { cursor: progress; }
.login-card #login-submit.is-busy::after {
  background: none;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: var(--surface);
  border-radius: 50%;
  animation: login-spin 700ms linear infinite;
}
.login-card #login-submit.is-done::after { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E") center / 16px no-repeat; transform: none; }

/* The way to an account sits apart from the form, under a hairline, as a full-height row: easy to
   hit, and still one action per card. Two classes beat the card's own button rule. */
.login-otp {
  letter-spacing: 0.42em;
  font-size: var(--text-3xl);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.login-pending {
  margin: 0 0 16px;
  color: var(--ink);
  font-size: var(--text-md);
  line-height: 1.55;
}
.login-pending[hidden] { display: none; }
.login-turnstile { margin: 0 0 14px; min-height: 0; }
.login-turnstile[hidden] { display: none; }
#login-resend { margin: -4px 0 12px; text-align: left; }
#login-resend:disabled { color: var(--muted); cursor: default; text-decoration: none; }

.login-closed,
.login-card .login-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 48px;
  margin: 22px 0 0;
  padding: 14px 0 0;
  border: 0;
  border-top: 1px solid var(--surface-3);
  border-radius: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: var(--text-base);
  line-height: 1.5;
  text-align: center;
}

.login-card .login-toggle { color: var(--teal); font-weight: 600; cursor: pointer; }
.login-card .login-toggle:hover { color: var(--cover); text-decoration: underline; text-underline-offset: 3px; }
.login-card .login-toggle:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; border-radius: var(--r-s); }

/* A short list, left-aligned so the icons line up, centred as a block under the card. */
.login-points {
  display: grid;
  justify-content: center;
  gap: 9px;
  margin: 26px 0 0;
  padding: 0;
  color: var(--muted);
  font-size: var(--text-base);
  list-style: none;
}

.login-points li { display: flex; align-items: center; gap: 8px; }
.login-points svg { width: 16px; height: 16px; fill: none; stroke: var(--teal); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* Touch: larger targets, and 16px text in fields so a phone does not zoom in on focus. */
@media (pointer: coarse) {
  .login-card input { font-size: 16px; }
  .composer textarea,
  .rail-composer textarea { font-size: 16px; }
  .login-lang button { min-height: 40px; min-width: 52px; }
}

@media (max-width: 480px) {
  .login-main { padding-top: 80px; }
  .login-card { padding: 26px 20px 20px; border-radius: var(--r-l); }
  .login-brand h1 { font-size: var(--text-4xl); }
  /* A phone's column is tall and narrow: keep the watermark to the corners. */
  .login-motif {
    opacity: 0.7;
    -webkit-mask: radial-gradient(ellipse 80% 62% at 50% 52%, transparent 60%, #000 100%);
    mask: radial-gradient(ellipse 80% 62% at 50% 52%, transparent 60%, #000 100%);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .login-gate:not([hidden]) .login-motif-branches { animation: login-fade 900ms ease-out both; }
  .login-gate:not([hidden]) .login-motif-trace { animation: login-draw 1700ms 250ms cubic-bezier(0.45, 0, 0.2, 1) both; }
  .login-gate:not([hidden]) .login-motif-tip,
  .login-gate:not([hidden]) .login-motif-halo { animation: login-fade 500ms 1850ms ease-out both; }
  .login-gate:not([hidden]) .login-motif-dots { animation: login-fade 900ms 1100ms ease-out both; }
  .login-gate:not([hidden]) .login-brand { animation: login-rise 520ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
  .login-gate:not([hidden]) .login-tagline { animation: login-rise 520ms 50ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
  .login-gate:not([hidden]) .login-card { animation: login-rise 520ms 100ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
  .login-gate:not([hidden]) .login-points { animation: login-rise 520ms 180ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
}

@keyframes login-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes login-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes login-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes login-spin { to { transform: rotate(360deg); } }

.account[hidden] { display: none; }

/* The account is one button, its name; language, the expert view and signing out open under it. */
.account {
  position: relative;
  display: flex;
  align-items: center;
  font-size: var(--text-sm);
}

.account-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 38px;
  padding: 3px 9px 3px 3px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-sm)/1 var(--font-ui);
  cursor: pointer;
}
.account-badge {
  position: absolute;
  top: -2px;
  left: 18px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 99px;
  background: var(--red-ink);
  color: var(--surface);
  font-size: var(--text-xs);
  line-height: 16px;
  text-align: center;
}
.account-badge[hidden] { display: none; }
.account-signups {
  border-bottom: 1px solid var(--surface-3);
  padding: 4px 8px 8px;
}
.account-signups[hidden] { display: none; }
.signup-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 0;
}
.signup-who { min-width: 0; }
.signup-who b, .signup-who small { display: block; }
.signup-who b { font-size: var(--text-base); }
.signup-who small {
  color: var(--muted);
  font-size: var(--text-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 150px;
}
.signup-row button {
  min-height: 28px;
  margin-left: 4px;
  padding: 0 8px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-xs);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-sm);
  cursor: pointer;
}
.signup-approve { border-color: var(--teal); color: var(--teal); }
.signup-refuse { color: var(--red-ink); }
.account-button:hover,
.account-button[aria-expanded="true"] { border-color: var(--teal); color: var(--ink); }

.account-avatar {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--line-soft);
  color: var(--teal-ink);
  font: 700 var(--text-base)/1 var(--font-ui);
}

.account-button b {
  max-width: 12ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 650;
}

.account-caret { color: var(--faint); }

.account-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 45;
  width: min(280px, calc(100vw - 16px));
  padding: 8px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: 0 18px 40px -12px rgba(23, 39, 48, 0.28), 0 2px 6px rgba(23, 39, 48, 0.06);
}
.account-menu[hidden] { display: none; }

.account-menu-who {
  margin: 4px 8px 8px;
  color: var(--muted);
  font-size: var(--text-sm);
}
.account-menu-who b { color: var(--ink); font-weight: 650; }

.account-menu-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 48px;
  padding: 4px 8px;
  border-top: 1px solid var(--surface-3);
  color: var(--ink);
  font-size: var(--text-base);
}
.account-menu .language-switch button { min-width: 52px; min-height: 36px; font-size: var(--text-sm); }

.account-menu .expert-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 8px;
  border: 0;
  border-top: 1px solid var(--surface-3);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
}
.account-menu .expert-toggle[hidden] { display: none; }
.account-menu .expert-toggle:hover { background: var(--wash); }
.expert-toggle-text { display: flex; flex-direction: column; gap: 2px; }
.expert-toggle-text b { font-size: var(--text-base); font-weight: 650; }
.expert-toggle-text small { color: var(--muted); font-size: var(--text-sm); line-height: 1.4; }
.expert-switch {
  position: relative;
  flex: none;
  width: 36px;
  height: 22px;
  border-radius: var(--r-pill);
  background: var(--line);
  transition: background 0.18s ease;
}
.expert-switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(23, 39, 48, 0.2);
  transition: transform 0.18s ease;
}
.expert-toggle[aria-pressed="true"] .expert-switch { background: var(--teal); }
.expert-toggle[aria-pressed="true"] .expert-switch::after { transform: translateX(14px); }

/* 算力 in the account menu: the phone's way there while the tab row is put away; a wide screen
   has the tab. */
.account-nodes {
  display: none;
  width: 100%;
  min-height: 34px;
  padding: 0 10px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-base)/1 var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.account-mail {
  border-top: 1px solid var(--surface-3);
  padding: 8px 8px 2px;
}
.account-mail-label {
  display: block;
  margin: 0 0 6px;
  color: var(--muted);
  font-size: var(--text-sm);
}
.account-email {
  display: block;
  box-sizing: border-box;
  width: 100%;
  min-height: 36px;
  margin: 0;
  padding: 0 10px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--wash);
  color: var(--ink);
  font: var(--text-base)/1.4 var(--font-ui);
}
.account-email:focus {
  outline: 2px solid var(--teal);
  outline-offset: 1px;
  background: var(--surface);
}
.account-menu .account-mail .expert-toggle {
  border-top: 0;
  min-height: 48px;
  padding: 8px 0 6px;
}
.account-mail-status {
  margin: 0 0 6px;
  color: var(--red-ink);
  font-size: var(--text-sm);
  line-height: 1.45;
}
.account-mail-status[hidden] { display: none; }

.account-logout {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 0 8px;
  border: 0;
  border-top: 1px solid var(--surface-3);
  background: transparent;
  color: var(--red-ink);
  font: 650 var(--text-base)/1 var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.account-logout:hover { background: var(--red-wash); }

/* Header buttons carry an icon and a word; on a phone the word steps back (still read aloud). */
.rail-drawer svg, .inspector-toggle svg, .files-open svg { flex: none; }
.rail-drawer, .inspector-toggle { gap: 6px; }
.new-analysis { display: inline-flex; align-items: center; gap: 5px; }
/* A drawn plus, not the "＋" glyph: a glyph sits on the font's baseline, a drawing on the centre. */
.new-analysis-plus { flex: none; }
.demo-short { display: none; }

@media (max-width: 1100px) {
  .product-header { grid-template-columns: 200px 1fr auto; padding: 0 18px; gap: 12px; }
  /* The chip is the only way to reach another run, so it survives this breakpoint while the
     decoration around it goes: a narrower screen must not lose the exit from a held slot. */
  .header-meta { padding: 5px 8px; gap: 0; }
  .header-meta small, .slot-meter { display: none; }
  .header-meta b { max-width: 13ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .run-list { right: 12px; }
  .top-nav { justify-content: flex-end; }

  /* The inspector becomes a sheet that slides in from the right (推拉). */
  .inspector-toggle { display: inline-flex; }
  /* ...but only where there is an inspector to show: on page 01 with a run under way. Elsewhere
     (another page, the welcome with nothing started) the button opened a backdrop over nothing,
     or a sheet of zeros. */
  body:not([data-page="chat"]) .inspector-toggle,
  body:has(.chat-page:not([data-mode="session"]):not([data-mode="gate"])) .inspector-toggle { display: none; }

  .chat-page[data-mode="session"] .chat-stage,
  .chat-page[data-mode="gate"] .chat-stage {
    grid-template-columns: minmax(0, 1fr);
  }

  .chat-page .inspector {
    position: fixed;
    top: var(--header-h);
    right: 0;
    bottom: 0;
    z-index: 50;
    display: flex;
    width: min(26rem, 88vw);
    max-height: none;
    padding: 12px;
    border-left: 1px solid var(--line);
    background: var(--wash);
    box-shadow: -18px 0 44px rgba(23, 39, 48, 0.16);
    transform: translateX(calc(100% + 72px));
    transition: transform 0.26s ease;
    overflow: auto;
  }

  .chat-page[data-drawer="open"] .inspector { transform: none; }

  /* The rail becomes a sheet of the same kind, mirrored to the left: below the breakpoint the
     pages keep their full width until the assistant is asked for. */
  .content { grid-template-columns: minmax(0, 1fr); }

  .rail-drawer { display: inline-flex; }

  body[data-page="chat"] .rail-drawer { display: none; }

  .assistant-rail {
    position: fixed;
    top: var(--header-h);
    left: 0;
    bottom: 0;
    z-index: 50;
    width: min(24rem, 92vw);
    margin: 0;
    border-left: none;
    border-radius: 0 18px 18px 0;
    box-shadow: 18px 0 44px rgba(23, 39, 48, 0.16);
    transform: translateX(calc(-100% - 72px));
    transition: transform 0.26s ease;
    animation: none;
  }

  body[data-rail-drawer="open"] .assistant-rail { transform: none; }

  /* A card that sends the reader to "the assistant on the right" needs a rail on the right to
     send them to. Below this breakpoint there is none, so the line goes with it. */
  .stage-next-here { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .concl-hero-canvas.is-loading { animation: none; }
  .login-gate.is-leaving { transition: none; }
  .login-card #login-submit.is-busy::after { animation-duration: 2.4s; }
  .top-nav a.is-arriving { animation: none; }
  .thinking-dot, .delib-branch, .delib-stage.is-live { animation: none; opacity: 1; transform: none; }
  .chat-page .inspector { transition: none; }
  .assistant-rail { animation: none; transition: none; }
  .files-drawer { transition: none; }
  .decision-card.is-flash { transition: none; }
  .review-badge.is-running { animation: none; }
}

@media (max-width: 680px) {
  /* Below this width the three groups cannot share a row, so each takes its own line: the brand,
     then the tabs, then the actions. Pinning the actions to the corner instead put them on top of
     the brand as soon as they were wider than what was left of the row — which is every phone,
     and all the way out to 680px. */
  .product-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    min-height: 0;
    padding: 8px 12px 0;
  }
  /* The brand keeps its words and the tabs keep the full width, so the actions are the group
     that gives way: they wrap among themselves rather than running off the edge. */
  .product-brand {
    flex: 0 1 auto;
    min-width: 0;
  }
  .product-brand > div { min-width: 0; }
  .suite-name,
  .suite-sub {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .header-actions {
    flex: 1 1 0;
    flex-wrap: wrap;
    justify-content: flex-end;
    row-gap: 6px;
    min-width: 0;
  }
  /* The two labels that carry the most width and the least meaning here give way first: the run
     is still named by its chip and the account by the button beside it. */
  .account-button b { max-width: 7ch; }
  .header-meta b { max-width: 9ch; }
  .top-nav {
    flex: 1 0 100%;
    width: 100%;
    justify-content: flex-start;
    height: 42px;
    border-width: 1px 0 0;
    border-radius: 0;
    background: transparent;
  }
}

/* The board is capped so the card under it stays in view. Capped, it must scroll: without this
   the log panel's bottom — the evidence the card asks about — sits past the edge, unreachable.
   Wide enough for both panes, the cap matches the running board's, which is what it takes for
   the log to be readable; a phone keeps the smaller cap and spends the room on the card. */
.chat-page[data-mode="gate"] .run-board {
  display: flex;
  flex: 0 0 auto;
  max-height: 46vh;
  overflow-y: auto;
}

@media (max-width: 860px) {
  .chat-page[data-mode="gate"] .run-board { max-height: 36vh; }
}
.chat-page[data-mode="gate"] .transcript,
.chat-page[data-mode="gate"] .composer-dock {
  display: flex;
}
/* The dock also holds the run-level actions in this mode, so it may need a second row. */
.chat-page[data-mode="gate"] .composer-dock {
  flex-wrap: wrap;
}
.chat-page[data-mode="gate"] .inspector {
  display: flex;
}
.decision-card {
  align-self: stretch;
  padding: 12px 14px;
  border: 1px solid var(--teal);
  border-radius: var(--r-m);
  background: var(--teal-wash);
}
.decision-card h2 { margin: 0 0 8px; font: 700 var(--text-lg)/1.3 var(--font-ui); }
.decision-card .evidence { margin: 0 0 8px; padding-left: 18px; }
.decision-choices { display: flex; flex-wrap: wrap; gap: 8px; }

/* An answered card: still in the record, plainly no longer the thing to act on. */
.decision-card.is-done {
  opacity: 0.62;
  border-color: var(--line);
  background: var(--surface);
}

.decision-card.is-done .decision-choices button { cursor: default; }

.decision-answered {
  margin: 8px 0 0;
  color: var(--teal);
  font: 650 var(--text-xs)/1.4 "SFMono-Regular", Menlo, monospace;
}

/* The interview's 自己的文件 answer is completed with a file, so the card that takes the file
   wears the decision card's shape: it is the same kind of ask, answered with a picker. */
.upload-card {
  align-self: stretch;
  padding: 12px 14px;
  border: 1px solid var(--teal);
  border-radius: var(--r-m);
  background: var(--teal-wash);
}

.upload-card h2 { margin: 0 0 8px; font: 700 var(--text-lg)/1.3 var(--font-ui); }
.upload-card p { margin: 0 0 8px; }

.upload-field {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
  font-size: var(--text-sm);
}

.upload-field span { font-weight: 650; }

.upload-status {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: var(--text-sm);
}

.upload-card.is-done {
  opacity: 0.62;
  border-color: var(--line);
  background: var(--surface);
}

/* The export button's one-line answer, in the preview page's own corner. */
.preview-toast {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 70;
  max-width: min(360px, 86vw);
  padding: 10px 14px;
  border: 1px solid var(--amber);
  border-radius: var(--r-m);
  background: var(--amber-wash);
  color: var(--ink);
  font-size: var(--text-base);
}

.preview-toast[hidden] { display: none; }

/* The Visual QA gate asks for a look at the figures, so the figures sit in the card that asks. */
.figure-gallery { margin: 4px 0 12px; }

.figure-kicker {
  margin: 0 0 8px;
  color: var(--muted);
  font: 650 var(--text-xs)/1.4 "SFMono-Regular", Menlo, monospace;
}

.figure-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 10px;
}

.figure-item {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  overflow: hidden;
  background: var(--surface);
}

/* Tall enough to read a tree's shape: these are the figures the gate asks a person to judge,
   so the preview has to be worth looking at before the click that opens it full size. */
.figure-item img {
  display: block;
  width: 100%;
  height: 260px;
  object-fit: contain;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}

.figure-item figcaption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  padding: 6px 8px;
  font-size: var(--text-xs);
}

.figure-name { color: var(--ink); font-weight: 650; }

.figure-item figcaption a {
  color: var(--teal);
  font-weight: 650;
  text-transform: uppercase;
  text-decoration: none;
}

/* Run board: one checklist of stages and confirmation cards. */
.run-blocked {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: var(--r-s);
  background: var(--amber-wash);
  color: var(--amber-ink);
  font-size: var(--text-sm);
}
.run-blocked[hidden] { display: none; }

.run-steps li.gate {
  cursor: default;
  border-bottom-color: transparent;
}
.run-steps li.gate .dot {
  border: 1.5px solid var(--teal);
  border-radius: var(--r-2xs);
  background: transparent;
}
.run-steps li.gate.complete .dot { background: var(--teal); }
.run-steps li.waiting {
  color: var(--teal);
  font-weight: 650;
  background: var(--teal-wash);
}
.run-steps li.waiting .dot {
  background: var(--teal);
  box-shadow: 0 0 0 3px rgba(42, 130, 107, 0.18);
}
.run-steps li.skipped { opacity: 0.55; }
.run-steps li.skipped .dot { background: transparent; border: 1px dashed var(--line); }
.run-steps li.current { border-left: 3px solid var(--teal); padding-left: 6px; }
.run-steps li.gate small { color: var(--teal); }

/* Plan card: summary first, the full checklist on demand. */
.plan-card .plan-steps { margin: 10px 0; }
.plan-card .plan-steps summary {
  cursor: pointer;
  color: var(--teal);
  font: 650 var(--text-sm)/1 var(--font-ui);
}
.plan-card .plan-steps ol {
  margin: 8px 0 0;
  padding-left: 18px;
  max-height: 220px;
  overflow: auto;
}
.plan-card .plan-steps li { margin-bottom: 3px; font-size: var(--text-base); }
.plan-card .plan-steps li small { margin-left: 6px; color: var(--muted); font-size: var(--text-xs); }
.plan-card .plan-steps li.plan-step-gate { color: var(--teal); }
.plan-wont { margin: 8px 0 0; color: var(--muted); font-size: var(--text-sm); }

/* ---- the compute page: node cards, the session form, and the terminal view ---------------- */

.nodes-page {
  padding: 0;
}

.nodes-page [hidden] {
  display: none !important;
}

.nodes-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: var(--page-top) var(--page-gutter) var(--space-8);
}

.nodes-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.nodes-head .page-title { margin: 0; }

.nodes-summary {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: var(--text-base);
}

#nodes-new, #admin-new { flex: 0 0 auto; }

.admin-page { padding: 0; }
.admin-page [hidden] { display: none !important; }
.admin-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: var(--page-top) var(--page-gutter) var(--space-10);
}
/* A settings page reads down one column; the column is the page's, from the same left edge. */
.admin-scroll > * { max-width: 960px; }
.admin-block { margin-top: var(--space-8); }
.admin-node b { display: block; }
/* Many nodes failing the same way: one card, what it means, the error, then who. */
.admin-node-group { grid-template-columns: 1fr auto; }
.admin-node-why { margin: 6px 0 0; color: var(--ink-2); font-size: var(--text-base); line-height: var(--leading); }
.admin-node-error {
  display: inline-block;
  margin-top: 6px;
  padding: 2px 6px;
  border-radius: var(--r-xs);
  background: var(--red-wash);
  color: var(--red-ink);
  font: var(--text-xs)/1.5 var(--font-mono);
  overflow-wrap: anywhere;
}
.admin-node-names { margin: 8px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: var(--leading); }
.admin-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin-top: 4px;
}
.admin-stat {
  padding: 12px 12px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}
.admin-stat b { display: block; font-size: var(--text-md); }
.admin-stat small { display: block; margin-top: 4px; color: var(--muted); font-size: var(--text-xs); line-height: 1.35; }
.admin-stat.is-off b { color: var(--red-ink); }
.admin-stat.is-on b { color: var(--teal); }
.admin-switch {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}
.admin-switch b { display: block; font-size: var(--text-md); }
.admin-switch small { display: block; margin-top: 3px; color: var(--muted); font-size: var(--text-sm); line-height: 1.45; }
.admin-node {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  margin: 0 0 8px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}
.admin-node.is-bad { border-color: var(--red-line); }
.admin-node.is-hot { border-color: var(--amber-line); }
.admin-node b { font-size: var(--text-md); }
.admin-node small { color: var(--muted); font-size: var(--text-sm); }
.admin-meter {
  height: 4px;
  margin-top: 8px;
  border-radius: 99px;
  background: var(--line-soft);
  overflow: hidden;
}
.admin-meter span {
  display: block;
  height: 100%;
  background: var(--teal);
}
.admin-meter.is-hot span { background: var(--amber); }
.admin-work-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--surface-3);
  font-size: var(--text-base);
}
.admin-work-row small { color: var(--muted); }
@media (max-width: 720px) {
  .admin-stats { grid-template-columns: 1fr 1fr; }
}
.admin-block-title {
  margin: 0 0 var(--space-3);
  color: var(--ink);
  font: var(--weight-strong) var(--text-lg)/1.3 var(--font-ui);
}
.admin-empty { margin: 0; color: var(--muted); font-size: var(--text-base); }
#admin-nodes-summary:not(:empty) { margin-bottom: var(--space-3); }
.admin-create {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 0 8px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}
.admin-create input, .admin-create select {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: var(--text-base)/1.4 inherit;
}
.admin-invite {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muted);
  font-size: var(--text-base);
}
.admin-request, .admin-person {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  margin: 0 0 8px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  text-align: left;
  color: var(--ink);
}
.admin-person { cursor: pointer; }
.admin-person.is-selected { border-color: var(--teal); }
.admin-person-main, .admin-request-main { min-width: 0; }
.admin-person-main b, .admin-request-main b { display: block; font-size: var(--text-md); }
.admin-person-main small, .admin-request-main small {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--text-sm);
}
.admin-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.admin-actions button, .admin-detail button, .admin-create button[type="submit"] {
  min-height: 32px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-sm)/1 inherit;
  cursor: pointer;
}
.admin-actions .is-primary, .admin-create button[type="submit"] {
  border-color: var(--teal);
  background: var(--teal);
  color: var(--surface);
}
.admin-actions .is-danger { color: var(--red-ink); border-color: var(--red-line); }
.admin-detail {
  margin-top: 8px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--wash);
}
.admin-detail p { margin: 0 0 12px; color: var(--muted); font-size: var(--text-base); }
.admin-detail-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 10px;
}
.admin-detail input[type="password"] {
  min-height: 32px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  font: var(--text-base)/1 inherit;
}
.signup-open {
  width: 100%;
  margin: 0;
  padding: 8px 4px;
  border: 0;
  background: transparent;
  color: var(--teal);
  font: 650 var(--text-base)/1.4 inherit;
  text-align: left;
  cursor: pointer;
}
@media (max-width: 720px) {
  .admin-scroll { padding: 16px 14px 28px; }
  .admin-request, .admin-person { align-items: flex-start; flex-direction: column; }
}

.session-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 34rem;
  margin: 0 0 18px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}

.session-form-row {
  display: grid;
  grid-template-columns: 64px 1fr;
  align-items: center;
  gap: 10px;
}

.session-form-row label span {
  color: var(--muted);
  font-size: var(--text-sm);
}

.session-form input[type="text"],
.session-form select {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: var(--text-base)/1.3 inherit;
}

.session-form input[type="text"] {
  font-family: var(--font-mono);
}

.session-form input:focus,
.session-form select:focus {
  outline: 2px solid var(--teal);
  outline-offset: -1px;
}

.session-presets {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.session-presets-label {
  color: var(--muted);
  font-size: var(--text-sm);
  margin-right: 2px;
}

.session-preset {
  padding: 4px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--ink-2);
  font: var(--text-sm)/1.4 var(--font-mono);
  cursor: pointer;
}

.session-preset:hover { border-color: var(--teal); color: var(--teal); }

.session-form-error {
  margin: 0;
  color: var(--red);
  font-size: var(--text-sm);
}

.session-form-actions { display: flex; gap: 10px; }

.session-form-actions button {
  padding: 8px 16px;
  border-radius: var(--r-pill);
  font: 650 var(--text-sm)/1.2 inherit;
  cursor: pointer;
}

.session-form-actions button[type="submit"] {
  border: 1px solid var(--teal);
  background: var(--teal);
  color: var(--surface);
}

.session-form-actions button[type="submit"]:hover { background: var(--teal-deep); }

.session-form-actions #session-cancel {
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
}

.nodes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 14px;
}

.nodes-empty {
  grid-column: 1 / -1;
  margin: 0;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--muted);
  font-size: var(--text-base);
}

.node-card {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}

.node-card.is-down { opacity: 0.72; align-self: start; }
.node-hw { margin: 6px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }

.node-card.is-tainted {
  border-color: var(--amber);
  background: var(--amber-wash);
}

.node-card-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}

/* A host name is a label, set like the page's other labels (it was the display serif, the only
   serif on the compute page). */
.node-card-head b {
  color: var(--ink);
  font: 650 var(--text-md)/1.2 var(--font-ui);
}

.node-address {
  color: var(--muted);
  font: var(--text-xs)/1 var(--font-mono);
}

.node-badges {
  display: inline-flex;
  gap: 6px;
  margin-left: auto;
}

.node-pool,
.node-taint {
  padding: 2px 8px;
  border-radius: var(--r-pill);
  font: 650 var(--text-xs)/1.5 var(--font-ui);
}

.node-pool.is-session { background: var(--teal-wash); color: var(--teal); }
.node-pool.is-compute { background: var(--blue-wash); color: var(--blue); }

.node-taint {
  background: var(--amber);
  color: var(--surface);
  cursor: help;
}

.node-bar-row {
  display: grid;
  grid-template-columns: 38px 1fr auto;
  align-items: center;
  gap: 8px;
}

.node-bar-label {
  color: var(--muted);
  font-size: var(--text-xs);
}

.node-bar {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  overflow: hidden;
}

.node-bar span {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--teal);
  transition: width 240ms ease;
}

.node-bar span.is-hot { background: var(--red); }

.node-bar-value {
  color: var(--ink-2);
  font: var(--text-xs)/1 var(--font-mono);
}

.node-gpus {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  min-height: 18px;
  color: var(--muted);
  font-size: var(--text-xs);
}

.node-gpu {
  padding: 2px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--ink-2);
  font: var(--text-xs)/1.5 var(--font-mono);
}

.node-sessions {
  color: var(--muted);
  font-size: var(--text-xs);
}

.node-session-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--wash);
  color: var(--ink);
  font: var(--text-sm)/1.3 var(--font-mono);
  cursor: pointer;
  text-align: left;
}

.node-session-row:hover { border-color: var(--teal); }

.node-session-row small { color: var(--teal); font-family: var(--font-ui); }

.node-session-row.is-ended { opacity: 0.65; }
.node-session-row.is-ended small { color: var(--muted); }

.session-view {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 62rem;
}

.session-view-head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.session-view-meta {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  flex: 1;
}

.session-view-meta b {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: var(--text-sm)/1.3 var(--font-mono);
  color: var(--ink);
}

.session-status {
  flex: 0 0 auto;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--teal-wash);
  color: var(--teal);
  font: 650 var(--text-xs)/1.5 var(--font-ui);
}

.session-status[data-status="dead"],
.session-status[data-status="closed"] {
  background: var(--surface-3);
  color: var(--muted);
}

#session-back,
#session-close {
  flex: 0 0 auto;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  font: 650 var(--text-sm)/1.2 inherit;
  cursor: pointer;
}

#session-back {
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
}

#session-back:hover { border-color: var(--teal); color: var(--teal); }

#session-close {
  border: 1px solid var(--red-line);
  background: var(--surface);
  color: var(--red);
}

#session-close:hover { border-color: var(--red); background: var(--red-wash); }

.session-dead-banner {
  margin: 0;
  padding: 9px 14px;
  border: 1px solid var(--amber);
  border-radius: var(--r-s);
  background: var(--amber-wash);
  color: var(--amber-ink);
  font-size: var(--text-sm);
}

.session-output {
  min-height: 320px;
  max-height: 56vh;
  margin: 0;
  padding: 14px 16px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--terminal);
  color: var(--teal-line);
  font: var(--text-sm)/1.55 var(--font-mono);
  white-space: pre-wrap;
  word-break: break-word;
}

.session-input-form {
  display: flex;
  gap: 8px;
}

.session-input-form input {
  flex: 1;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: var(--text-base)/1.3 var(--font-mono);
}

.session-input-form input:focus {
  outline: 2px solid var(--teal);
  outline-offset: -1px;
}

.session-input-form button {
  padding: 9px 18px;
  border: 1px solid var(--teal);
  border-radius: var(--r-s);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-base)/1.2 inherit;
  cursor: pointer;
}

.session-input-form button:hover { background: var(--teal-deep); }
.session-input-form button:disabled,
.session-input-form input:disabled { opacity: 0.55; cursor: default; }

/* ---- one-click demo ---------------------------------------------------------------------- */

.demo-start {
  flex: none;
  padding: 10px 16px;
  border: 1px solid var(--teal);
  border-radius: var(--r-pill);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-base)/1.2 var(--font-ui);
  cursor: pointer;
  white-space: nowrap;
}

.demo-start:hover { background: var(--teal-deep); }

.demo-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 4px 3px 10px;
  border: 1px solid var(--amber-line);
  border-radius: var(--r-pill);
  background: var(--amber-wash);
  color: var(--amber-ink);
  font: 600 var(--text-xs)/1.2 var(--font-ui);
  white-space: nowrap;
}

.demo-pill[hidden] { display: none; }

.demo-pill button {
  padding: 1px 6px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: inherit;
  font: 600 var(--text-xs)/1.2 var(--font-ui);
  cursor: pointer;
}

.demo-pill button:hover { background: var(--amber-line); }

/* ---- the narration line above the step rows ---------------------------------------------- */
.run-narration {
  margin: 2px 0 0;
  color: var(--muted);
  font: var(--text-base)/1.5 var(--font-ui);
}

.run-narration[hidden] { display: none; }

/* ---- quadrant panel: plain summary first, grid behind a toggle --------------------------- */
/* Three counts read as one line, with the way into the details at its end: a card of stacked
   short lines spent a sixth of the column on three numbers. */
.monitor-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  padding: 9px 12px 10px;
  border-top: 1px solid var(--line);
}

.monitor-summary p {
  margin: 0;
  color: var(--ink);
  font: var(--text-base)/1.45 var(--font-ui);
}

.monitor-details-toggle {
  align-self: center;
  margin: 0 0 0 auto;
  padding: 3px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--teal);
  font: 600 var(--text-xs)/1.4 var(--font-ui);
  cursor: pointer;
}

.monitor-details-toggle:hover { border-color: var(--teal); }

#quadrant-monitor[data-details="collapsed"] .monitor-grid,
#quadrant-monitor[data-details="collapsed"] .monitor-blockers {
  display: none;
}

/* ---- first-run coach marks ---------------------------------------------------------------- */
.coach-hint {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0 2px;
  padding: 8px 10px;
  border: 1px solid var(--blue-line);
  border-left: 3px solid var(--teal);
  border-radius: var(--r-s);
  background: var(--blue-wash);
  color: var(--ink-2);
  font: var(--text-sm)/1.45 var(--font-ui);
}

.coach-hint p { margin: 0; flex: 1; }

.coach-hint .coach-ok {
  flex: none;
  padding: 3px 10px;
  border: 1px solid var(--teal);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--teal);
  font: 600 var(--text-xs)/1.4 var(--font-ui);
  cursor: pointer;
}

.coach-hint .coach-ok:hover { background: var(--teal-wash); }

/* ---- the conclusion page ------------------------------------------------------------------ */
.conclusion-page { padding: 0; }
/* The empty-state card stands in for the whole body; `hidden` alone loses to the grid below. */
.conclusion-body[hidden] { display: none; }
.conclusion-body {
  /* px, not rem: the page's root size is 13px, so 70rem was only 910px. Full width up to that,
     so its outline while loading is as wide as the page that replaces it. From the page's left
     edge, under its head, like every other page; the cap stops a very wide screen, not a wide
     one (with the rail folded away a 1120px column left a band of nothing on the right). */
  box-sizing: border-box;
  width: 100%;
  max-width: calc(1320px + 2 * var(--page-gutter));
  margin: 0;
  padding: 0 var(--page-gutter) 30px;
}

/* One column: every card reads at full width, the answer and its figure first. */
.conclusion-cards {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

.concl-card {
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
}

.concl-card h2 {
  margin: 0 0 10px;
  font: 650 var(--text-lg)/1.3 var(--font-ui);
  color: var(--ink);
}

.concl-figure-card img {
  display: block;
  max-width: 100%;
  max-height: 420px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--wash);
}

.concl-empty {
  margin: 0;
  color: var(--muted);
  font: var(--text-base)/1.5 var(--font-ui);
}

.concl-row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin: 0;
  padding: 7px 0;
  border-top: 1px solid var(--surface-3);
  font: var(--text-base)/1.4 var(--font-ui);
}

.concl-row:first-of-type { border-top: 0; }

.concl-row span { color: var(--muted); }
.concl-row b { font-weight: 650; color: var(--ink); text-align: right; }

.concl-checks {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.concl-checks li {
  padding: 4px 0;
  border-top: 1px solid var(--surface-3);
  color: var(--ink-2);
  font: var(--text-sm)/1.45 var(--font-ui);
}

.concl-temporal {
  margin: 10px 0 0;
  padding: 8px 10px;
  border: 1px solid var(--amber-line);
  border-left: 3px solid var(--amber);
  border-radius: var(--r-s);
  background: var(--amber-wash);
  color: var(--amber-ink);
  font: var(--text-sm)/1.5 var(--font-ui);
}

.concl-limitation {
  margin: 6px 0 0;
  color: var(--amber-ink);
  font: var(--text-sm)/1.55 var(--font-ui);
}

.concl-basis-kicker {
  margin: 12px 0 4px;
  color: var(--teal);
  font: 700 var(--text-xs)/1.2 var(--font-ui);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.concl-rules {
  margin: 0;
  padding: 0;
  list-style: none;
}

.concl-rules li {
  padding: 6px 0;
  border-top: 1px solid var(--surface-3);
  color: var(--ink-2);
  font: var(--text-sm)/1.5 var(--font-ui);
}

.concl-rules a {
  display: block;
  margin-top: 2px;
  color: var(--blue);
  font: var(--text-xs)/1.4 var(--font-mono);
  overflow-wrap: anywhere;
}

@media (max-width: 680px) {
  
  .demo-start { align-self: center; }
}

/* ==========================================================================================
   The next step, and everything that leads to it.
   One component answers "what now?" on every page: a sentence, one primary action, and quieter
   alternatives. Its tone says the kind of moment (waiting, needs you, a problem, done) before a
   word is read; colour is never the only signal, the title always says it too.
   ========================================================================================== */

:where(button, a, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}

.composer:focus-within,
.rail-composer:focus-within {
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(42, 130, 107, 0.14);
}

.next-step {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
  width: min(100%, var(--chat-col, 52rem));
  margin: 0 auto 10px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-left-width: 4px;
  border-radius: var(--r-m);
  background: var(--surface);
}

.next-step[hidden] { display: none; }
.next-step[data-tone="attention"] { border-left-color: var(--teal); background: var(--teal-wash); }
.next-step[data-tone="problem"] { border-left-color: var(--red); background: var(--red-wash); }
.next-step[data-tone="wait"] { border-left-color: var(--subtle); background: var(--wash); }
.next-step[data-tone="success"] { border-left-color: var(--teal); background: var(--teal-wash); }
.next-step[data-tone="info"] { border-left-color: var(--faint); }

.next-step-text { flex: 1 1 18rem; min-width: 0; }

.next-step-kicker {
  margin: 0 0 2px;
  color: var(--muted);
  font: 700 var(--text-xs)/1.3 var(--font-ui);
  letter-spacing: 0.04em;
}

.next-step h2 {
  margin: 0;
  color: var(--ink);
  font: 700 var(--text-xl)/1.35 var(--font-ui);
}

.next-step p { margin: 4px 0 0; color: var(--ink-2); font-size: var(--text-base); line-height: 1.55; }

/* A question already on screen in the conversation is not repeated here in large type: the dock
   keeps one line on how to answer it, beside its button. */
.next-step[data-echo="1"] { padding: 9px 14px; gap: 8px 14px; }
.next-step[data-echo="1"] #next-step-title { display: none; }
.next-step[data-echo="1"] .next-step-kicker { display: inline; margin: 0 6px 0 0; }
.next-step[data-echo="1"] #next-step-detail { display: inline; margin: 0; font-size: var(--text-base); line-height: 1.5; }

.next-step-more { margin-top: 6px; }
.next-step-more summary { cursor: pointer; color: var(--muted); font-size: var(--text-sm); }
.next-step-more pre {
  max-height: 10rem;
  margin: 6px 0 0;
  padding: 8px 10px;
  overflow: auto;
  border-radius: var(--r-s);
  background: var(--wash);
  font: var(--text-sm)/1.5 "SFMono-Regular", Menlo, monospace;
  white-space: pre-wrap;
  word-break: break-all;
}

.next-step .run-actions {
  flex: 0 1 auto;
  justify-content: flex-end;
  padding: 0;
}

.run-actions button {
  min-height: 36px;
  padding: 8px 14px;
  border-radius: var(--r-s);
  font: 650 var(--text-base)/1.2 var(--font-ui);
  color: var(--ink-2);
}

.run-actions button[hidden] { display: none; }

/* The one thing to do next. */
.run-actions button.is-primary,
.decision-choices button.is-primary,
.dialog-actions button.is-primary,
.conclusion-actions button.is-primary,
.rail-next-step-go {
  border-color: var(--teal);
  background: var(--teal);
  color: var(--surface);
}

.run-actions button.is-primary:hover,
.decision-choices button.is-primary:hover,
.dialog-actions button.is-primary:hover,
.conclusion-actions button.is-primary:hover {
  border-color: var(--teal-deep);
  background: var(--teal-deep);
  color: var(--surface);
}

/* Costs something that cannot be taken back: stopping a step, a risky override. */
.run-actions button.is-danger,
.dialog-actions button.is-danger,
.choice-chip.is-danger,
.rail-choice-chip.is-danger {
  border-color: var(--red);
  background: var(--surface);
  color: var(--red-ink);
}

.dialog-actions button.is-primary.is-danger {
  background: var(--red);
  color: var(--surface);
}

#change-input { border-color: var(--line); color: var(--ink-2); }

/* The failure keeps its board on screen, like a card does. */
.chat-page[data-mode="failed"] {
  align-items: stretch;
  padding: 18px clamp(24px, 3vw, 48px) 22px;
}

.chat-page[data-mode="failed"] .chat-stage {
  max-width: min(1500px, 100%);
  margin: 0 auto;
  width: 100%;
  grid-template-columns: minmax(0, 1fr);
}

.chat-page[data-mode="failed"] .run-board {
  display: flex;
  flex: 0 0 auto;
  max-height: 46vh;
  overflow-y: auto;
}

.chat-page[data-mode="failed"] .transcript,
.chat-page[data-mode="failed"] .composer-dock {
  display: flex;
}

.chat-page[data-mode="failed"] .run-error {
  border-color: var(--red-line);
  background: var(--red-wash);
  color: var(--red-ink);
}

/* ---- gate cards: in the conversation, leading with the suggested choice ----------------- */

.decision-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px 18px;
  border: 1px solid var(--teal-line);
  border-left: 4px solid var(--teal);
  border-radius: var(--r-m);
  background: var(--wash);
  scroll-margin: 24px;
}

.decision-card.is-flash { box-shadow: 0 0 0 4px rgba(42, 130, 107, 0.22); }
.decision-card.is-busy { opacity: 0.75; }

.decision-kicker {
  margin: 0;
  color: var(--teal);
  font: 700 var(--text-sm)/1.3 var(--font-ui);
  letter-spacing: 0.04em;
}

.decision-card h2 { margin: 0; font: 700 var(--text-xl)/1.3 var(--font-ui); font-style: normal; }
.decision-card .decision-prompt { margin: 0; color: var(--ink-2); font-size: var(--text-md); }
.decision-card .evidence { margin: 0; padding-left: 18px; color: var(--ink-2); font-size: var(--text-base); line-height: 1.6; }

.decision-why {
  margin: 0;
  padding: 8px 10px;
  border-radius: var(--r-s);
  background: var(--teal-wash);
  color: var(--teal-ink);
  font-size: var(--text-base);
}

.decision-choices { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }

.decision-choices button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 38px;
  padding: 8px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-md)/1.2 var(--font-ui);
  cursor: pointer;
}

.decision-choices button:hover:not([disabled]) { border-color: var(--teal); color: var(--teal); }
.decision-choices button.is-primary:hover:not([disabled]) { color: var(--surface); }
.decision-choices button[disabled] { cursor: not-allowed; opacity: 0.55; }
.decision-choices button.is-caution { border-color: var(--red-line); color: var(--red-ink); }

.choice-badge {
  padding: 2px 6px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.24);
  font: 700 var(--text-xs)/1.2 var(--font-ui);
}

.decision-input {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 6px 8px;
  align-items: center;
  padding: 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-s);
  background: var(--surface);
}

.decision-input[hidden] { display: none; }
.decision-input label { grid-column: 1 / -1; font: 650 var(--text-base)/1.3 var(--font-ui); }
.decision-input input { min-height: 36px; padding: 6px 10px; border: 1px solid var(--line-strong); border-radius: var(--r-s); font: inherit; }
.decision-input button { min-height: 36px; padding: 6px 12px; border: 1px solid var(--line-strong); border-radius: var(--r-s); background: var(--surface); cursor: pointer; font: 650 var(--text-base)/1 var(--font-ui); }
.decision-input small { grid-column: 1 / -1; color: var(--muted); font-size: var(--text-sm); }

.decision-error {
  margin: 0;
  padding: 8px 10px;
  border-radius: var(--r-s);
  background: var(--red-wash);
  color: var(--red-ink);
  font-size: var(--text-base);
}

.decision-error[hidden] { display: none; }
.decision-note { margin: 0; color: var(--muted); font-size: var(--text-sm); }
.decision-card .rule-source summary { cursor: pointer; color: var(--muted); font-size: var(--text-sm); }

.decision-card.is-done {
  gap: 4px;
  opacity: 1;
  border-color: var(--line);
  border-left-color: var(--line-strong);
  background: var(--surface);
}

.decision-card.is-done .evidence,
.decision-card.is-done .decision-why,
.decision-card.is-done .decision-choices,
.decision-card.is-done .decision-note,
.decision-card.is-done .rule-source,
.decision-card.is-done .decision-prompt { display: none; }

.decision-answered { margin: 0; color: var(--teal); font: 650 var(--text-base)/1.4 var(--font-ui); }

.decision-context {
  align-self: flex-start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font-size: var(--text-sm);
  cursor: pointer;
  text-decoration: underline;
}

/* ---- confirmations and dialogs ---------------------------------------------------------- */

.confirm-dialog {
  width: min(92vw, 30rem);
  padding: 22px 22px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  box-shadow: 0 24px 60px rgba(23, 39, 48, 0.24);
  color: var(--ink);
}

.confirm-dialog::backdrop { background: rgba(23, 39, 48, 0.36); }
.confirm-dialog h2 { margin: 0 0 8px; font: 700 var(--text-xl)/1.35 var(--font-ui); }
.confirm-dialog p { margin: 0 0 12px; color: var(--ink-2); font-size: var(--text-md); line-height: 1.6; }
.confirm-dialog .upload-field { display: flex; flex-direction: column; gap: 4px; margin: 0 0 10px; font-size: var(--text-base); }
.dialog-error { padding: 8px 10px; border-radius: var(--r-s); background: var(--red-wash); color: var(--red-ink); }
.dialog-error[hidden] { display: none; }

.dialog-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-top: 8px; }

.dialog-actions button {
  min-height: 38px;
  padding: 8px 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-md)/1 var(--font-ui);
  cursor: pointer;
}

/* ---- the chips a reply offers: a costly one looks it, "never mind" is quiet -------------- */
.choice-chip.is-quiet,
.rail-choice-chip.is-quiet { border-style: dashed; color: var(--muted); }

/* ---- header: the new-analysis door is always there --------------------------------------- */
.new-analysis {
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--teal);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--teal);
  font: 650 var(--text-base)/1 var(--font-ui);
  white-space: nowrap;
  cursor: pointer;
}

.new-analysis:hover { background: var(--teal-wash); }
.run-switch b { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-ui); }

/* ---- the runtime banner: said once, at the top ------------------------------------------ */
.runtime-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 8px 10px 8px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--wash);
  color: var(--ink-2);
  font-size: var(--text-base);
  line-height: 1.5;
}
.runtime-banner-text { flex: 1; min-width: 0; }
.runtime-banner-close {
  flex: none;
  min-height: 28px;
  padding: 0 10px;
  border: 1px solid currentColor;
  border-radius: var(--r-pill);
  background: transparent;
  color: inherit;
  font: 650 var(--text-sm)/1 var(--font-ui);
  opacity: 0.8;
  cursor: pointer;
}
.runtime-banner-close:hover { opacity: 1; }

.runtime-banner[data-tone="problem"] { background: var(--red-wash); color: var(--red-ink); }
.runtime-banner[hidden] { display: none; }

/* The assistant's model is down: said once, quietly, where the next message will be typed. */
.assistant-notice {
  box-sizing: border-box;
  width: min(100%, 52rem);
  margin: 0 auto 8px;
  padding: 6px 10px;
  border-left: 3px solid var(--viz-moderate);
  background: var(--amber-wash);
  color: var(--amber-ink);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.assistant-notice[hidden] { display: none; }

/* ---- welcome: one question, two quiet ways to try it -------------------------------------- */
.empty-state h1 { font-size: var(--text-4xl); }
.empty-state { max-width: 34rem; }
/* Chinese has no italic: a browser can only lean the glyphs, which reads as a mistake. Upright
   and in the Chinese face; letter-spacing meant for Latin capitals only spreads Chinese apart. */
.app[data-lang="zh"] .empty-kicker { letter-spacing: 0.08em; }
.app[data-lang="zh"] :is(#run-headline, .stage-next-line, .plan-card h2, .decision-card h2, .upload-card h2) {
  font-style: normal;
  font-family: "PingFang SC", var(--font-ui);
  letter-spacing: 0;
}
.app[data-lang="zh"] .run-narration { font: var(--text-base)/1.6 "PingFang SC", var(--font-ui); }

.empty-alt { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; color: var(--muted); font-size: var(--text-base); }

.starter-chip.link,
.demo-start.link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 650 var(--text-base)/1.4 var(--font-ui);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  box-shadow: none;
}

/* ---- the rail's copy of the next step, beside every report page ------------------------- */
.rail-next-step {
  display: grid;
  gap: 6px;
  margin: 0 0 10px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--faint);
  border-radius: var(--r-m);
  background: var(--surface);
}

.rail-next-step[hidden] { display: none; }
.rail-next-step[data-tone="attention"] { border-left-color: var(--teal); background: var(--teal-wash); }
.rail-next-step[data-tone="problem"] { border-left-color: var(--red); background: var(--red-wash); }
.rail-next-step-kicker { margin: 0; color: var(--muted); font: 700 var(--text-xs)/1.2 var(--font-ui); }
.rail-next-step b { font-size: var(--text-md); line-height: 1.4; }

.rail-next-step-go {
  justify-self: start;
  min-height: 32px;
  padding: 6px 12px;
  border: 1px solid var(--teal);
  border-radius: var(--r-s);
  font: 650 var(--text-base)/1 var(--font-ui);
  cursor: pointer;
}

/* ---- the conclusion page leads with the files people came for ---------------------------- */
.conclusion-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}

.conclusion-actions[hidden] { display: none; }

.conclusion-actions button {
  min-height: 40px;
  padding: 8px 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-md)/1 var(--font-ui);
  cursor: pointer;
}

/* ---- sign in / first run ---------------------------------------------------------------- */

@media (max-width: 720px) {
  .next-step { padding: 12px; }
  .next-step .run-actions { justify-content: flex-start; width: 100%; }
  .decision-input { grid-template-columns: 1fr; }
  .new-analysis { padding: 0 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .decision-card, .next-step { transition: none; scroll-behavior: auto; }
}

/* While a decision waits, the board steps back: the card in the conversation is the thing to
   read, so the board keeps its headline, progress and steps and gives up height. */
.chat-page[data-mode="gate"] .run-board { max-height: 30vh; }
.next-step[data-kind="decide"] #next-step-detail { display: none; }
.next-step[data-kind="decide"] { padding: 10px 14px; }

/* The dock is a column in every mode: the next step, then the chips, then the composer. */
.composer-dock {
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.chat-page[data-mode="gate"] .composer-dock,
.chat-page[data-mode="running"] .composer-dock,
.chat-page[data-mode="failed"] .composer-dock { flex-wrap: nowrap; }

/* A scrolling tab strip starts at its first tab: centring an overflowing row cut 01 off. */
/* The strip is as wide as the tabs it holds and grows as they arrive: an empty track would
   advertise pages that do not exist yet. */
.top-nav { justify-content: flex-start; justify-self: start; max-width: 100%; }
.top-nav a { color: var(--muted); flex: 0 0 auto; }

#change-input.is-primary { border-color: var(--teal); color: var(--surface); }

/* While the board carries the reason (a failure) or the card carries the question (a decision),
   the next step keeps to its title and its buttons. */
.next-step[data-compact="1"] #next-step-detail { display: none; }
.next-step[data-compact="1"] { padding: 10px 14px; }

.empty-alt { margin-top: 18px; }

.starter-chip { white-space: nowrap; }

@media (max-width: 720px) {
  /* On a phone the header gives its height back to the work: the brand keeps its name. */
  .suite-sub, .validation-badge { display: none; }
  .chat-page[data-mode="gate"] .run-board,
  .chat-page[data-mode="running"] .run-board,
  .chat-page[data-mode="failed"] .run-board { max-height: 30vh; }
  .run-split { display: none; }
  .next-step { margin-bottom: 6px; }
}

/* ---- the run list: each run can be renamed, put away or deleted ------------------------- */
.run-row-more {
  align-self: center;
  width: 32px;
  min-height: 32px;
  border: 1px solid transparent;
  border-radius: var(--r-s);
  background: transparent;
  color: var(--muted);
  font: 700 var(--text-lg)/1 var(--font-ui);
  cursor: pointer;
}

.run-row-more:hover { border-color: var(--line); background: var(--surface); color: var(--ink); }

.run-row-menu {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 2px 0 6px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  list-style: none;
}

.run-row-menu button {
  min-height: 32px;
  padding: 6px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-base)/1 var(--font-ui);
  cursor: pointer;
}

.run-row-menu button.is-danger { border-color: var(--red-line); color: var(--red-ink); }
.run-row-wrap.is-archived .run-row { opacity: 0.7; }

.run-list-archived {
  align-self: center;
  margin-top: 4px;
  padding: 6px 8px;
  border: 0;
  background: none;
  color: var(--teal);
  font: 650 var(--text-sm)/1.2 var(--font-ui);
  text-decoration: underline;
  cursor: pointer;
}

.run-list-archived[hidden] { display: none; }

/* ---- the way back: an opt-in notification, offered while a run works ---------------------- */
.notify-toggle {
  display: inline-block;
  margin: 4px 0 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 600 var(--text-sm)/1.5 var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.notify-toggle:hover:not(:disabled) { text-decoration: underline; }
.notify-toggle:disabled { color: var(--subtle); cursor: default; }
.notify-toggle[hidden] { display: none; }

/* ---- what each step found: a quiet milestone line in the conversation --------------------- */
.bubble.finding {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  align-self: stretch;
  max-width: none;
  padding: 6px 10px;
  border: 0;
  border-left: 3px solid var(--teal);
  border-radius: 0 8px 8px 0;
  background: var(--wash);
  color: var(--ink);
  font-size: var(--text-base);
  line-height: 1.55;
}
.finding-mark { color: var(--teal); font-weight: 700; }
.finding-text { flex: 1 1 16rem; }
.finding-link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 650 var(--text-sm)/1.5 var(--font-ui);
  cursor: pointer;
}
.finding-link:hover { text-decoration: underline; }

.inline-tree {
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
}
.inline-tree-canvas { max-height: 520px; overflow: auto; font-size: var(--text-base); color: var(--muted); }
.inline-tree figcaption { margin-top: 6px; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.inline-tree-source { font-size: var(--text-xs); color: var(--ink-2); }
.inline-tree-explore { color: var(--teal); font-weight: 600; white-space: nowrap; text-decoration: none; }
.inline-tree-explore:hover { text-decoration: underline; }
.tree-view-svg { display: block; max-width: 100%; height: auto; }
.tree-branch { stroke: var(--ink-2); stroke-width: 1.2; }
.tree-tip { font: var(--text-xs) var(--font-ui); fill: var(--ink); }
.tree-support { stroke: var(--surface); stroke-width: 1; }
.tree-support.is-strong { fill: var(--teal); }
.tree-support.is-moderate { fill: var(--viz-moderate); }
.tree-support.is-weak { fill: var(--faint); }
.tree-scale { stroke: var(--ink-2); stroke-width: 1.5; }
.tree-scale-label { font: var(--text-xs) var(--font-ui); fill: var(--muted); }

/* ---- expert view: one switch, remembered ------------------------------------------------- */

/* ---- the answer first: the question, one sentence, how far to trust it, why ------------- */
.concl-answer { grid-column: 1 / -1; border-left: 4px solid var(--teal); }
.concl-asked { margin: 0 0 4px; color: var(--muted); font-size: var(--text-base); }
.concl-headline { margin: 0 0 10px; font-size: var(--text-2xl); line-height: 1.45; color: var(--ink); }
/* ---- skeletons -----------------------------------------------------------------------------
   What is loading is drawn in its own shape, pulsing softly; with reduced motion it holds still.
   The parts sit in the real container (a node grid, the record list, the run list), so they take
   its layout and nothing moves when the content replaces them. */
.skel-bar {
  display: block;
  flex: none;
  height: 12px;
  border-radius: var(--r-xs);
  background: linear-gradient(90deg, var(--surface-3) 0%, var(--wash) 45%, var(--surface-3) 90%) 0 0 / 200% 100%;
  animation: skel-shimmer 1.4s ease-in-out infinite;
}
.skel-bar.is-block { border-radius: var(--r-s); }
.skel-bar.is-pill { border-radius: var(--r-pill); }
.skel-bar.is-dot { border-radius: 50%; }
@keyframes skel-shimmer { to { background-position: -200% 0; } }
.skel-stack { display: grid; gap: 8px; min-width: 0; }
.skel-row { display: flex; align-items: center; gap: 10px; }
.skel-row > .skel-bar:last-child { margin-left: auto; }
.skel-card { display: grid; gap: 12px; pointer-events: none; }
.skel-figures { display: grid; grid-template-columns: 1.6fr 1fr; gap: 16px; }
.skel-tiles { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; }
.skel-tile { padding: 12px; border: 1px solid var(--line-soft); border-radius: var(--r-s); }
.skel-entry { display: grid; grid-template-columns: 9px 1fr; gap: 12px; align-items: start; padding: 10px 0; list-style: none; }
.skel-entry > .skel-bar.is-dot { margin-top: 2px; }
.skel-list-row { padding: 10px 12px; list-style: none; }
.skel-tree { display: grid; gap: 9px; padding: 14px 4px; }
.skel-conversation { display: grid; gap: 12px; padding: 4px 0; }
.skel-bubble {
  width: min(68%, 520px);
  padding: 12px 14px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
}
.skel-bubble.is-user { justify-self: end; width: min(32%, 240px); background: var(--teal-wash); }
@media (max-width: 720px) {
  .skel-figures { grid-template-columns: 1fr; }
  .skel-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .skel-bubble { width: 86%; }
  .skel-bubble.is-user { width: 52%; }
}
@media (prefers-reduced-motion: reduce) {
  .skel-bar { animation: none; }
}

/* The answer at the end of a finished run's conversation: the sentence, its reliability, three
   numbers, the way in. Drawn like the other cards in the conversation. */
.answer-teaser {
  width: min(100%, 680px);
  margin: 10px 0 14px;
  padding: 16px 18px 14px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--teal);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.answer-teaser-headline { margin: 2px 0 10px; color: var(--ink); font: 700 var(--text-lg)/1.5 var(--font-ui); }
.answer-teaser .concl-reliability { margin-bottom: 0; }
.answer-teaser-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 8px;
  margin: 12px 0 0;
}
.answer-teaser-stats > div { padding: 8px 10px; border-radius: var(--r-s); background: var(--wash); }
.answer-teaser-stats dt { color: var(--muted); font-size: var(--text-sm); line-height: 1.4; }
.answer-teaser-stats dd { margin: 2px 0 0; color: var(--ink); font: 700 var(--text-md)/1.35 var(--font-ui); }

.concl-reliability { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px 12px; margin-bottom: 10px; }
.concl-reliability-badge {
  padding: 2px 10px;
  border-radius: var(--r-pill);
  background: var(--line-soft);
  color: var(--teal-ink);
  font-size: var(--text-sm);
  font-weight: 700;
}
.concl-reliability[data-level="moderate"] .concl-reliability-badge { background: var(--amber-wash); color: var(--amber-ink); }
.concl-reliability[data-level="weak"] .concl-reliability-badge { background: var(--red-wash); color: var(--red-ink); }
.concl-reliability[data-level="unknown"] .concl-reliability-badge { background: var(--surface-3); color: var(--muted); }
.concl-reasons { flex: 1 1 18rem; margin: 0; padding-left: 18px; color: var(--ink-2); font-size: var(--text-base); line-height: 1.55; }
.concl-subtitle { margin: 18px 0 8px; font-size: var(--text-base); color: var(--ink-2); }
/* Whether anyone checked it, beside how reliable it is, in the same size. */
.concl-reliability .concl-review-inline { margin: 0; padding: 2px 10px; font-size: var(--text-sm); font-weight: 650; line-height: inherit; }
.concl-subtitle-row { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 16px; margin: 18px 0 8px; }
.concl-subtitle-row .concl-subtitle { margin: 0; }
.concl-explain { font-size: var(--text-sm); }
/* The tiles read as a row of numbers; what each means opens on request (and on hover). */
.concl-evidence:not(.is-explained) .concl-plain { display: none; }
/* The evidence as tiles: the label, the number large, then what it means. */
.concl-evidence {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 10px;
  margin: 0;
}
.concl-stat {
  padding: 12px 14px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface-2);
}
.concl-evidence dt { color: var(--muted); font-size: var(--text-sm); }
.concl-evidence dd { margin: 4px 0 0; display: flex; flex-direction: column; gap: 4px; }
.concl-evidence dd > b {
  color: var(--ink);
  font-size: var(--text-2xl);
  font-weight: 650;
  line-height: 1.25;
  font-variant-numeric: tabular-nums;
}
.concl-unit { color: var(--muted); font-size: var(--text-sm); font-weight: 500; white-space: nowrap; }
.concl-plain { color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }

/* ---- the answer's figure: the time tree and the root-to-tip plot --------------------------- */
.concl-hero {
  margin: 16px 0 4px;
  padding: 16px 16px 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
}
.concl-hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.85fr) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
}
.concl-hero.is-single .concl-hero-grid { grid-template-columns: minmax(0, 1fr); }
.concl-hero-panel header { margin-bottom: 6px; }
.concl-hero-panel h3 { margin: 0; color: var(--ink); font-size: var(--text-md); font-weight: 650; }
.concl-hero-panel header p { margin: 2px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.45; }
.concl-hero-canvas { position: relative; min-height: 120px; overflow-x: auto; }
.concl-hero-canvas.is-loading {
  min-height: 260px;
  border-radius: var(--r-s);
  background: linear-gradient(90deg, var(--surface-3) 0%, var(--surface-2) 45%, var(--surface-3) 90%) 0 0 / 200% 100%;
  animation: concl-shimmer 1.4s ease-in-out infinite;
}
@keyframes concl-shimmer { to { background-position: -200% 0; } }
.concl-hero-canvas img { display: block; max-width: 100%; border-radius: var(--r-s); }
/* A selection question's figure: the site map drawn by the selection stage, as one wide image. */
.concl-hero.is-selection .concl-hero-canvas img { width: 100%; min-width: 640px; height: auto; }
.concl-selection-links { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 18px; margin-top: 10px; }
.concl-selection-files { color: var(--muted); font-size: var(--text-sm); }
.concl-selection-files a { margin-left: 8px; }
.concl-hero-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
  color: var(--ink-2);
  font-size: var(--text-sm);
}
.concl-hero-legend li { display: inline-flex; align-items: center; gap: 7px; }
.concl-hero-key { display: inline-block; flex: none; }
.concl-hero-key.is-band { width: 18px; height: 10px; border-radius: var(--r-2xs); background: rgba(42, 130, 107, 0.18); box-shadow: inset 0 0 0 1px rgba(42, 130, 107, 0.45); }
.concl-hero-key.is-outlier { width: 9px; height: 9px; border-radius: 50%; background: var(--amber); }
.concl-hero-key.is-fit { width: 18px; border-top: 2px dashed var(--ink-2); }
.concl-hero-key.is-dot { width: 10px; height: 10px; border-radius: 50%; }
/* A legend entry is a switch: click to see only that region, click again for all. */
.concl-hero-filter {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 32px;
  padding: 0 10px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  cursor: pointer;
}
.concl-hero-filter small { color: var(--subtle); font-size: var(--text-xs); }
.concl-hero-filter:hover { border-color: var(--line-soft); background: var(--wash); }
.concl-hero-filter[aria-pressed="true"] { border-color: var(--teal); background: var(--teal-wash); color: var(--teal-ink); }
/* The sentence the figure is for, above it. */
.concl-hero-reading {
  margin: 0 0 12px;
  color: var(--ink);
  font-size: var(--text-md);
  line-height: 1.6;
}
.concl-hero-modes {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 12px;
  padding: 3px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--wash);
  font-size: var(--text-sm);
}
.concl-hero-modes span { padding: 0 6px 0 8px; color: var(--muted); }
.concl-hero-modes button {
  min-height: 32px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--r-s);
  background: transparent;
  color: var(--muted);
  font: 600 var(--text-sm)/1 var(--font-ui);
  cursor: pointer;
}
.concl-hero-modes button[aria-pressed="true"] { background: var(--surface); color: var(--teal-ink); box-shadow: 0 1px 3px rgba(27, 68, 68, 0.1); }
.concl-hero-caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 16px;
  margin-top: 8px;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.concl-hero-caption .concl-source { flex-basis: 100%; }
.concl-hero-links { display: inline-flex; flex-wrap: wrap; gap: 4px 14px; }
.concl-link {
  padding: 6px 0;
  border: 0;
  background: none;
  color: var(--teal-deep);
  font: 650 var(--text-base)/1.3 var(--font-ui);
  text-decoration: none;
  cursor: pointer;
}
.concl-link:hover { text-decoration: underline; text-underline-offset: 3px; }

/* The drawing itself (web/tree-view.js). */
.tt-svg { display: block; max-width: none; overflow: visible; font-family: var(--font-ui); }
.tt-grid { stroke: var(--surface-3); stroke-width: 1; }
.tt-axis { fill: var(--subtle); font-size: var(--text-xs); }
.tt-axis-title { fill: var(--muted); font-size: var(--text-xs); }
.tt-band { fill: rgba(42, 130, 107, 0.1); }
.tt-ci { stroke: var(--teal); stroke-width: 1.5; }
.tt-root-label { fill: var(--teal-ink); font-size: var(--text-sm); font-weight: 650; }
.tt-branch { stroke: var(--ink-2); stroke-width: 1.3; stroke-linecap: round; }
.tt-root { fill: var(--teal); stroke: var(--surface); stroke-width: 2; cursor: help; }
.tt-hit { fill: transparent; cursor: help; }
.tt-hit:hover { fill: rgba(42, 130, 107, 0.18); }
.tt-hit-row { fill: transparent; cursor: help; }
.tt-hit-row:hover { fill: rgba(42, 130, 107, 0.06); }
/* Colour says what a dot is (its region, or off the clock); density only says how many there are,
   through fill-opacity, so the two never overwrite each other. */
.tt-tip { fill: var(--teal); }
.tt-point { fill: var(--teal); fill-opacity: 0.72; cursor: help; }
.tt-label { fill: var(--ink-2); font-size: var(--text-xs); pointer-events: none; }
.tt-label.is-outlier { fill: var(--amber-ink); font-weight: 650; }
.tt-fit { stroke: var(--ink-2); stroke-width: 1.5; stroke-dasharray: 5 4; }
/* Hundreds of tips: finer lines and lighter dots, so the shape of the tree shows through. */
.tt-svg.is-dense .tt-branch { stroke-width: 0.7; }
.tt-svg.is-dense .tt-tip { fill-opacity: 0.85; }
.tt-svg.is-dense .tt-point { fill-opacity: 0.45; }
.tt-svg .tt-tip.is-outlier, .tt-svg .tt-point.is-outlier { fill: var(--amber); fill-opacity: 1; stroke: var(--surface); stroke-width: 1.2; }
.tt-svg.is-dense .tt-tip.is-outlier, .tt-svg.is-dense .tt-point.is-outlier { stroke-width: 0.6; }
/* By region: three validated slots (dataviz reference palette, all-pairs CVD-safe), the rest grey. */
.tt-svg .tt-c1, .concl-hero-key.tt-c1 { fill: var(--viz-1); background: var(--viz-1); }
.tt-svg .tt-c2, .concl-hero-key.tt-c2 { fill: var(--viz-2); background: var(--viz-2); }
.tt-svg .tt-c3, .concl-hero-key.tt-c3 { fill: var(--viz-3); background: var(--viz-3); }
.tt-svg .tt-cother, .concl-hero-key.tt-cother { fill: var(--faint); background: var(--faint); }
.tt-svg .tt-cnone { fill: var(--line-strong); }
.tt-svg .is-dim { fill: var(--line); fill-opacity: 0.55; }
.tt-point:hover { fill: var(--teal-ink); fill-opacity: 1; }
/* A large figure: the marks on a canvas between two SVG layers (web/tree-view.js, layers). The
   highlight under the pointer is the SVG figure's hover, drawn once on the front layer. */
.tt-stack { position: relative; }
.tt-stack > .tt-canvas,
.tt-stack > .tt-front { position: absolute; top: 0; left: 0; }
.tt-stack > .tt-canvas { pointer-events: none; }
.tt-front .tt-hover-node { fill: rgba(42, 130, 107, 0.18); pointer-events: none; }
.tt-front .tt-hover-row { fill: rgba(42, 130, 107, 0.06); pointer-events: none; }
/* The other figure's pointer, and what was clicked: rings on the sequences, a band on a clade.
   Hover is a thin ink ring; the pick is the teal the page uses for "this one". */
.tt-link { pointer-events: none; }
/* A sequence named in the conversation: a link to it on the tree, quiet inside the sentence. */
.seq-ref {
  display: inline;
  padding: 0 2px;
  border: 0;
  border-radius: 3px;
  background: none;
  color: var(--teal-deep);
  font: inherit;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  cursor: pointer;
}
.seq-ref:hover { background: var(--teal-wash); text-decoration-style: solid; }
.seq-ref:focus-visible, .seq-ref-all:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
.seq-ref-all {
  margin-top: 6px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 650 var(--text-sm)/1.4 var(--font-ui);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
/* A part of a QC chart that was clicked: what it holds, and where it is on the tree. Kept at the
   foot of the page's visible area while the report scrolls under it. */
.qc-pick-sheet {
  position: sticky;
  bottom: 16px;
  z-index: 5;
  width: min(640px, calc(100% - 2 * var(--page-gutter, 24px)));
  margin: 12px auto 16px;
  padding: 12px 44px 14px 16px;
  border: 1px solid var(--teal-line);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: 0 10px 28px rgba(22, 50, 58, 0.14);
}
.qc-pick-sheet[hidden] { display: none; }
.qc-pick-sheet[aria-busy="true"] .qc-pick-head b::after { content: " …"; }
.qc-pick-sheet p { margin: 0; }
.qc-pick-head { color: var(--ink); font-size: var(--text-md); }
.qc-pick-head b { font-weight: 650; }
.qc-pick-line { margin-top: 3px; color: var(--ink-2); font-size: var(--text-sm); line-height: 1.5; }
.qc-pick-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.qc-pick-close {
  position: absolute; top: 6px; right: 8px; width: 30px; height: 30px; border: 0; border-radius: var(--r-s);
  background: none; color: var(--muted); font: 400 20px/1 var(--font-ui); cursor: pointer;
}
.qc-pick-close:hover { background: var(--surface-2); color: var(--ink); }
/* What was clicked in the figure, under it: what it is, and where to take it. */
.concl-hero-pick {
  position: relative;
  margin: 12px 0 2px;
  padding: 10px 44px 12px 14px;
  border: 1px solid var(--teal-line);
  border-radius: var(--r-m);
  background: var(--teal-wash);
}
.concl-hero-pick[hidden] { display: none; }
.concl-hero-pick p { margin: 0; }
.concl-hero-pick-head b { color: var(--ink); font-size: var(--text-md); font-weight: 650; }
.concl-hero-pick-facts { margin-top: 2px; color: var(--ink-2); font-size: var(--text-sm); line-height: 1.5; }
.concl-hero-pick-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 10px; }
.concl-hero-pick-close {
  position: absolute;
  top: 6px;
  right: 8px;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: var(--r-s);
  background: none;
  color: var(--muted);
  font: 400 20px/1 var(--font-ui);
  cursor: pointer;
}
.concl-hero-pick-close:hover { background: var(--surface); color: var(--ink); }
.concl-hero-pick-close:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
.tt-link-ring { fill: none; stroke-width: 1.6; }
.tt-link-ring.is-hover { stroke: var(--ink); stroke-opacity: 0.85; }
.tt-link-ring.is-pick { stroke: var(--teal-deep); stroke-width: 2.2; }
.tt-link-band.is-hover { fill: var(--ink); fill-opacity: 0.05; }
.tt-link-band.is-pick { fill: var(--teal); fill-opacity: 0.1; stroke: var(--teal); stroke-opacity: 0.55; stroke-width: 1; }
.tt-tooltip {
  position: absolute;
  z-index: 3;
  max-width: min(320px, 90%);
  padding: 6px 9px;
  border-radius: var(--r-s);
  background: var(--ink);
  color: var(--surface);
  font-size: var(--text-sm);
  line-height: 1.4;
  pointer-events: none;
  box-shadow: 0 6px 18px rgba(23, 39, 48, 0.18);
}
.concl-source { font-size: var(--text-xs); color: var(--ink-2); }
.expert-only { display: none; }
body.is-expert .expert-only { display: inline; }
.concl-caveats p { margin: 0 0 4px; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }

.concl-compare { grid-column: 1 / -1; }
.concl-compare-table { width: 100%; border-collapse: collapse; font-size: var(--text-base); }
.concl-compare-table th, .concl-compare-table td { padding: 4px 8px; border-bottom: 1px solid var(--line); text-align: left; }
.concl-compare-table tr.is-changed td { background: var(--amber-wash); font-weight: 600; }
.concl-compare-summary { margin: 8px 0 0; font-size: var(--text-base); color: var(--ink); }

.concl-followups { grid-column: 1 / -1; }
.concl-followup { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.concl-followup:last-of-type { border-bottom: 0; }
.concl-followup p { margin: 2px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.concl-followup button {
  flex: none;
  padding: 6px 12px;
  border: 1px solid var(--teal);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--teal-ink);
  font: 650 var(--text-base)/1.3 var(--font-ui);
  cursor: pointer;
}
.concl-followup button:hover:not(:disabled) { background: var(--line-soft); }

.expert-details { margin-top: 10px; }
.expert-details > summary { cursor: pointer; color: var(--teal); font-size: var(--text-base); font-weight: 650; }
.tunables-form { display: grid; gap: 10px; margin-top: 8px; }
.tunable { display: grid; grid-template-columns: minmax(8rem, 14rem) 1fr; gap: 2px 10px; align-items: center; font-size: var(--text-base); }
.tunable-key { grid-column: 1; font-size: var(--text-xs); color: var(--muted); }
.tunable input, .tunable select { grid-column: 2; grid-row: 1 / span 2; padding: 5px 8px; border: 1px solid var(--line); border-radius: var(--r-xs); font: inherit; }
.tunable small { grid-column: 1 / -1; color: var(--muted); font-size: var(--text-sm); }
.tunables-error { margin: 0; color: var(--red-ink); font-size: var(--text-base); }
.tunables-form button[type="submit"] { justify-self: start; }
.concl-command { padding: 8px 10px; border-radius: var(--r-xs); background: var(--surface-3); font-size: var(--text-sm); white-space: pre-wrap; word-break: break-all; }
.conclusion-cards > .expert-details { grid-column: 1 / -1; }
.tunables-form button[type="submit"] {
  padding: 7px 14px;
  border: 0;
  border-radius: var(--r-s);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-base)/1.3 var(--font-ui);
  cursor: pointer;
}
.tunables-form button[type="submit"]:disabled { opacity: 0.6; cursor: default; }
@media (max-width: 900px) {
  .concl-hero-grid { grid-template-columns: minmax(0, 1fr); gap: 18px; }
}
@media (max-width: 640px) {
  /* A phone's width goes to the answer: one gutter at the page edge, not one at every layer
     (page 24 + body 22 + card 18 once left the tiles two-thirds of the screen). */
  .conclusion-page { --page-gutter: 12px; }
  .conclusion-body { padding-bottom: 24px; }
  .concl-card { padding: 14px; }
  .concl-evidence { --tile-min: 140px; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
  .concl-stat { padding: 10px 11px; }
  .concl-evidence dd > b { font-size: var(--text-xl); }
  .concl-hero { margin-left: -4px; margin-right: -4px; padding: 12px 10px 10px; }
  .concl-followup { flex-direction: column; align-items: stretch; }
  .tunable { grid-template-columns: 1fr; }
  .tunable input, .tunable select { grid-column: 1; grid-row: auto; }
}
.concl-preliminary { margin-left: 8px; padding: 1px 8px; border-radius: var(--r-pill); background: var(--amber-wash); color: var(--amber-ink); font-size: var(--text-xs); font-weight: 700; }
/* A page that has just filled in, not yet opened. */
a[data-page].has-new { position: relative; }
a[data-page].has-new::after {
  content: "";
  position: absolute;
  top: 4px;
  right: 4px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--red);
}
@media (max-width: 640px) {
  /* A tree shrunk to a phone's width is unreadable; it keeps its size and scrolls sideways,
     in the conversation and on the conclusion alike. */
  .inline-tree-canvas .tree-view-svg,
  .concl-hero-canvas .tree-view-svg { max-width: none; }
}
.concl-say { margin: 8px 0 0; }

/* ---- auto-confirm ---------------------------------------------------------------------- */
.plan-autopilot { display: flex; align-items: flex-start; gap: 8px; margin-top: 10px; font-size: var(--text-base); cursor: pointer; }
.plan-autopilot input { margin-top: 3px; }
.plan-autopilot span { display: flex; flex-direction: column; gap: 2px; }
.plan-autopilot small { color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.decision-stop-reason {
  margin: 0 0 8px;
  padding: 6px 10px;
  border-left: 3px solid var(--viz-moderate);
  background: var(--amber-wash);
  color: var(--amber-ink);
  font-size: var(--text-base);
  line-height: 1.5;
}
.notify-toggle:not([hidden]) + .notify-toggle { margin-left: 14px; }

/* ---- the phone header: one row of controls, the page tabs under it ------------------------
   Every control keeps a 36px or larger target; the words beside the icons are read aloud but not
   drawn, and the account's settings live in its menu, so nothing wraps onto a third line. */
@media (max-width: 680px) {
  .product-header { padding: 6px 12px 0; gap: 4px 8px; }
  .evo-logo { width: 32px; height: 32px; }
  .header-actions { gap: 6px; flex-wrap: nowrap; }
  .header-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .files-open, .rail-drawer, .inspector-toggle, .new-analysis {
    justify-content: center;
    width: 38px;
    min-height: 38px;
    padding: 0;
  }
  .new-analysis-plus { width: 16px; height: 16px; }
  .header-meta { gap: 6px; padding: 3px 4px 3px 3px; border-radius: var(--r-m); }
  .run-switch { min-height: 32px; padding: 0 4px; }
  .account-button b, .account-caret { display: none; }
  .account-button { padding: 3px; }
  .demo-long { display: none; }
  .demo-short { display: inline; }
  /* In the demo, the pill's ✕ is the way to a new analysis; the plus would say it twice. */
  .header-meta:has(#demo-pill:not([hidden])) .new-analysis { display: none; }
  .demo-pill button { min-width: 28px; min-height: 28px; }
  /* The tabs go under the controls, so the brand and the controls share the first row; and only
     once there is somewhere to go besides the conversation (算力 is in the account menu). */
  .top-nav { order: 3; height: 40px; }
  .top-nav:not(.has-reports) { display: none; }
  .account-nodes:not([hidden]) { display: block; }
  .header-meta { min-width: 0; }
  .run-switch { min-width: 0; }
}

/* ---- the desktop header when it is crowded ----------------------------------------------
   A running demo adds the pill and the slot meter to the controls, and the fixed brand and tab
   columns then pushed the row past the window: labels broke into one character per line and the
   account went off the edge. The brand and tabs now size to what they hold, no label wraps, and
   the controls shed words in steps (the icons keep their names as tooltips). */
@media (min-width: 681px) {
  .product-header { grid-template-columns: auto minmax(0, 1fr) auto; }
  .top-nav { min-width: 0; }
  .header-actions { min-width: 0; }
  .header-label, .header-meta small, .header-meta b, .files-open, .rail-drawer, .inspector-toggle,
  .account-button b { white-space: nowrap; }
}
@media (min-width: 681px) and (max-width: 1500px) {
  .demo-long { display: none; }
  .demo-short { display: inline; }
}
@media (min-width: 681px) {
  .product-header.is-crowded :is(.files-open, .rail-drawer, .inspector-toggle) .header-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
  }
  .product-header.is-crowded :is(.files-open, .rail-drawer, .inspector-toggle) { justify-content: center; min-width: 36px; padding: 0 10px; }
  /* Still too many tabs: the strip scrolls, and a shade at the edge that has more says so. */
  .top-nav {
    background:
      linear-gradient(to right, var(--wash) 40%, rgba(242, 246, 245, 0)) left / 24px 100% no-repeat local,
      linear-gradient(to left, var(--wash) 40%, rgba(242, 246, 245, 0)) right / 24px 100% no-repeat local,
      linear-gradient(to right, rgba(24, 58, 62, 0.14), rgba(24, 58, 62, 0)) left / 12px 100% no-repeat scroll,
      linear-gradient(to left, rgba(24, 58, 62, 0.14), rgba(24, 58, 62, 0)) right / 12px 100% no-repeat scroll,
      var(--wash);
    scrollbar-width: none;
  }
  .top-nav::-webkit-scrollbar { display: none; }
}
@media (min-width: 681px) and (max-width: 1320px) {
  .files-open .header-label, .rail-drawer .header-label, .inspector-toggle .header-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
  }
  .files-open, .rail-drawer, .inspector-toggle { justify-content: center; min-width: 36px; padding: 0 10px; }
}
@media (min-width: 681px) and (max-width: 1100px) {
  .header-meta { gap: 6px; }
  /* A tab strip that scrolls shows a shade at the edge that has more (covers ride the content,
     shades ride the box), so a clipped tab reads as "more this way", not as a cut. */
  .top-nav {
    background:
      linear-gradient(to right, var(--wash) 40%, rgba(242, 246, 245, 0)) left / 24px 100% no-repeat local,
      linear-gradient(to left, var(--wash) 40%, rgba(242, 246, 245, 0)) right / 24px 100% no-repeat local,
      linear-gradient(to right, rgba(24, 58, 62, 0.14), rgba(24, 58, 62, 0)) left / 12px 100% no-repeat scroll,
      linear-gradient(to left, rgba(24, 58, 62, 0.14), rgba(24, 58, 62, 0)) right / 12px 100% no-repeat scroll,
      var(--wash);
    scrollbar-width: none;
  }
  .top-nav::-webkit-scrollbar { display: none; }
}
@media (min-width: 681px) and (max-width: 900px) {
  .product-brand .suite-sub, .top-nav .nav-number { display: none; }
  .top-nav a { padding: 0 10px; }
  .header-meta small, .account-button b, .account-caret { display: none; }
  .header-meta b { max-width: 9ch; }
  .new-analysis .header-label { display: none; }
}

/* The panel button opens the conversation's inspector; on any other page it would open nothing. */
@media (max-width: 1100px) {
  body:not([data-page="chat"]) .inspector-toggle { display: none; }
}

@media (max-width: 480px) {
  /* The mark says EvoTrace on its own; the row is for the controls. */
  .product-brand > div { display: none; }
}

/* ---- the Nextstrain library: the welcome's way in, and the gallery ------------------------ */
.library-entry {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  width: min(100%, 30rem);
  min-height: 64px;
  margin: 14px auto 0;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-1);
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.library-entry:hover { border-color: var(--teal); box-shadow: 0 8px 22px -12px rgba(23, 60, 52, 0.35); transform: translateY(-1px); }

.run-library { border-style: solid; background: var(--wash); }

body.has-library { overflow: hidden; }
.library-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(23, 39, 48, 0.34);
}
.library-backdrop[hidden], .library[hidden] { display: none; }
.library {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 61;
  display: flex;
  flex-direction: column;
  width: min(1060px, calc(100vw - 32px));
  height: min(88vh, 920px);
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: 0 30px 80px -24px rgba(23, 39, 48, 0.45);
  transform: translate(-50%, -50%);
  overflow: hidden;
}
.library-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 22px 10px;
}
.library-head h2 { margin: 0; color: var(--ink); font-size: var(--text-2xl); font-weight: 700; }
.library-lede { max-width: min(100%, 780px); margin: 6px 0 0; color: var(--muted); font-size: var(--text-base); line-height: 1.55; }
.library-close {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  border: 1px solid var(--line-soft);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
}
.library-close:hover { border-color: var(--teal); color: var(--ink); }
.library-tools { display: flex; flex-direction: column; gap: 10px; padding: 4px 22px 10px; }
.library-search {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 46px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface-2);
  color: var(--subtle);
}
.library-search:focus-within { border-color: var(--teal); box-shadow: 0 0 0 4px rgba(42, 130, 107, 0.14); background: var(--surface); }
.library-search input {
  flex: 1;
  min-width: 0;
  height: 44px;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--ink);
  font: var(--text-md)/1.2 var(--font-ui);
}
.library-families {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 2px;
  scrollbar-width: thin;
}
.library-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font: 600 var(--text-base)/1 var(--font-ui);
  cursor: pointer;
}
.library-chip small { color: var(--subtle); font-size: var(--text-xs); font-weight: 600; }
.library-chip:hover { border-color: var(--teal); }
.library-chip[aria-pressed="true"] { border-color: var(--teal); background: var(--teal-wash); color: var(--teal-ink); }
.library-chip[aria-pressed="true"] small { color: var(--teal); }
.library-status { margin: 0; padding: 0 22px 8px; color: var(--muted); font-size: var(--text-sm); }
.library-list {
  display: grid;
  flex: 1;
  grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
  align-content: start;
  gap: 12px;
  margin: 0;
  padding: 4px 22px 18px;
  overflow-y: auto;
  list-style: none;
}
.library-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 16px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface-2);
}
.library-card:hover { border-color: var(--teal-line); }
.library-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.library-family { color: var(--teal-deep); font-size: var(--text-sm); font-weight: 700; }
.library-path { overflow: hidden; color: var(--subtle); font-size: var(--text-xs); text-overflow: ellipsis; white-space: nowrap; }
.library-card h3 { margin: 0; color: var(--ink); font-size: var(--text-md); font-weight: 650; line-height: 1.35; }
.library-facts { margin: 0; color: var(--ink-2); font-size: var(--text-base); font-variant-numeric: tabular-nums; }
.library-badges { display: flex; flex-wrap: wrap; gap: 5px; margin: 0; }
.library-badge { padding: 2px 8px; border-radius: var(--r-pill); font-size: var(--text-xs); font-weight: 650; }
.library-badge.is-time { background: var(--line-soft); color: var(--teal-ink); }
.library-badge.is-plain { background: var(--surface-3); color: var(--muted); }
.library-badge.is-rebuild { background: var(--blue-wash); color: var(--blue-ink); }
.library-badge.is-view { background: var(--amber-wash); color: var(--amber-ink); }
.library-badge.is-recomb { background: var(--red-wash); color: var(--red-ink); }
.concl-recombination .recomb-list { margin: 8px 0 0; padding-left: 18px; }
.concl-recombination .recomb-list li { margin: 3px 0; color: var(--subtle); font-size: var(--text-sm); line-height: 1.5; }
.concl-recombination .recomb-actions { margin-top: 12px; }
.concl-recombination .recomb-error { color: var(--red); }
.concl-recombination .principle-provenance { color: var(--muted); font-size: var(--text-xs); }
.library-source { margin: 0; color: var(--subtle); font-size: var(--text-sm); line-height: 1.45; }
/* The button sits at the card's foot, so the buttons along a row line up whatever the title's length. */
.library-open {
  align-self: flex-start;
  min-height: 40px;
  margin-top: auto;
  padding: 0 18px;
  border: 0;
  border-radius: var(--r-s);
  background: var(--teal);
  color: var(--surface);
  font: 650 var(--text-base)/1 var(--font-ui);
  cursor: pointer;
}
.library-open:hover:not(:disabled) { background: var(--teal-deep); }
.library-open:disabled { opacity: 0.7; cursor: progress; }
.library-foot { margin: 0; padding: 10px 22px 14px; border-top: 1px solid var(--surface-3); color: var(--subtle); font-size: var(--text-sm); }

/* A run opened from Nextstrain says whose analysis it is, above the answer: a line of facts and a
   line of whose reading the rest is, quieter than the answer they introduce. */
.concl-source-note {
  margin: 0 0 14px;
  padding: 0 0 12px;
  border-bottom: 1px solid var(--line-soft);
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 1.55;
}
.concl-source-note p { margin: 0; }
.concl-source-facts { color: var(--ink-2); }
.concl-source-note a { color: var(--teal-deep); font-weight: 650; white-space: nowrap; }

/* A side card that reads as one line until opened: its title, then what is inside in a few words. */
.concl-fold { padding: 0; }
.concl-fold > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 14px;
  padding: 14px 44px 14px 18px;
  position: relative;
  list-style: none;
  cursor: pointer;
  border-radius: inherit;
}
.concl-fold > summary::-webkit-details-marker { display: none; }
.concl-fold > summary::after { position: absolute; right: 20px; top: 21px; }
.concl-fold > summary:hover { background: var(--surface-2); }
.concl-fold > summary:focus-visible { outline: 2px solid var(--teal); outline-offset: -2px; }
.concl-fold > summary h2 { margin: 0; font-size: var(--text-md); }
.concl-fold-sum { color: var(--muted); font-size: var(--text-sm); }
.concl-fold[open] > summary { border-bottom: 1px solid var(--line-soft); border-radius: var(--r-m) var(--r-m) 0 0; }
.concl-fold > :not(summary) { margin-left: 18px; margin-right: 18px; }
.concl-fold > :last-child:not(summary) { margin-bottom: 16px; }
.concl-fold > summary + * { margin-top: 12px; }

@media (max-width: 680px) {
  .library { top: 0; left: 0; width: 100vw; height: 100dvh; border-radius: 0; transform: none; }
  .library-head { padding: max(14px, env(safe-area-inset-top)) 16px 8px; }
  .library-tools, .library-status, .library-foot { padding-left: 16px; padding-right: 16px; }
  .library-list { grid-template-columns: minmax(0, 1fr); padding: 4px 16px max(16px, env(safe-area-inset-bottom)); }
  .library-search input { font-size: 16px; }
}

/* ---- where to look next ------------------------------------------------------------------ */
.library-quick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 10px 0 0;
  color: var(--muted);
  font-size: var(--text-base);
}
.library-quick[hidden] { display: none; }

.concl-related { display: grid; gap: 0; margin: 4px 0 0; padding: 0; list-style: none; }
.concl-related li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
}
.concl-related li:first-child { border-top: 0; }
.concl-related b { font-size: var(--text-base); }
.concl-related p { margin: 2px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.concl-related button, .concl-explore .concl-followup button {
  flex: none;
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid var(--teal);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--teal-ink);
  font: 650 var(--text-base)/1.3 var(--font-ui);
  cursor: pointer;
}
.concl-related button:hover:not(:disabled) { background: var(--line-soft); }
.concl-related button:disabled { opacity: 0.7; cursor: progress; }
.concl-explore-status:empty { display: none; }
@media (max-width: 640px) {
  .concl-related li { flex-direction: column; align-items: stretch; }
}

/* ---- the first move: a file, a question, or just looking ---------------------------------- */
/* The welcome is three ways in, in the order people have them: data, a question, nothing yet.
   The file door is a drop target; the question door holds real questions, each answered by an
   analysis in the library; "just looking" is the quiet line under both. */
.empty-state { max-width: 520px; }
.empty-state .empty-lede { max-width: 440px; margin: 0 auto 18px; line-height: 1.6; text-wrap: balance; }
.empty-state .empty-alt { margin: 16px 0 0; }
.opening-doors { display: grid; gap: 10px; text-align: left; }
.opening-door {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 12px;
  align-items: start;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
/* The mark sits on the title's line: its centre on the centre of the first line of text. */
.door-mark { color: var(--teal); margin-top: -4px; }
.door-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.door-text > b { font-size: var(--text-lg); font-weight: 700; color: var(--ink); }
.door-text > small { color: var(--muted); font-size: var(--text-base); line-height: 1.5; }
.door-file {
  border-style: dashed;
  border-color: var(--teal-soft);
  background: var(--surface-2);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.door-file:hover,
.door-file:focus-within { border-color: var(--teal); background: var(--teal-wash); }
.door-file:focus-within { outline: 2px solid var(--teal); outline-offset: 2px; }
.door-status { color: var(--amber-ink); font-size: var(--text-base); }
.door-status[hidden] { display: none; }
.opening-questions { display: grid; gap: 6px; margin: 6px 0 0; padding: 0; list-style: none; }
.opening-questions[hidden] { display: none; }
.opening-question {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  background: var(--surface-2);
  color: var(--ink);
  font: 600 var(--text-base)/1.45 var(--font-ui);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.opening-question small { color: var(--muted); font-size: var(--text-sm); font-weight: 400; }
.opening-question:hover { border-color: var(--teal); background: var(--teal-wash); }
.opening-question:hover small { color: var(--teal); }
.opening-question:disabled { opacity: 0.7; cursor: progress; }
.library-link.link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 650 var(--text-base)/1.4 var(--font-ui);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.chat-column { position: relative; }
.opening-dropmask {
  position: absolute;
  inset: 8px;
  z-index: 20;
  display: grid;
  place-items: center;
  border: 2px dashed var(--teal);
  border-radius: var(--r-l);
  background: rgba(239, 248, 244, 0.94);
  color: var(--teal);
  font: 700 var(--text-lg)/1.4 var(--font-ui);
  pointer-events: none;
}
.opening-dropmask[hidden] { display: none; }
@media (max-width: 720px) {
  .opening-door { padding: 12px 13px; gap: 10px; }
  .door-mark { width: 24px; height: 24px; margin-top: -1px; }
  .empty-state .empty-lede { margin-bottom: 14px; }
  /* The questions take the card's full width; the icon column would waste a fifth of a phone. */
  .door-question .opening-questions { margin-left: -34px; }
}

/* ==========================================================================================
   One visual language.
   Every new surface draws from this block, and the most visible old ones have moved onto it:
   three radii (small parts, cards, panels), one card, three kinds of button, one chip, and
   colours that each mean one thing everywhere (docs/voice.md, 视觉语言):
     teal       — yours, or what you act on (your sequences, a primary action, confirmed)
     amber      — caution (weak signal, off the clock, a choice with a cost)
     red-brown  — something did not work
     slate      — waiting or in progress
     grey       — reference and background (the Nextstrain tree behind your sequences, what a
                  fast method answers and what the full analysis settles)
   ========================================================================================== */
.card {
  padding: 14px 16px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.card-kicker {
  margin: 0 0 6px;
  color: var(--teal-ink);
  font: 700 var(--text-xs)/1.3 var(--font-ui);
  letter-spacing: 0.06em;
}
.card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-top: 12px; }
.btn-primary,
.btn-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 0 15px;
  border-radius: var(--r-s);
  font: 650 var(--text-base)/1.2 var(--font-ui);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.btn-primary { border: 1px solid var(--teal); background: var(--teal); color: var(--surface); }
.btn-primary:hover { border-color: var(--teal-deep); background: var(--teal-deep); }
.btn-secondary { border: 1px solid var(--teal-line); background: var(--surface); color: var(--teal-ink); }
.btn-secondary:hover { border-color: var(--teal); background: var(--teal-wash); }
.btn-primary:disabled,
.btn-secondary:disabled { opacity: 0.65; cursor: progress; }
.btn-quiet,
.starter-chip.link,
.demo-start.link,
.library-link.link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 650 var(--text-base)/1.4 var(--font-ui);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  cursor: pointer;
}
.btn-quiet:hover,
.starter-chip.link:hover,
.demo-start.link:hover,
.library-link.link:hover { color: var(--teal-deep); background: none; }
/* Every focus ring is the same ring. */
.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-quiet:focus-visible,
.choice-chip:focus-visible,
.opening-question:focus-visible,
.welcome-recent-row:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }

/* ---- reference-tree placement: the placement card ------------------------------------------- */
.place-card {
  margin: 8px 0 12px;
  padding: 16px 18px 14px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.place-headline { margin: 0 0 10px; color: var(--ink); font: 650 var(--text-md)/1.55 var(--font-ui); }
.place-figure { margin: 2px 0 4px; overflow: hidden; }
.place-figure .tt-svg { width: 100%; height: auto; }
.place-legend { display: flex; align-items: center; gap: 8px; margin: 2px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.place-key {
  flex: none;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--teal);
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 3px var(--teal-line);
}
.place-lines { margin: 12px 0 0; padding-left: 18px; color: var(--ink); font-size: var(--text-base); line-height: 1.7; }
/* An answer from the fast results: what it rests on, and the way on to the full analysis. */
.fast-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px solid var(--line-soft);
  white-space: normal;
}
.fast-basis { color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.fast-dispatch { min-height: 30px; padding: 0 12px; }

/* What placement answers, and what the full analysis settles: a statement of scope, not a warning,
   so it wears the reference grey rather than the amber of a caution. */
.place-caveat {
  margin: 12px 0 0;
  padding: 8px 12px;
  border-left: 3px solid var(--ref-grey);
  border-radius: 0 var(--r-s) var(--r-s) 0;
  background: var(--wash);
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 1.6;
}
.place-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.place-table th { color: var(--muted); font-weight: 650; text-align: left; }
.place-table th,
.place-table td { padding: 5px 8px 5px 0; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.tt-svg.has-marks .tt-branch { stroke: var(--faint); }
.tt-svg.has-marks .tt-tip { fill: var(--ref-grey); }
.tt-mark { fill: var(--teal); fill-opacity: 0.88; stroke: var(--surface); stroke-width: 1.5; cursor: help; }
.tt-mark:hover { fill: var(--teal-ink); fill-opacity: 1; }
.bubble-action { display: flex; width: fit-content; margin-top: 10px; }

/* ---- the first screen uses its width --------------------------------------------------------- */
.welcome-recent { margin: 18px 0 0; text-align: left; }
.welcome-recent[hidden] { display: none; }
.welcome-recent-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
/* Cards in a row are one height: the row stretches the item, and the card fills it. */
.welcome-recent-list > li { display: flex; }
.welcome-recent-list .welcome-recent-row { flex: 1; justify-content: flex-start; }
.welcome-recent-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  padding: 10px 14px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
  color: var(--ink);
  font: 650 var(--text-base)/1.4 var(--font-ui);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.welcome-recent-row small { color: var(--muted); font-size: var(--text-sm); font-weight: 400; }
.welcome-recent-row:hover { border-color: var(--teal); background: var(--teal-wash); }
@media (min-width: 1000px) {
  .chat-page[data-mode="welcome"] .chat-stage { max-width: 1040px; }
  .chat-page[data-mode="welcome"] .empty-state { max-width: 940px; padding-top: 28px; }
  .chat-page[data-mode="welcome"] .opening-doors { grid-template-columns: 1fr 1.25fr; align-items: stretch; gap: 14px; }
  .chat-page[data-mode="welcome"] .door-file { align-content: start; min-height: 100%; }
  .chat-page[data-mode="welcome"] .welcome-recent-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.door-pick { width: fit-content; margin-top: 8px; pointer-events: none; }
.door-file:hover .door-pick { border-color: var(--teal); background: var(--teal-wash); }
.welcome-recent-row small { display: -webkit-box; overflow: hidden; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
@media (min-width: 1000px) {
  /* Beside the questions the file door is a proper drop zone: centred, with room to aim at. */
  .chat-page[data-mode="welcome"] .door-file {
    grid-template-columns: 1fr;
    justify-items: center;
    align-content: center;
    padding: 28px 26px;
    text-align: center;
  }
  .chat-page[data-mode="welcome"] .door-file .door-mark { width: 46px; height: 46px; }
  .chat-page[data-mode="welcome"] .door-file .door-text { align-items: center; max-width: 320px; }
  .chat-page[data-mode="welcome"] .door-file .door-pick { margin-top: 12px; }
}
.ledger-empty { margin: 4px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.6; }
#ledger-list:not(:empty) + .ledger-empty { display: none; }
#nav-nodes .nav-number { display: none; }
/* One action look for "open" everywhere: the library's cards match the conclusion's rows. */
.library-card .library-open.btn-secondary { width: fit-content; min-height: 34px; padding: 0 16px; border: 1px solid var(--teal-line); background: var(--surface); color: var(--teal-ink); }
.library-card .library-open.btn-secondary:hover:not(:disabled) { border-color: var(--teal); background: var(--teal-wash); }

/* Shapes say what a thing is: an action is a rounded rectangle, a card is a card, and a pill is
   something you pick in the conversation (an answer, a filter). */
.run-actions button,
.concl-followup button,
.concl-related button,
.library-card .library-open.btn-secondary { border-radius: var(--r-s); }
.plan-card,
.opening-door,
.concl-card,
.library-card,
.decision-card,
.next-step { border-radius: var(--r-m); }

/* ---- the research record ---------------------------------------------------------------------
   A timeline in the one visual language: a filled teal dot is something you did or said, a teal
   ring is a card answered for you by its recommendation, grey is the workbench, amber a choice with
   a cost or a result to treat with caution, red-brown a step that did not finish. */
.record-drawer {
  position: fixed;
  top: var(--header-h);
  right: 0;
  bottom: 0;
  z-index: 45;
  display: flex;
  flex-direction: column;
  width: min(100vw, 460px);
  border-left: 1px solid var(--line);
  background: var(--surface);
  box-shadow: -18px 0 44px rgba(23, 39, 48, 0.14);
  transform: translateX(calc(100% + 72px));
  transition: transform 0.26s ease;
}
body[data-record="open"] .record-drawer { transform: none; }
.record-head {
  display: flex;
  flex: 0 0 auto;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px 12px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface-2);
}
.record-heading h2 { margin: 0; color: var(--ink); font: 700 var(--text-lg)/1.3 var(--font-ui); }
.record-run { margin: 3px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.4; }
.record-body { flex: 1 1 auto; overflow-y: auto; padding: 12px 16px 18px; overscroll-behavior: contain; }
.record-lead { margin: 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.6; }
.record-filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0; }
.record-list { position: relative; margin: 6px 0 0; padding: 0; list-style: none; }
.record-empty { margin: 14px 0 0; color: var(--muted); font-size: var(--text-base); line-height: 1.7; }
.record-day {
  margin: 16px 0 4px;
  color: var(--muted);
  font: 700 var(--text-xs)/1.3 var(--font-ui);
  letter-spacing: 0.04em;
}
.record-entry {
  position: relative;
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr);
  gap: 10px;
  padding: 7px 0 9px;
}
/* The thread that joins one entry to the next. */
.record-entry::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 5.5px;
  border-left: 1px solid var(--line-soft);
}
.record-day + .record-entry::before { top: 12px; }
.record-dot {
  position: relative;
  width: 9px;
  height: 9px;
  margin: 5px 0 0 1.5px;
  border-radius: 50%;
  background: var(--ref-grey);
  box-shadow: 0 0 0 3px var(--surface);
}
.record-entry.who-you .record-dot { background: var(--teal); }
.record-entry.who-auto .record-dot { background: var(--surface); box-shadow: inset 0 0 0 2px var(--teal), 0 0 0 3px var(--surface); }
.record-entry.is-amber .record-dot { background: var(--amber); box-shadow: 0 0 0 3px var(--surface); }
.record-entry.is-failed .record-dot { background: var(--red-ink); }
.record-entry.kind-step .record-dot { width: 7px; height: 7px; margin: 6px 0 0 2.5px; }
.record-meta { display: flex; align-items: baseline; gap: 8px; }
.record-kicker { color: var(--muted); font: 700 var(--text-xs)/1.3 var(--font-ui); letter-spacing: 0.04em; }
.record-entry.who-you .record-kicker,
.record-entry.who-auto .record-kicker { color: var(--teal-ink); }
.record-entry.is-amber .record-kicker { color: var(--amber-ink); }
.record-entry.is-failed .record-kicker { color: var(--red-ink); }
.record-meta time { color: var(--muted); font-size: var(--text-xs); font-variant-numeric: tabular-nums; }
.record-text { margin: 2px 0 0; color: var(--ink); font-size: var(--text-base); line-height: 1.6; overflow-wrap: anywhere; }
.record-entry.kind-asked .record-text { color: var(--muted); }
.record-entry.kind-step .record-text { color: var(--muted); font-size: var(--text-sm); }
.record-entry.kind-result .record-text { font-weight: 650; }
.record-entry.kind-note .record-text {
  margin-top: 4px;
  padding: 8px 10px;
  border-radius: var(--r-s);
  background: var(--teal-wash);
  white-space: pre-wrap;
}
.record-detail { margin: 4px 0 0; padding-left: 16px; color: var(--muted); font-size: var(--text-sm); line-height: 1.6; }
.record-go { margin-top: 4px; font-size: var(--text-sm); }
.record-foot {
  flex: 0 0 auto;
  padding: 12px 16px 14px;
  border-top: 1px solid var(--line-soft);
  background: var(--surface-2);
}
.record-foot-note { margin: 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.6; }
.record-foot .card-actions { margin-top: 10px; }
.record-link { display: block; margin-top: 10px; font-size: var(--text-sm); }
@media (prefers-reduced-motion: reduce) {
  .record-drawer { transition: none; }
}

/* ---- observations: what the author may really be after --------------------------------------
   A card like any other; its grounds are tagged by whose they are (you, your data, the field),
   and yes and no carry the same weight. */
.record-observation {
  margin: 12px 0 4px;
  padding: 14px 16px;
  border: 1px solid var(--teal-line);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.record-observation[hidden] { display: none; }
.record-observation-text { margin: 0; color: var(--ink); font: 650 var(--text-md)/1.6 var(--font-ui); }
.record-grounds { display: grid; gap: 5px; margin: 10px 0 0; padding: 0; list-style: none; }
.record-ground { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px; align-items: baseline; color: var(--muted); font-size: var(--text-sm); line-height: 1.55; }
.record-ground-tag {
  padding: 1px 6px;
  border-radius: var(--r-xs);
  background: var(--teal-wash);
  color: var(--teal-ink);
  font: 700 var(--text-xs)/1.5 var(--font-ui);
  white-space: nowrap;
}
.record-ground.is-data .record-ground-tag { background: var(--surface-3); color: var(--muted); }
.record-ground.is-field .record-ground-tag { background: var(--surface-3); color: var(--muted); }
.record-observation-so {
  margin: 10px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--line-soft);
  color: var(--ink);
  font-size: var(--text-base);
  line-height: 1.65;
}
.record-observation .card-actions[hidden],
.record-own[hidden],
.record-observation-done[hidden] { display: none; }
.record-own { margin-top: 12px; }
.record-own textarea {
  display: block;
  width: 100%;
  min-height: 56px;
  padding: 8px 10px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-s);
  color: var(--ink);
  font: var(--text-base)/1.6 var(--font-ui);
  resize: vertical;
}
.record-own textarea:focus { outline: none; border-color: var(--teal); }
.record-observation-done { margin: 10px 0 0; color: var(--teal-ink); font-size: var(--text-base); }
/* An observation waiting: a dot on the button, nothing that pops up. */
.record-open { position: relative; }
.record-dot-new { display: none; }
.record-open.has-observation .record-dot-new {
  display: block;
  position: absolute;
  top: 5px;
  right: 5px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--teal);
  box-shadow: 0 0 0 2px var(--surface);
}

/* ---- languages -------------------------------------------------------------------------------
   Twelve languages in one picker; the picker names each in its own language. */
.language-picker {
  min-height: 30px;
  max-width: 180px;
  padding: 0 26px 0 10px;
  border: 0;
  border-radius: var(--r-xs);
  background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='%2375868C' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 8px center / 10px 10px;
  color: var(--teal-deep);
  font: 650 var(--text-sm)/1.2 var(--font-ui);
  appearance: none;
  cursor: pointer;
}
.language-picker:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.account-menu .language-picker { min-height: 36px; }
/* Right to left: the page mirrors; numbers, sequence names and code keep their own direction. */
[dir="rtl"] .language-picker { padding: 0 10px 0 26px; background-position: left 8px center; }
[dir="rtl"] body { text-align: right; }
[dir="rtl"] .record-drawer,
[dir="rtl"] .files-drawer { right: auto; left: 0; border-left: 0; border-right: 1px solid var(--line); transform: translateX(calc(-100% - 72px)); }
[dir="rtl"] body[data-record="open"] .record-drawer,
[dir="rtl"] body[data-files="open"] .files-drawer { transform: none; }
[dir="rtl"] .record-entry::before { left: auto; right: 5.5px; }
[dir="rtl"] .record-dot { margin: 5px 1.5px 0 0; }
[dir="rtl"] .record-detail,
[dir="rtl"] .place-lines { padding-left: 0; padding-right: 16px; }
[dir="rtl"] .record-open.has-observation .record-dot-new { right: auto; left: 5px; }
[dir="rtl"] code, [dir="rtl"] .tt-svg, [dir="rtl"] input[type="password"] { direction: ltr; }

/* ---- a long page scrolls inside itself ----------------------------------------------------
   The shell is one screen tall: the header, its tabs and the assistant beside a report stay
   where they are while the reader goes down a long conclusion. Letting the page spill out
   made the whole document scroll, header and assistant with it. Each page keeps its own
   place when the reader switches away and back. */
.page:not(.chat-page) {
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

/* ---- the file, asked for in the conversation --------------------------------------------
   The same door as the welcome's: one place to drop or pick, no browser file boxes. */
.upload-card {
  padding: 14px 16px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.upload-card h2 { margin: 0 0 10px; color: var(--ink); font: 650 var(--text-md)/1.4 var(--font-ui); }
.upload-drop {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  border: 1px dashed var(--teal-soft);
  border-radius: var(--r-s);
  background: var(--surface-2);
  cursor: pointer;
  transition: border-color var(--t-quick) var(--ease-out), background-color var(--t-quick) var(--ease-out), scale var(--t-press) var(--ease-out);
}
.upload-drop:hover, .upload-drop:focus-within { border-color: var(--teal); background: var(--teal-wash); }
.upload-drop:focus-within { outline: 2px solid var(--teal); outline-offset: 2px; }
.upload-drop:active { scale: 0.99; }
.upload-drop-mark {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--r-m);
  background: var(--surface);
  color: var(--teal);
  box-shadow: 0 0 0 1px var(--teal-line);
}
.upload-drop-text { display: grid; gap: 2px; }
.upload-drop-text b { color: var(--teal-ink); font: 650 var(--text-md)/1.4 var(--font-ui); }
.upload-drop-text small { color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.upload-card .upload-example {
  margin: 10px 0 0;
  padding: 2px 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 600 var(--text-base)/1.5 var(--font-ui);
  cursor: pointer;
}
.upload-card .upload-example:hover { text-decoration: underline; text-underline-offset: 3px; }
.upload-card.is-done .upload-example { display: none; }
.upload-card .upload-status { margin: 8px 0 0; color: var(--muted); font-size: var(--text-base); }
.upload-card .upload-status:empty { display: none; }
.upload-card.is-sending .upload-drop { opacity: 0.6; pointer-events: none; }
.upload-card.is-done .upload-drop { display: none; }
.upload-card.is-done .upload-status { color: var(--teal-ink); }

/* ==========================================================================================
   Motion.
   One vocabulary for everything that moves, so the page feels like one object:
     - Things arrive on a spring and leave quickly. An entrance settles (a spring with a
       barely visible overshoot); an exit gets out of the way (a short ease-in). Leaving is
       always faster than arriving.
     - Only transform and opacity move. Movement uses the individual `translate` and `scale`
       properties, so it composes with any `transform` a surface already uses to sit in place.
     - Everything shown by toggling `hidden` fades and scales in and out in place
       (@starting-style for the entrance, `display ... allow-discrete` for the exit); a browser
       without those simply shows and hides, as before.
     - Asked for less motion, the page keeps fades of opacity and nothing that travels.
   ========================================================================================== */
:root {
  /* Springs sampled from a damped oscillator (damping ratio 0.86, 0.78, 1.0). */
  --spring: linear(0, 0.047, 0.1551, 0.2879, 0.4233, 0.5485, 0.6572, 0.7474, 0.8195, 0.8753, 0.9172, 0.9478,
    0.9693, 0.984, 0.9936, 0.9995, 1.0029, 1.0045, 1.005, 1.0049, 1.0044, 1.0037, 1.003, 1.0024, 1.0018, 1.0014,
    1.001, 1.0007, 1.0005, 1.0003, 1.0002, 1.0001, 1, 1);
  --spring-pop: linear(0, 0.0451, 0.1516, 0.286, 0.426, 0.5578, 0.6736, 0.7703, 0.8474, 0.9064, 0.9495, 0.9797,
    0.9994, 1.0113, 1.0175, 1.0198, 1.0195, 1.0177, 1.0152, 1.0124, 1.0097, 1.0072, 1.0052, 1.0035, 1.0022, 1.0013,
    1.0006, 1.0001, 1, 1);
  --settle: linear(0, 0.0502, 0.16, 0.2893, 0.4165, 0.5313, 0.6296, 0.7111, 0.777, 0.8294, 0.8704, 0.9021, 0.9265,
    0.945, 0.9591, 0.9696, 0.9775, 0.9834, 0.9878, 0.991, 0.9934, 0.9952, 0.9965, 0.9974, 0.9981, 0.9987, 0.999,
    0.9993, 0.9995, 0.9997, 0.9999, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.32, 0, 0.67, 0);
  --t-press: 90ms;    /* a finger on a button */
  --t-quick: 160ms;   /* colour, a fade that accompanies a move */
  --t-base: 240ms;    /* a backdrop, a small change in place */
  --t-exit: 200ms;    /* anything leaving */
  --t-pop: 440ms;     /* a menu, a card, a dialog arriving */
  --t-sheet: 560ms;   /* a drawer arriving */
}
@supports not (transition-timing-function: linear(0, 1)) {
  :root {
    --spring: cubic-bezier(0.32, 0.72, 0, 1);
    --spring-pop: cubic-bezier(0.34, 1.25, 0.64, 1);
    --settle: cubic-bezier(0.22, 1, 0.36, 1);
  }
}

/* ---- sheets: the drawers slide on a spring, and leave quickly ---------------------------- */
.files-drawer,
.record-drawer,
.inspector,
.assistant-rail { transition: transform var(--t-exit) var(--ease-in); }
body[data-files="open"] .files-drawer,
body[data-record="open"] .record-drawer,
.chat-page[data-drawer="open"] .inspector,
body[data-rail-drawer="open"] .assistant-rail { transition: transform var(--t-sheet) var(--spring); }
/* On page 01 the rail comes in over the conversation from the edge it belongs to. */
body[data-page="chat"][data-rail-peek="open"] .assistant-rail { transition: translate var(--t-sheet) var(--spring); }
@starting-style {
  body[data-page="chat"][data-rail-peek="open"] .assistant-rail { translate: 100% 0; }
}

/* ---- backdrops fade, they never snap ---------------------------------------------------- */
:is(.files-backdrop, .rail-backdrop, .inspector-backdrop, .library-backdrop) {
  opacity: 1;
  transition: opacity var(--t-base) var(--ease-out), display var(--t-base) allow-discrete;
}
:is(.files-backdrop, .rail-backdrop, .inspector-backdrop, .library-backdrop)[hidden] {
  opacity: 0;
  transition-duration: var(--t-exit);
  transition-timing-function: var(--ease-in);
}
@starting-style {
  :is(.files-backdrop, .rail-backdrop, .inspector-backdrop, .library-backdrop):not([hidden]) { opacity: 0; }
}

/* ---- menus and popovers grow from where they were asked for ---------------------------- */
.run-list, .account-menu { transform-origin: top right; }
[dir="rtl"] :is(.run-list, .account-menu) { transform-origin: top left; }
:is(.run-list, .account-menu, .library) {
  transition: opacity var(--t-quick) var(--ease-out), scale var(--t-pop) var(--spring),
    translate var(--t-pop) var(--spring), display var(--t-pop) allow-discrete;
}
:is(.run-list, .account-menu, .library)[hidden] {
  opacity: 0;
  scale: 0.96;
  translate: 0 -4px;
  transition-duration: 140ms;
  transition-timing-function: var(--ease-in);
}
@starting-style {
  :is(.run-list, .account-menu):not([hidden]) { opacity: 0; scale: 0.96; translate: 0 -6px; }
  .library:not([hidden]) { opacity: 0; scale: 0.97; translate: 0 10px; }
}

/* ---- dialogs ---------------------------------------------------------------------------- */
.confirm-dialog {
  transition: opacity var(--t-quick) var(--ease-out), scale var(--t-pop) var(--spring),
    display var(--t-pop) allow-discrete, overlay var(--t-pop) allow-discrete;
}
.confirm-dialog:not([open]) {
  opacity: 0;
  scale: 0.96;
  transition-duration: 150ms;
  transition-timing-function: var(--ease-in);
}
@starting-style { .confirm-dialog[open] { opacity: 0; scale: 0.96; } }
.confirm-dialog::backdrop {
  transition: background-color var(--t-base) var(--ease-out), display var(--t-base) allow-discrete,
    overlay var(--t-base) allow-discrete;
}
.confirm-dialog:not([open])::backdrop { background-color: transparent; }
@starting-style { .confirm-dialog[open]::backdrop { background-color: transparent; } }

/* ---- what arrives in the conversation --------------------------------------------------- */
@keyframes arrive {
  from { opacity: 0; translate: 0 10px; scale: 0.985; }
}
@keyframes arrive-small {
  from { opacity: 0; translate: 0 6px; scale: 0.96; }
}
@keyframes fade-in {
  from { opacity: 0; }
}
.bubble, .rail-bubble { animation: arrive var(--t-pop) var(--spring) backwards; }
.bubble.user, .rail-bubble.user { transform-origin: bottom right; }
.place-card, .plan-card, .decision-card, .step-card, .upload-card, .bubble-action { animation: arrive var(--t-pop) var(--spring) backwards; }
/* Answers offered as chips come in one after another, quickly enough to read as one gesture. */
:is(.choice-row, .rail-choices) > * { animation: arrive-small var(--t-pop) var(--spring-pop) backwards; }
:is(.choice-row, .rail-choices) > :nth-child(2) { animation-delay: 30ms; }
:is(.choice-row, .rail-choices) > :nth-child(3) { animation-delay: 60ms; }
:is(.choice-row, .rail-choices) > :nth-child(4) { animation-delay: 90ms; }
:is(.choice-row, .rail-choices) > :nth-child(5) { animation-delay: 120ms; }
:is(.choice-row, .rail-choices) > :nth-child(n + 6) { animation-delay: 150ms; }
/* A history put back on opening a run is shown as one piece; only what is new arrives. */
:is(.transcript, .rail-transcript) > .is-replayed,
:is(.transcript, .rail-transcript) > .is-replayed * { animation: none; }
:is(.transcript, .rail-transcript).is-arriving { animation: fade-in 320ms var(--ease-out) both; }
/* A card opens top to bottom: what it is, then what it holds, then what can be done with it. */
.is-entering > * { animation: fade-in var(--t-base) var(--ease-out) both; }
.is-entering > :nth-child(2) { animation-delay: 70ms; }
.is-entering > :nth-child(3) { animation-delay: 140ms; }
.is-entering > :nth-child(4) { animation-delay: 210ms; }
.is-entering > :nth-child(n + 5) { animation-delay: 260ms; }
/* The welcome reads top to bottom: what this is, what it asks of you, the two ways in, then the
   quieter ways to look around. Each step lands a beat after the one above it. */
.empty-state > * { animation: arrive-small var(--t-pop) var(--settle) backwards; }
.empty-state > :nth-child(2) { animation-delay: 50ms; }
.empty-state > :nth-child(3) { animation-delay: 110ms; }
.empty-state > :nth-child(4) { animation-delay: 190ms; }
.empty-state > :nth-child(5) { animation-delay: 260ms; }
.empty-state > :nth-child(n + 6) { animation-delay: 320ms; }
.opening-questions > * { animation: fade-in var(--t-base) var(--ease-out) both; animation-delay: 260ms; }
.opening-questions > :nth-child(2) { animation-delay: 300ms; }
.opening-questions > :nth-child(3) { animation-delay: 340ms; }
.opening-questions > :nth-child(n + 4) { animation-delay: 380ms; }
/* The conclusion's cards settle into place in reading order. */
.conclusion-cards > * { animation: arrive var(--t-pop) var(--spring) backwards; }
.conclusion-cards > :nth-child(2) { animation-delay: 40ms; }
.conclusion-cards > :nth-child(3) { animation-delay: 80ms; }
.conclusion-cards > :nth-child(n + 4) { animation-delay: 120ms; }

/* ---- what the page tells you comes in quietly, and leaves faster ------------------------
   The dock, the run board, notices and error lines fade in with a few pixels of settle and
   fade out a little quicker; nothing slides across the page. A line that changed its words
   in place fades them in again, once. */
:is(.next-step, .rail-next-step, .run-board, .run-error, .run-narration, .run-eta, .login-error,
    .welcome-error, .session-dead-banner, .session-form-error, .login-hint, .nodes-notice) {
  transition: opacity var(--t-base) var(--ease-out), translate var(--t-pop) var(--settle),
    display var(--t-base) allow-discrete;
}
:is(.next-step, .rail-next-step, .run-board, .run-error, .run-narration, .run-eta, .login-error,
    .welcome-error, .session-dead-banner, .session-form-error, .login-hint, .nodes-notice)[hidden] {
  opacity: 0;
  translate: 0 4px;
  transition-duration: var(--t-exit);
  transition-timing-function: var(--ease-in);
}
@starting-style {
  :is(.next-step, .rail-next-step, .run-board, .run-error, .run-narration, .run-eta, .login-error,
      .welcome-error, .session-dead-banner, .session-form-error, .login-hint, .nodes-notice):not([hidden]) {
    opacity: 0;
    translate: 0 4px;
  }
}
/* The next step comes in a beat after what it follows from, so the eye reads the news first and
   the action second. Leaving is immediate. */
:is(.next-step, .rail-next-step):not([hidden]) { transition-delay: 200ms, 200ms, 0s; }
.is-resaid { animation: resay 360ms var(--ease-out); }
@keyframes resay { from { opacity: 0.25; } }
/* A wait is only shown if it lasts: a quick answer never flashes the dots. */
.thinking { animation: fade-in var(--t-base) var(--ease-out) 180ms both; }
.thinking-text { animation: fade-in var(--t-base) var(--ease-out) both; }

/* ---- the record's observation, and a filter changing the timeline ----------------------- */
.record-observation {
  transition: opacity var(--t-base) var(--ease-out), translate var(--t-pop) var(--spring),
    scale var(--t-pop) var(--spring), display var(--t-pop) allow-discrete;
}
.record-observation[hidden] { opacity: 0; scale: 0.98; transition-duration: var(--t-exit); transition-timing-function: var(--ease-in); }
@starting-style { .record-observation:not([hidden]) { opacity: 0; translate: 0 8px; scale: 0.98; } }
.record-list.is-refiltered { animation: fade-in var(--t-base) var(--ease-out); }
.record-observation-done:not([hidden]) { animation: fade-in var(--t-base) var(--ease-out); }

/* ---- panels that open in place grow to their height -------------------------------------- */
:root { interpolate-size: allow-keywords; }
.rail-panel-body {
  overflow: clip;
  transition: height var(--t-pop) var(--settle), opacity var(--t-base) var(--ease-out), display var(--t-pop) allow-discrete;
}
.rail-panel-body[hidden] { height: 0; opacity: 0; transition-duration: var(--t-exit); transition-timing-function: var(--ease-in); }
@starting-style { .rail-panel-body:not([hidden]) { height: 0; opacity: 0; } }
.rail-panel-caret { transition: rotate var(--t-pop) var(--spring); }
.rail-panel-head[aria-expanded="true"] .rail-panel-caret { rotate: 180deg; }

/* ---- a finger on a control: it gives, a little ------------------------------------------ */
:is(.btn-primary, .btn-secondary, .choice-chip, .starter-chip, .library-chip, .rail-choice-chip, .opening-question,
    .files-open, .rail-drawer, .inspector-toggle, .new-analysis, .dialog-actions button, .composer button[type="submit"],
    .rail-composer button, .welcome-recent-row, .door-file, .run-switch) {
  transition: scale var(--t-press) var(--ease-out), background-color var(--t-quick) var(--ease-out),
    border-color var(--t-quick) var(--ease-out), color var(--t-quick) var(--ease-out), box-shadow var(--t-quick) var(--ease-out);
}
:is(.btn-primary, .btn-secondary, .choice-chip, .starter-chip, .library-chip, .rail-choice-chip, .opening-question,
    .files-open, .rail-drawer, .inspector-toggle, .new-analysis, .dialog-actions button, .composer button[type="submit"],
    .rail-composer button, .run-switch):active:not(:disabled) { scale: 0.97; }
:is(.welcome-recent-row, .door-file):active { scale: 0.985; }

/* ---- a pointer over a control: it answers before the click --------------------------------
   What a click would do shows while the pointer rests on it, and the same on keyboard focus:
   an action that moves the analysis on lifts a pixel and deepens; an answer offered as a chip
   takes the accent's wash and nudges toward you; anything that cannot be taken back warms to
   red, so "停止" never looks safe the moment before it is pressed. Pressing settles it back. */
:is(.btn-primary, .btn-secondary, .run-actions button, .decision-choices button, .dialog-actions button,
    .conclusion-actions button, .rail-next-step-go, .choice-chip, .starter-chip, .rail-choice-chip,
    .opening-question, .welcome-recent-row, .library-open, .demo-start, .new-analysis, .composer button[type="submit"],
    .rail-composer button, .concl-followup button, .concl-related button) {
  transition: translate var(--t-quick) var(--ease-out), scale var(--t-press) var(--ease-out),
    background-color var(--t-quick) var(--ease-out), border-color var(--t-quick) var(--ease-out),
    color var(--t-quick) var(--ease-out), box-shadow var(--t-quick) var(--ease-out);
}
@media (hover: hover) {
  :is(.btn-primary, .run-actions button.is-primary, .decision-choices button.is-primary,
      .dialog-actions button.is-primary, .conclusion-actions button.is-primary, .rail-next-step-go,
      .library-open, .demo-start:not(.link), .composer button[type="submit"], .rail-composer button):hover:not(:disabled) {
    translate: 0 -1px;
    box-shadow: var(--shadow-accent);
  }
  :is(.btn-secondary, .run-actions button:not(.is-primary), .decision-choices button:not(.is-primary),
      .dialog-actions button:not(.is-primary), .choice-chip, .starter-chip:not(.link), .rail-choice-chip,
      .opening-question, .welcome-recent-row, .new-analysis):hover:not(:disabled) {
    translate: 0 -1px;
    box-shadow: 0 4px 12px -8px rgba(23, 39, 48, 0.35);
  }
}
:is(.btn-primary, .run-actions button, .decision-choices button, .dialog-actions button, .rail-next-step-go,
    .choice-chip, .starter-chip, .rail-choice-chip, .opening-question, .library-open, .demo-start,
    .composer button[type="submit"], .rail-composer button):focus-visible:not(:disabled) {
  box-shadow: var(--focus-ring);
}
/* Cannot be taken back: the hover says so in red, never in the accent. */
:is(.run-actions button.is-danger, .dialog-actions button.is-danger, .choice-chip.is-danger,
    .rail-choice-chip.is-danger, .run-row-menu button.is-danger):is(:hover, :focus-visible):not(:disabled) {
  border-color: var(--red);
  background: var(--red-wash);
  color: var(--red-ink);
  box-shadow: 0 4px 12px -8px rgba(162, 67, 44, 0.55);
}
.dialog-actions button.is-primary.is-danger:is(:hover, :focus-visible):not(:disabled) {
  border-color: var(--red-ink);
  background: var(--red-ink);
  color: var(--surface);
}
:is(.btn-primary, .btn-secondary, .run-actions button, .decision-choices button, .dialog-actions button,
    .choice-chip, .starter-chip, .rail-choice-chip, .opening-question, .welcome-recent-row, .library-open,
    .demo-start, .new-analysis, .composer button[type="submit"], .rail-composer button, .rail-next-step-go):active:not(:disabled) {
  translate: 0 0;
  box-shadow: none;
}

/* ---- the navigation: one pill slides to the page you chose ------------------------------ */
.top-nav { position: relative; }
.top-nav.has-pill a.active { background: transparent; box-shadow: none; }
.top-nav.has-pill a { position: relative; z-index: 1; transition: color var(--t-quick) var(--ease-out); }
.nav-pill {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  border-radius: var(--r-s);
  background: var(--surface);
  box-shadow: 0 1px 4px rgba(24, 58, 62, 0.08);
  pointer-events: none;
  opacity: 0;
}
.nav-pill.is-placed { opacity: 1; }
.nav-pill.is-moving {
  transition: translate var(--t-pop) var(--spring), width var(--t-pop) var(--spring), opacity var(--t-quick) var(--ease-out);
}

/* ---- pages: the one that arrives settles in, leaning the way you went ------------------- */
/* `backwards`, not `both`: a finished arrival must leave no `translate` behind. `translate: 0px` is
   not `none`, and it made every page a stacking context and the box its fixed children are placed
   in, so a sheet opened from the page (the inspector on a phone) sat under the backdrop and off
   by the page's own offset. */
.page:not([hidden]) { animation: arrive-page 360ms var(--settle) backwards; }
html[data-nav="forward"] .page:not([hidden]) { animation-name: arrive-forward; }
html[data-nav="back"] .page:not([hidden]) { animation-name: arrive-back; }
@keyframes arrive-page { from { opacity: 0; translate: 0 6px; } }
@keyframes arrive-forward { from { opacity: 0; translate: 16px 0; } }
@keyframes arrive-back { from { opacity: 0; translate: -16px 0; } }
[dir="rtl"][data-nav="forward"] .page:not([hidden]) { animation-name: arrive-back; }
[dir="rtl"][data-nav="back"] .page:not([hidden]) { animation-name: arrive-forward; }

/* ---- less motion, when asked ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  :root { --t-pop: 1ms; --t-sheet: 1ms; --t-press: 1ms; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
  :is(.btn-primary, .btn-secondary, .choice-chip):active:not(:disabled) { scale: none; }
  /* The hover still says what a click would do, in colour and shadow; it just does not lift. */
  :is(.btn-primary, .btn-secondary, .run-actions button, .decision-choices button, .dialog-actions button,
      .conclusion-actions button, .rail-next-step-go, .choice-chip, .starter-chip, .rail-choice-chip,
      .opening-question, .welcome-recent-row, .library-open, .demo-start, .new-analysis, .composer button,
      .rail-composer button):hover { translate: none; }
  /* Nothing slides out either; a drawer or menu that leaves simply goes. */
  :root { --t-exit: 1ms; }
  :is(.next-step, .rail-next-step):not([hidden]) { transition-delay: 0s; }
}

/* ---- a run in the background leaves the conversation in front ---------------------------------
   While a run works, the board is one row: where it is, how far along, and a way to look closer.
   The steps and the live log open on request (the choice is remembered). A failure opens the same
   way: what stopped and what to do first, the steps and the tool's last output one click away
   (the dock's 查看详情 opens them too). A waiting decision does the same: the card under the board
   asks the question, and the board above it only says where the run stands. */
.run-board-toggle { flex: 0 0 auto; align-self: center; }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact {
  padding: 12px 18px;
  max-height: none;
  overflow: visible;
}
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact .run-head {
  align-items: center;
  flex-wrap: nowrap;
}
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact .run-kicker { margin-bottom: 4px; }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board #run-headline { margin: 0; font-size: var(--text-2xl); }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact .run-count { font-size: var(--text-sm); }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact .run-progress { margin: 10px 0 0; }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact .run-narration { display: none; }
/* Closed, the details keep their place in the flow at zero height (so they can grow back in
   place) and leave the tab order once the close has finished. */
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact .run-split {
  visibility: hidden;
  transition: visibility 0s linear var(--t-exit);
}
.chat-page:not([data-mode="running"]):not([data-mode="gate"]):not([data-mode="failed"]) .run-board-toggle { display: none; }

/* A way in that was refused says so where it was clicked, and the welcome stays around it. */
.welcome-error {
  justify-self: center;
  margin: 10px auto 0;
  max-width: 560px;
  padding: 8px 12px;
  border: 1px solid var(--red-line);
  border-radius: var(--r-s);
  background: var(--red-wash);
  color: var(--red-ink);
  font-size: var(--text-base);
  line-height: 1.5;
  text-align: center;
}
.welcome-error[hidden] { display: none; }

/* A decision or a stopped step is named once, at the top of the board, and the card in the
   conversation carries its content. The dock under them said the same title again in large type
   (three times in all while a decision waited), so in those modes it is one line: "下一步", the
   buttons, and for a failure the technical details. The board's narration line, which restated
   the card, steps back while a decision waits. */
.next-step[data-compact="1"] { flex-wrap: nowrap; gap: 10px; padding: 8px 10px 8px 14px; }
.next-step[data-compact="1"] #next-step-title { display: none; }
.next-step[data-compact="1"] .next-step-text {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  min-width: 0;
}
.next-step[data-compact="1"] .next-step-kicker { display: inline; margin: 0; }
.next-step[data-compact="1"] .next-step-more { margin-top: 0; }
.next-step[data-compact="1"] .run-actions { flex: none; width: auto; }
.chat-page[data-mode="gate"] #run-narration { display: none; }

/* What tells two runs of the same name apart: quieter than the name, on the same line. */
.run-name-hint {
  color: var(--muted);
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: 500;
}

/* The offer to name a big tree's tips sits right under the drawing. */
.tree-names-toggle {
  display: block;
  margin: 6px 0 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 650 var(--text-sm)/1.5 var(--font-ui);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
/* Named, a big tree is thousands of pixels tall: on the conclusion it scrolls in its box, as it
   does in the conversation, instead of pushing the evidence a page away. */
.concl-hero-canvas { max-height: 560px; overflow: auto; }

/* A step the person stopped is not a failure: the same line, without the alarm. */
.chat-page[data-mode="failed"] .run-error[data-tone="quiet"] {
  border-color: var(--line);
  background: var(--wash);
  color: var(--ink-2);
}

/* The pool in one sentence, under its numbers. */
.nodes-notice {
  margin: 8px 0 0;
  max-width: 56rem;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--wash);
  color: var(--ink-2);
  font-size: var(--text-base);
  line-height: 1.55;
}
.nodes-notice[hidden] { display: none; }
.nodes-notice[data-tone="problem"] { border-color: var(--red-line); background: var(--red-wash); color: var(--red-ink); }

/* Signed out, the first paint is the sign-in card: the workbench is not drawn behind it for the
   moment the session check takes (index.html sets data-auth before the stylesheet applies). */
html[data-auth="out"] .app { visibility: hidden; }
html[data-auth="out"] #login-gate[hidden] { display: flex; }

/* The recommended option says so in a word, where a percentage used to stand. */
.delib-badge:empty { display: none; }
.delib-badge {
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--teal);
  color: var(--surface);
  font: 700 var(--text-xs)/1.4 var(--font-ui);
}
.step-card.is-done .delib-badge { background: var(--faint); }

/* On a phone the board is a status line, not a hero: a smaller headline, and a failure's reason
   in two lines that open on a tap (the whole paragraph took a third of the screen above the
   conversation it is about). */
@media (max-width: 680px) {
  .run-board #run-headline { margin-bottom: 2px; font-size: var(--text-2xl); }
  .run-board .run-kicker { margin-bottom: 4px; }
  .run-board .run-progress { margin-top: 6px; }
  .chat-page[data-mode="failed"] .run-error:not(.is-open) {
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    cursor: pointer;
    /* The bottom padding would show the top of a third line; a border in the box's own colour
       keeps the spacing and clips cleanly. */
    padding-bottom: 0;
    border-bottom: 10px solid var(--red-wash);
  }
  .chat-page[data-mode="failed"] .run-error[data-tone="quiet"]:not(.is-open) { border-bottom-color: var(--wash); }
}

/* ---- the run board is one card, and its details a labelled panel inside it -------------------
   Opened, the steps and the live log used to be laid straight onto the page with the headline
   jumping in size and the conversation starting right under them, which read as the layout
   breaking. The board is now a card with its own surface and edge; the headline keeps its size;
   the details sit in an inset panel under a label, and open by growing in place. */
.run-board {
  margin: 12px 16px 4px;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--surface-2);
  box-shadow: var(--shadow-2);
}
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact { padding: 12px 18px; }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board:not(.is-compact) { padding: 16px 20px 18px; }

.run-details {
  display: grid;
  grid-template-rows: 1fr;
  opacity: 1;
  transition:
    grid-template-rows var(--t-pop) var(--ease-out),
    opacity var(--t-base) var(--ease-out);
}
.run-details-inner {
  min-height: 0;
  overflow: hidden;
}
.run-details-label {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 14px 0 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  color: var(--ink-2);
  font: 700 var(--text-sm)/1.3 var(--font-ui);
}
.run-details-label small { color: var(--muted); font-weight: 500; }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board.is-compact .run-details {
  grid-template-rows: 0fr;
  opacity: 0;
  transition:
    grid-template-rows var(--t-exit) ease-in,
    opacity var(--t-quick) ease-in;
}
/* The panel keeps a fixed, scrolling height: the steps and the log scroll inside it, so the
   board never grows past the conversation it sits above. */
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board .run-split { height: min(240px, 28vh); }
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .run-board:not(.is-compact) { max-height: none; overflow: visible; }
/* What scrolls up under the board fades out rather than being cut at its edge. */
.chat-page[data-mode="running"] .transcript,
.chat-page[data-mode="gate"] .transcript,
.chat-page[data-mode="failed"] .transcript {
  -webkit-mask: linear-gradient(to bottom, transparent 0, #000 18px);
  mask: linear-gradient(to bottom, transparent 0, #000 18px);
}
.run-split .run-steps { padding-right: 4px; }

/* The toggle: a quiet pill whose chevron says which way it goes. */
.run-board-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font: 650 var(--text-sm)/1 var(--font-ui);
  text-decoration: none;
  cursor: pointer;
}
.run-board-chevron { transition: transform var(--t-base) var(--ease-out); }
.run-board-toggle[aria-expanded="true"] .run-board-chevron { transform: rotate(180deg); }

/* ---- a reply written out at reading pace ------------------------------------------------------
   Each piece fades in (opacity only, so it stays on the compositor); a thin caret sits at the end until the sentence is
   whole. Nothing moves sideways and nothing bounces: the text arrives, it does not perform. */
.stream-chunk { animation: stream-in 260ms var(--ease-out) both; }
@keyframes stream-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.is-streaming > .stream-text::after {
  content: "";
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin-left: 2px;
  vertical-align: -0.18em;
  border-radius: var(--r-2xs);
  background: var(--teal);
  opacity: 0.55;
  animation: stream-caret 1s ease-in-out infinite;
}
@keyframes stream-caret { 50% { opacity: 0.1; } }
@media (prefers-reduced-motion: reduce) {
  .stream-chunk, .is-streaming > .stream-text::after { animation: none; }
}

/* ---- auto-confirm: a switch where the work is typed ---------------------------------------------
   Beside Send, so it is found without looking and turned either way at any point. The track says
   which way it is at a glance; the word stays the same, the tooltip says what each side means. */
.composer .autopilot-switch {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 30px;
  margin-right: 6px;
  padding: 0 10px 0 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--muted);
  font: 650 var(--text-sm)/1 var(--font-ui);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color var(--t-quick) var(--ease-out), background-color var(--t-quick) var(--ease-out),
    color var(--t-quick) var(--ease-out);
}
.composer .autopilot-switch[hidden] { display: none; }
.autopilot-track {
  position: relative;
  width: 26px;
  height: 16px;
  border-radius: var(--r-pill);
  background: var(--line-strong);
  transition: background-color var(--t-base) var(--ease-out);
}
.autopilot-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(23, 39, 48, 0.25);
  transition: translate var(--t-pop) var(--spring);
}
[dir="rtl"] .autopilot-thumb { left: auto; right: 2px; }
.composer .autopilot-switch[aria-checked="true"] { border-color: var(--teal-line); background: var(--teal-wash); color: var(--teal-deep, var(--teal-deep)); }
.autopilot-switch[aria-checked="true"] .autopilot-track { background: var(--teal); }
.autopilot-switch[aria-checked="true"] .autopilot-thumb { translate: 10px 0; }
[dir="rtl"] .autopilot-switch[aria-checked="true"] .autopilot-thumb { translate: -10px 0; }
@media (hover: hover) {
  .composer .autopilot-switch:hover { border-color: var(--teal); color: var(--ink); }
  .composer .autopilot-switch[aria-checked="false"]:hover .autopilot-track { background: var(--line-strong); }
}
.composer .autopilot-switch:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.composer .autopilot-switch:active { scale: 0.97; }
/* On a phone the word goes; the switch and its tooltip-name stay. */
@media (max-width: 520px) {
  .composer .autopilot-switch { padding: 0 7px; }
  .composer .autopilot-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
}
/* The switch takes room from the sentence; the composer grows by as much, not the placeholder less. */
.composer:has(.autopilot-switch:not([hidden])) { width: min(100%, 40rem); }
.composer textarea::placeholder { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Until the reader's catalog has been applied the words stay out of sight (a second at most). */
html[data-i18n="pending"] body { visibility: hidden; }

/* ---- the step's log, as someone watching it sees it ---------------------------------------------
   New lines fade in under the old ones; a tool's own output is set in a slightly quieter ink and
   the "still running" lines quieter still; a cursor sits at the end while the step is working. */
.run-log .log-line { display: inline; }
.run-log .log-tool { color: var(--muted); }
.run-log .log-beat { color: var(--subtle); }
.run-log .log-line.is-new { animation: log-in 420ms var(--ease-out) both; }
@keyframes log-in { from { opacity: 0; } to { opacity: 1; } }
.run-log.is-live::after {
  content: "";
  display: inline-block;
  width: 0.55em;
  height: 1.05em;
  margin-left: 1px;
  vertical-align: -0.2em;
  background: var(--teal);
  opacity: 0.5;
  animation: log-caret 1.1s steps(2, jump-none) infinite;
}
@keyframes log-caret { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .run-log .log-line.is-new, .run-log.is-live::after { animation: none; }
}
.run-log-status {
  flex: 0 0 auto;
  margin: 6px 0 0;
  padding-top: 6px;
  border-top: 1px dashed var(--line-soft);
  color: var(--subtle);
  font: var(--text-xs)/1.4 var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.run-log-status[hidden] { display: none; }
.run-log-status::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--teal);
  vertical-align: 1px;
  animation: log-pulse 1.6s ease-in-out infinite;
}
@keyframes log-pulse { 50% { opacity: 0.3; } }
@media (prefers-reduced-motion: reduce) { .run-log-status::before { animation: none; } }


/* ==========================================================================================
   Tree explorer (web/tree-explorer.js): the trees page draws the run's tree itself.
   Grey is the tree, teal what the reader acts on, amber a caution, ink the selected clade.
   ========================================================================================== */
/* The trees page's two views sit in the page's head, where the other report pages keep their
   section tabs (the tabs family, web/design/components.css). */
.stage-head .trees-switch { align-self: flex-start; }

/* A card on the page like the reports' sections: from the page's left edge, to its right one. */
.tree-explorer {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin: var(--space-1) var(--page-gutter) var(--space-6);
  overflow: hidden;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
.tree-explorer[hidden] { display: none; }

.tx-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
}
.tx-control { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: var(--text-sm); }
.tx-control[hidden] { display: none; }
.tx-select,
.tx-search-input,
.tx-group-input,
.tx-filter-find,
.tx-site-input {
  min-height: 30px;
  padding: 4px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: var(--text-sm)/1.3 var(--font-ui);
}
.tx-select { max-width: 12rem; }
.tx-segmented { display: inline-flex; }
.tx-site { position: relative; display: inline-flex; align-items: center; gap: 8px; }
/* The sites to pick from, under the box: the most-changed first, each with how often it changed. */
.tx-site-pick {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  width: min(20rem, 86vw);
  max-height: 300px;
  padding: 6px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: 0 14px 36px rgba(24, 58, 62, 0.16);
}
.tx-site-pick[hidden] { display: none; }
.tx-site-pick-head { margin: 2px 6px 6px; color: var(--muted); font-size: var(--text-xs); line-height: 1.45; }
.tx-site-pick-group { margin: 8px 8px 2px; color: var(--subtle); font: 700 var(--text-xs)/1.3 var(--font-ui); }
.tx-site-opt {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 8px;
  border: 0;
  border-radius: var(--r-s);
  background: none;
  color: var(--ink);
  font: 600 var(--text-sm)/1.3 var(--font-ui);
  text-align: start;
  cursor: pointer;
}
.tx-site-opt small { color: var(--muted); font-weight: 500; font-size: var(--text-xs); }
.tx-site-opt:hover, .tx-site-opt:focus-visible { background: var(--teal-wash); color: var(--teal-ink); outline: none; }
.tx-site-opt.is-current { box-shadow: inset 0 0 0 1px var(--teal-line); }
.tx-site[hidden] { display: none; }
.tx-site-input { width: 13rem; }
.tx-site-note { color: var(--amber-ink); font-size: var(--text-xs); max-width: 22rem; }
.tx-segmented[hidden] { display: none; }
.tx-search { display: inline-flex; align-items: center; gap: 8px; flex: 1 1 14rem; min-width: 12rem; flex-wrap: wrap; }
.tx-search-input { flex: 1; min-width: 0; }
.tx-search-count { color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
.tx-toggles { display: inline-flex; gap: 12px; }
.tx-toggle { display: inline-flex; align-items: center; gap: 5px; color: var(--muted); font-size: var(--text-sm); cursor: pointer; white-space: nowrap; }
.tx-toggle[hidden] { display: none; }
.tx-toggle input { accent-color: var(--teal); margin: 0; }
.tx-zoom, .tx-out { display: inline-flex; align-items: center; gap: 4px; }
.tx-icon,
.tx-button {
  min-width: 30px;
  min-height: 30px;
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font: 600 var(--text-sm)/1 var(--font-ui);
  cursor: pointer;
}
.tx-icon:hover, .tx-button:hover { border-color: var(--teal); color: var(--teal-ink, var(--teal-ink)); }
.tx-button.is-primary { border-color: var(--teal); background: var(--teal); color: var(--surface); }
.tx-button.is-primary:hover { background: var(--teal-deep, var(--teal-deep)); color: var(--surface); }
.tx-link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--teal);
  font: 600 var(--text-sm)/1.3 var(--font-ui);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.tx-link:hover { text-decoration: underline; }
.tx-link[hidden] { display: none; }

.tx-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 14px;
  padding: 6px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--wash);
  color: var(--muted);
  font-size: var(--text-sm);
}
.tx-note[hidden] { display: none; }
.tx-note-count { color: var(--ink); font-weight: 600; }
.tx-note-source { font-size: var(--text-xs); }
.tx-note-warn { color: var(--amber-ink, var(--amber-ink)); }
.tx-note-warn::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 6px; border-radius: 50%; background: var(--amber); vertical-align: 1px; }

.tx-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 17.5rem;
}
.tx-stage {
  position: relative;
  min-width: 0;
  min-height: 320px;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
  outline: none;
}
.tx-stage.is-pointing { cursor: pointer; }
.tx-stage.is-dragging { cursor: grabbing; }
.tx-stage:focus-visible { box-shadow: inset 0 0 0 2px var(--teal-line, var(--teal-line)); }
.tx-canvas { position: absolute; inset: 0; display: block; }
.tx-overlay { pointer-events: none; }
.tx-axis-title {
  position: absolute;
  right: 12px;
  bottom: 2px;
  color: var(--muted);
  font-size: var(--text-xs);
  pointer-events: none;
}
.tx-status {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  color: var(--muted);
  text-align: center;
  background: var(--surface);
}
.tx-status[hidden] { display: none; }
.tx-tooltip {
  position: absolute;
  top: 0;
  left: 0;
  max-width: 230px;
  padding: 6px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: rgba(255, 255, 255, 0.97);
  box-shadow: 0 4px 14px rgba(23, 39, 48, 0.08);
  font-size: var(--text-sm);
  pointer-events: none;
}
.tx-tooltip[hidden] { display: none; }
.tx-tip-title { font-weight: 600; word-break: break-all; }
.tx-tip-line { color: var(--muted); }

.tx-side {
  min-height: 0;
  overflow: auto;
  border-left: 1px solid var(--line);
  background: var(--surface);
}
.tx-panel, .tx-legend { padding: 12px 14px; }
.tx-panel[hidden], .tx-legend[hidden] { display: none; }
.tx-legend { border-top: 1px solid var(--line-soft, var(--line-soft)); }
.tx-hint { margin: 0; color: var(--muted); font-size: var(--text-sm); }
.tx-panel-head { display: grid; grid-template-columns: 1fr auto; gap: 0 8px; align-items: start; }
.tx-panel-kind { grid-column: 1; color: var(--muted); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; }
.tx-clade-tag { display: inline-block; margin-left: 4px; padding: 0 5px; border: 1px solid var(--ink); border-radius: 4px; color: var(--ink); font-weight: 600; text-transform: none; letter-spacing: 0; }
.tx-panel-title { grid-column: 1; margin: 2px 0 8px; font-size: var(--text-md); line-height: 1.35; word-break: break-all; }
.tx-close { grid-column: 2; grid-row: 1 / span 2; min-width: 28px; min-height: 28px; font-size: var(--text-lg); }
/* The label column is capped so a long field name ("Serotype (Genbank metadata)") wraps itself
   instead of squeezing the value to one letter a line. */
.tx-facts { display: grid; grid-template-columns: minmax(0, 9.5em) minmax(0, 1fr); gap: 4px 10px; margin: 0 0 8px; font-size: var(--text-sm); }
.tx-facts dt { color: var(--muted); }
.tx-facts dd { margin: 0; word-break: break-word; }
.tx-support { display: inline-flex; align-items: center; gap: 6px; }
.tx-dot { display: inline-block; flex: none; width: 9px; height: 9px; border-radius: 50%; }
.tx-inferred { margin: 0 0 8px; font-size: var(--text-sm); }
.tx-section { margin-top: 10px; }
.tx-section[hidden] { display: none; }
.tx-section h4 { margin: 0 0 6px; color: var(--muted); font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.tx-bars { margin: 0; padding: 0; list-style: none; display: grid; gap: 4px; font-size: var(--text-sm); }
.tx-bars li { display: grid; grid-template-columns: minmax(0, 7rem) 1fr auto; align-items: center; gap: 8px; }
.tx-bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tx-bar-track { height: 8px; border-radius: var(--r-2xs); background: var(--line-soft, var(--line-soft)); overflow: hidden; }
.tx-bar-fill { display: block; height: 100%; border-radius: var(--r-2xs); }
.tx-bar-count { color: var(--muted); font-variant-numeric: tabular-nums; }
.tx-muts { margin: 0 0 4px; font-size: var(--text-sm); line-height: 1.5; }
.tx-muts code { font-size: var(--text-xs); word-break: break-word; }
.tx-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.tx-legend-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.tx-legend-title { margin: 0; font-size: var(--text-sm); font-weight: 600; }
.tx-legend-list { margin: 0 0 6px; padding: 0; list-style: none; }
.tx-legend-button {
  width: 100%;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  padding: 3px 6px;
  border: 0;
  border-radius: var(--r-xs);
  background: none;
  color: var(--ink);
  font: var(--text-sm)/1.35 var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.tx-legend-button:hover { background: var(--wash); }
.tx-legend-item.is-picked .tx-legend-button { background: var(--teal-wash, var(--teal-wash)); box-shadow: inset 0 0 0 1px var(--teal-line, var(--teal-line)); }
.tx-legend-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tx-legend-count { color: var(--muted); font-variant-numeric: tabular-nums; }
.tx-ramp { height: 10px; margin: 4px 6px 4px; border-radius: 3px; }
.tx-ramp-bar { border-radius: var(--r-xs); }
.tx-ramp-ends { display: flex; justify-content: space-between; margin: 0 6px 8px; color: var(--muted); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.tx-ramp-missing { cursor: default; }
.tx-branch-legend { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line-soft); }
.tx-branch-legend .tx-legend-title { margin-bottom: 6px; }
.tx-branch-swatch { display: inline-block; width: 16px; height: 3px; border-radius: 2px; }
.tx-strips { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tx-strips[hidden] { display: none; }
.tx-strip-select { max-width: 9.5rem; }
.tx-strip-chips { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.tx-strip-chip { display: inline-flex; align-items: center; gap: 2px; padding: 2px 2px 2px 8px; border: 1px solid var(--line); border-radius: 999px; background: var(--wash); font-size: var(--text-sm); }
.tx-strip-remove { min-width: 22px; min-height: 22px; border: 0; border-radius: 50%; background: none; color: var(--muted); font-size: var(--text-md); line-height: 1; cursor: pointer; }
.tx-strip-remove:hover { background: var(--surface); color: var(--ink); }
.tx-topn { min-height: 24px; padding: 1px 4px; font-size: var(--text-sm); }
.tx-legend-tools { display: flex; align-items: center; gap: 10px; margin: 0 0 6px; }
.tx-legend-item { display: flex; align-items: center; }
.tx-legend-item .tx-legend-button { flex: 1; min-width: 0; }
.tx-legend-button.has-swatch { grid-template-columns: minmax(0, 1fr) auto; }
.tx-swatch { position: relative; flex: none; width: 12px; height: 12px; margin: 0 2px 0 6px; border-radius: 50%; cursor: pointer; box-shadow: 0 0 0 1px rgba(23, 39, 48, 0.12); }
.tx-swatch:hover, .tx-swatch:focus-within { box-shadow: 0 0 0 2px var(--teal); }
.tx-swatch input { position: absolute; inset: -4px; width: calc(100% + 8px); height: calc(100% + 8px); padding: 0; border: 0; opacity: 0; cursor: pointer; }
.tx-legend-more { padding: 2px 6px; color: var(--muted); font-size: var(--text-sm); list-style: none; }
.tx-ramp-missing:hover { background: none; }
.tree-explorer { position: relative; }
.tx-view { position: relative; display: inline-flex; }
.tx-view-button.is-on { border-color: var(--teal); background: var(--teal-wash); color: var(--teal-ink); }
.tx-view-menu { position: absolute; z-index: 6; top: calc(100% + 6px); right: 0; width: 17rem; padding: 6px 14px 12px; border: 1px solid var(--line); border-radius: var(--r-m); background: var(--surface); box-shadow: var(--shadow-3); }
.tx-view-menu[hidden] { display: none; }
.tx-view-menu.opens-right { right: auto; left: 0; }
.tx-view-section { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; padding-bottom: 8px; }
.tx-view-section .tx-palette-sub { flex-basis: 100%; margin: 6px 0 0; }
.tx-view-section .tx-select { max-width: 100%; }
.tx-view-section:first-child .tx-palette-sub { border-top: 0; padding-top: 4px; }
.tx-minimap { position: absolute; right: 12px; bottom: 40px; z-index: 2; width: 150px; height: 110px; border: 1px solid var(--line); border-radius: var(--r-s); background: var(--surface); box-shadow: var(--shadow-2); cursor: pointer; touch-action: none; }
.tx-minimap[hidden] { display: none; }
.tx-add-search { flex: none; }
.tx-main { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto auto auto; min-width: 0; min-height: 0; }
.tx-main .tx-stage { grid-row: 1; grid-column: 1; }
.tx-main .tx-frequencies { grid-row: 2; grid-column: 1 / -1; }
.tx-main .tx-sites { grid-row: 3; grid-column: 1 / -1; }
.tx-main .tx-table { grid-row: 4; grid-column: 1 / -1; }
.tx-table-head, .tx-table-row { display: grid; align-items: center; }
.tx-table-head { margin: 6px 16px 0; border-bottom: 1px solid var(--line); overflow: hidden; }
.tx-table-th { padding: 4px 8px; border: 0; background: none; color: var(--muted); font: var(--weight-medium) var(--text-xs)/1.4 var(--font-ui); text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.tx-table-th:hover { color: var(--teal-ink); }
.tx-table-body { position: relative; height: 240px; margin: 0 16px 10px; overflow: auto; outline: none; }
.tx-table-body:focus-visible { box-shadow: inset 0 0 0 2px var(--teal-line); }
.tx-table-spacer { position: relative; }
.tx-table-rows { position: absolute; top: 0; left: 0; right: 0; }
.tx-table-row { height: 26px; border-bottom: 1px solid var(--line-soft); font-size: var(--text-sm); cursor: pointer; }
.tx-table-row:hover, .tx-table-row.is-active { background: var(--surface-3); }
.tx-table-row.is-selected { background: var(--teal-wash); color: var(--teal-ink); font-weight: var(--weight-medium); }
.tx-table-td { display: flex; align-items: center; gap: 5px; padding: 0 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.tx-freq-canvas[hidden] { display: none; }
.tx-main.has-map { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); }
.tx-map { grid-row: 1; grid-column: 2; display: flex; flex-direction: column; min-width: 0; min-height: 0; border-left: 1px solid var(--line); background: var(--surface); }
.tx-map[hidden] { display: none; }
.tx-map-plot { position: relative; flex: 1; min-height: 240px; margin: 6px 8px 0; border: 1px solid var(--line-soft); border-radius: var(--r-s); overflow: hidden; }
.tx-map-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; outline: none; cursor: grab; touch-action: none; }
.tx-map-canvas:focus-visible { box-shadow: inset 0 0 0 2px var(--teal-line); }
.tx-map-hint { margin: 6px 16px 10px; color: var(--subtle); font-size: var(--text-xs); line-height: var(--leading); }
.tx-stage.is-lasso { cursor: crosshair; }
.tx-lasso-button.is-on { border-color: var(--teal); background: var(--teal-wash); color: var(--teal-ink); }
.tx-diversity { flex: none; border-top: 1px solid var(--line); background: var(--surface); }
.tx-diversity[hidden] { display: none; }
.tx-diversity-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 8px 16px 0; }
.tx-diversity-head .tx-legend-title { margin: 0; }
.tx-diversity-hint { color: var(--subtle); font-size: var(--text-xs); }
.tx-map-when { color: var(--ink-2); font-size: var(--text-xs); font-variant-numeric: tabular-nums; white-space: nowrap; }
.tx-map-when:empty { display: none; }
.tx-diversity-focus { color: var(--teal-ink); font-size: var(--text-xs); font-weight: var(--weight-medium); }
.tx-diversity-focus:empty { display: none; }
.tx-diversity-plot { position: relative; padding: 0 6px 4px; }
.tx-diversity-canvas { display: block; width: 100%; height: 132px; outline: none; cursor: crosshair; }
.tx-diversity-canvas:focus-visible { box-shadow: inset 0 0 0 2px var(--teal-line); border-radius: var(--r-xs); }
.tx-diversity-tip { top: 0; left: 0; }
.tx-search .tx-search-input { flex: 1 1 9rem; min-width: 9rem; }
.tx-filter-button.is-on { border-color: var(--teal); background: var(--teal-wash); color: var(--teal-ink); }
.tx-filterbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 6px 16px; border-bottom: 1px solid var(--line); background: var(--teal-wash); font-size: var(--text-sm); }
.tx-filterbar[hidden] { display: none; }
.tx-filter-chip { background: var(--surface); }
.tx-filter-key { color: var(--muted); }
.tx-filter-count { margin-left: auto; color: var(--teal-ink); font-weight: var(--weight-medium); }
.tx-filter-panel { left: auto; right: 16px; transform: none; width: min(24rem, calc(100% - 32px)); }
.tx-filter-panel .tx-control { margin-bottom: 8px; }
.tx-filter-find { width: 100%; margin-bottom: 6px; }
.tx-filter-list { max-height: 15rem; overflow: auto; margin: 0 0 10px; padding: 0; list-style: none; border: 1px solid var(--line-soft); border-radius: var(--r-s); }
.tx-filter-list li[hidden] { display: none; }
.tx-filter-value { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; align-items: center; gap: 8px; padding: 4px 10px; font-size: var(--text-sm); cursor: pointer; }
.tx-filter-value:hover { background: var(--surface-3); }
.tx-filter-value input { accent-color: var(--teal); margin: 0; }
.tx-filter-dates { margin-bottom: 10px; }
.tx-date-row { display: flex; align-items: center; gap: 10px; }
.tx-date-sliders { display: grid; flex: 1; gap: 2px; }
.tx-range { width: 100%; accent-color: var(--teal); }
.tx-date-text { display: block; margin-top: 4px; color: var(--muted); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.tx-range-row { display: flex; gap: 10px; margin-bottom: 4px; }
.tx-range-input { width: 7.5rem; }
.tx-filter-exclude { margin: 0 0 10px; }
.tx-filter-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-top: 10px; border-top: 1px solid var(--line-soft); }
.tx-groups { display: flex; flex-wrap: wrap; gap: 6px 18px; padding: 6px 16px; border-bottom: 1px solid var(--line); background: var(--surface-2); }
.tx-groups[hidden] { display: none; }
.tx-group { display: inline-flex; align-items: center; gap: 8px; flex: 1 1 18rem; min-width: 14rem; max-width: 30rem; }
.tx-group .tx-group-input { flex: 1; min-width: 0; }
.tx-group-ring { flex: none; width: 12px; height: 12px; border: 3px solid; border-radius: 50%; background: var(--surface); }
.tx-icon:disabled, .tx-button:disabled { opacity: 0.4; cursor: default; border-color: var(--line); color: var(--ink); }
.tx-help-button { border-radius: 50%; }
/* Shortcuts and commands: a dialog over the explorer, the command box on top. */
.tx-dialog {
  position: absolute;
  z-index: 5;
  top: 56px;
  left: 50%;
  width: min(34rem, calc(100% - 32px));
  max-height: calc(100% - 72px);
  overflow: auto;
  transform: translateX(-50%);
  padding: 12px 14px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--surface);
  box-shadow: var(--shadow-3);
}
.tx-dialog[hidden] { display: none; }
.tx-palette-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.tx-palette-title { margin: 0; font-size: var(--text-md); }
.tx-palette-input {
  width: 100%;
  min-height: 36px;
  padding: 6px 10px;
  border: 1px solid var(--teal);
  border-radius: var(--r-s);
  font: var(--text-base)/1.3 var(--font-ui);
  outline: none;
  box-shadow: var(--focus-ring);
}
.tx-palette-list { margin: 6px 0 10px; padding: 0; list-style: none; }
.tx-palette-item { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 10px; border-radius: var(--r-xs); font-size: var(--text-base); cursor: pointer; }
.tx-palette-item.is-active, .tx-palette-item:hover { background: var(--teal-wash); color: var(--teal-ink); }
.tx-palette-empty { padding: 6px 10px; color: var(--muted); font-size: var(--text-base); }
.tx-palette-sub { margin: 4px 0 6px; padding-top: 10px; border-top: 1px solid var(--line-soft); color: var(--muted); font-size: var(--text-sm); }
.tx-keys { display: grid; grid-template-columns: max-content 1fr; gap: 5px 14px; margin: 0; font-size: var(--text-sm); }
.tx-keys dt { margin: 0; white-space: nowrap; }
.tx-keys dd { margin: 0; color: var(--muted); }
.tx-command kbd, .tx-keys kbd {
  display: inline-block;
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: var(--r-2xs);
  background: var(--wash);
  color: var(--ink);
  font: var(--weight-medium) var(--text-xs)/1.5 var(--font-ui);
  white-space: nowrap;
}

@media (max-width: 860px) {
  /* A phone pinches and drags instead of pressing zoom buttons; exports are a desktop task. */
  .tx-body { grid-template-columns: 1fr; grid-template-rows: minmax(58vh, 1fr) auto; }
  .tx-side { border-left: 0; border-top: 1px solid var(--line); max-height: none; overflow: visible; }
  .tx-toolbar { padding: 8px 12px; gap: 6px 10px; }
  .tx-search { order: 10; flex-basis: 100%; }
  .tx-zoom .tx-icon, .tx-out > .tx-button:not(.tx-view-button), .tx-out > .tx-link { display: none; }
  .tx-view-export { display: none; }
  /* On a phone the menu spans the toolbar, anchored to it rather than to its button. */
  .tx-toolbar { position: relative; }
  .tx-view { position: static; }
  .tx-view-menu { top: calc(100% - 4px); left: 12px; right: 12px; width: auto; }
  /* Lasso and back stay: a phone has no Shift key and no Backspace. */
  .tx-zoom .tx-lasso-button, .tx-zoom .tx-back-button { display: inline-block; }
  .tx-diversity-hint { display: none; }
  .tx-main.has-map { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(58vh, 1fr) auto auto; }
  .tx-map { grid-row: 2; grid-column: 1; min-height: 320px; border-left: 0; border-top: 1px solid var(--line); }
  .tx-main.has-map { grid-template-rows: minmax(58vh, 1fr) auto auto auto; }
  .tx-main .tx-frequencies { grid-row: 3; }
  .tx-main.has-map { grid-template-rows: minmax(58vh, 1fr) auto auto auto auto; }
  .tx-main .tx-sites { grid-row: 4; }
  .tx-main .tx-table { grid-row: 5; }
  .tx-toggles { gap: 10px; }
  .tx-note { padding: 5px 12px; }
  .tx-note-source { display: none; }
}

}  /* @layer legacy */

/* The selection page with the tree beside its report: the report on the left, the tree explorer
   docked on the right (the same explorer as the trees page, any tree size), a handle between them.
   On a narrow screen the tree sits below the report. */
.stage-split {
  flex: 1;
  min-height: 0;
  display: flex;
}
.stage-split > .stage-frame { flex: 1 1 auto; min-width: 0; }
.stage-split .tree-explorer.is-docked {
  flex: 0 0 var(--dock-w, 42%);
  min-width: 320px;
  margin: 0 var(--page-gutter) var(--space-4) 0;
}
.split-handle {
  flex: 0 0 10px;
  cursor: col-resize;
  position: relative;
  touch-action: none;
}
.split-handle::after {
  content: "";
  position: absolute;
  top: 40%;
  bottom: 40%;
  left: 3px;
  width: 4px;
  border-radius: 2px;
  background: var(--line-strong);
}
.split-handle:hover::after,
.split-handle:focus-visible::after { background: var(--teal); }
.split-handle:focus-visible { outline: none; }
.split-handle[hidden] { display: none; }
.stage-split.is-resizing > .stage-frame { pointer-events: none; }
.dock-toggle {
  align-self: flex-start;
  margin-top: var(--space-2);
  padding: 4px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--teal-deep);
  font: var(--weight-medium) var(--text-sm) var(--font-ui);
  cursor: pointer;
}
.dock-toggle[aria-pressed="true"] { border-color: var(--teal); background: var(--teal-wash, var(--surface-2)); }
.dock-toggle[hidden] { display: none; }
@media (max-width: 980px) {
  .stage-split { flex-direction: column; }
  .stage-split > .stage-frame { flex: 1 1 60%; min-height: 360px; }
  .stage-split .tree-explorer.is-docked { flex: 0 0 auto; height: 70vh; min-width: 0; margin: 0 var(--page-gutter) var(--space-4); }
  .split-handle { display: none; }
}

/* ---- the conversation lies on the page, not in a box ------------------------------------------
   A reading column in a white frame as wide as the screen left a band of empty card on both sides
   of every message and above a short conversation: the frame, not the text, set the size of the
   emptiness. As in the chat products people know, the conversation now sits on the page itself;
   the column is wide enough for the cards in it, the assistant speaks in plain prose at a reading
   size, the reader's own lines are the only bubbles, and the composer floats above a fade. The
   side panel keeps to the right edge on a wide screen instead of drifting in with a centred cap. */
.chat-page { --chat-col: 760px; }
.chat-column {
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.chat-page[data-mode="session"] .chat-stage,
.chat-page[data-mode="gate"] .chat-stage { max-width: 100%; }
.transcript { gap: 14px; }
.bubble.assistant,
.bubble.question {
  max-width: 100%;
  padding: 2px 0;
  border-color: transparent;
  background: transparent;
  font-size: var(--text-md);
  line-height: 1.7;
}
.bubble.question { padding-left: 14px; border-left-color: var(--teal); }
.bubble.user {
  max-width: min(560px, 85%);
  font-size: var(--text-md);
  line-height: 1.6;
  border-radius: 18px 18px 6px 18px;
}
.composer-dock { background: linear-gradient(180deg, rgba(245, 248, 247, 0), var(--wash) 18px); }
.composer {
  background: var(--surface);
  box-shadow: 0 4px 18px rgba(23, 39, 48, 0.07);
}
.chat-page .answer-teaser { width: 100%; }
/* The run board heads the same column: one left edge from the headline down to the composer. */
.run-board { width: min(100%, var(--chat-col)); margin: 0 auto 8px; }
/* With a board at the top the conversation follows it; only a bare conversation sits on the
   composer, where a board's gap would otherwise open up in the middle. */
.chat-page:is([data-mode="running"], [data-mode="gate"], [data-mode="failed"]) .transcript::before { content: none; }
@media (max-width: 860px) {
  .transcript { padding-inline: 4px; }
  .composer-dock { padding-inline: 0; }
}
