/* ============================================================================
   Scenario Lab — agent swarm demonstration.

   No colours are defined here. Every value comes from the Daylight tokens in
   styles.css, so the page re-skins with the theme toggle and cannot drift from
   the rest of the site. Colour keeps its meaning too: green is YES, rose is NO,
   amber is the accent that carries the shock banner.
   ========================================================================== */

.lab-shell {
  max-width: 1500px;
  margin: 0 auto;
  padding: 20px 22px 70px;
}

/* ---------- hero ---------- */
/* Single column. This was a two-column grid whose right cell held the amber
   "Recorded runs" notice; with the notice removed it left 510px of dead space
   beside the title. One child, one column. */
.lab-hero {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin-bottom: 18px;
}
.lab-hero-copy {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 14px;
}
.lab-kicker {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--green-deep);
  margin: 0;
  order: 2;
}
.lab-hero h1 {
  font-family: var(--font-display);
  font-size: clamp(26px, 2.6vw, 34px);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0;
  order: 1;
}
.lab-sub-link {
  display: inline-block;
  margin-top: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--green-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.lab-sub-link:hover { color: var(--green-strong); }

.lab-sub {
  margin: 0;
  color: var(--muted);
  font-size: 16px;
  line-height: 1.55;
  max-width: 62ch;
  text-wrap: pretty;
}

/* The simulated-demo notice. Amber, because this is a caution rather than a
   verdict -- rose would read as "outcome NO" in a system where colour is verdict. */
.lab-notice {
  background: var(--amber-soft);
  border: 1px solid color-mix(in oklab, var(--amber) 45%, var(--line-strong));
  border-radius: var(--radius);
  padding: 16px 18px;
}
.lab-notice-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text);
  border: 1px solid color-mix(in oklab, var(--amber) 55%, transparent);
  border-radius: var(--radius-sm);
  padding: 3px 9px;
  margin-bottom: 9px;
}
.lab-notice p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--muted);
}
/* Ink + underline, not green: --green-deep over the amber wash measures 4.46:1,
   a hair under the floor, and the underline carries the affordance anyway. */
.lab-notice a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }


/* Small type uses --muted, not --subtle. Measured on this page's own surfaces,
   --subtle (#7a8094) lands at 3.93:1 on --surface and 3.60:1 on --page, under the
   4.5 floor for text this size. --muted is 7.4:1 and reads as the same tier.
   The global token is left alone -- changing it would move the whole site. */

/* The domain bar is the dashboard's own component (styles.css). Nothing is
   restyled here on purpose -- the point is that both surfaces share one control. */

/* ---------- layout ---------- */
.lab-grid {
  display: grid;
  grid-template-columns: 290px minmax(0, 1fr) 340px;
  gap: 18px;
  /* stretch, not start: the card list should run the full height of the tallest
     column rather than stopping short of the outcome panel beside it. */
  align-items: stretch;
}
.lab-col {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 18px;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.lab-col-main { padding: 18px 18px 0; }
.lab-h {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 14px;
}

/* ---------- scenario cards ---------- */
.lab-scenarios { display: grid; gap: 9px; }
.lab-scenario {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 13px 14px;
  cursor: pointer;
  transition: border-color 0.18s ease, background 0.18s ease, transform 0.18s ease;
}
.lab-scenario:hover { border-color: var(--line-strong); transform: translateY(-1px); }
.lab-scenario[aria-pressed="true"] {
  background: var(--green-soft);
  border-color: color-mix(in oklab, var(--green) 45%, var(--line-strong));
}
.lab-scenario strong {
  display: block;
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 5px;
  line-height: 1.3;
}
.lab-scenario span {
  display: block;
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.45;
}

/* ---------- controls ---------- */
.lab-controls { display: flex; gap: 8px; margin-top: 16px; }
.lab-run {
  flex: 1;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: #06301f;
  background: var(--brand-grad);
  border: 0;
  border-radius: var(--radius-sm);
  padding: 12px 0;
  cursor: pointer;
  box-shadow: var(--shadow-green);
  transition: transform 0.18s ease, filter 0.18s ease;
}
.lab-run:hover { transform: translateY(-1px); filter: brightness(1.04); }
.lab-run[data-running="true"] {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line-strong);
  box-shadow: none;
}
.lab-chip {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0 12px;
  min-width: 56px;
  cursor: pointer;
  transition: border-color 0.18s ease, color 0.18s ease;
}
.lab-chip:hover { border-color: var(--line-strong); color: var(--text); }

/* ---------- canvas ---------- */
.lab-canvas-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  /* The answer block above ends in a hairline, and the visual starts right below. The row
     is centred between the two rather than resting on either: it was 0/14 on the swarm
     page and 30/0 in the card panel, where the container's own top padding stacked on top
     of the head's and left nothing underneath. */
  padding-block: 14px;
}
/* "Actors & interactions" was wrapping onto two lines because the count and phase chips
   squeezed it, in a header only 44px tall. */
/* margin-bottom: 0 -- the base .lab-h carries 14px, which lands INSIDE the head box and
   pushed the row off-centre (14px from the rule, 29px from the visual). Only the swarm
   page has this heading, which is why the card panel centred correctly and this did not.
   The head's own padding-block owns that spacing now. */
.lab-canvas-head .lab-h { flex: none; white-space: nowrap; margin-bottom: 0; }
/* Section label left, and the two meta chips as ONE group on the right: what the visual
   contains, then where the replay is up to. Pushed individually they read as three
   unrelated fragments of small mono text strewn between the answer and the canvas. */
.lab-canvas-head .lab-count { margin-inline-start: auto; }
.lab-canvas-head .lab-phase { margin-inline-start: 0; }
.lab-count {
  /* Not margin-left:auto -- when the head wraps, a solo item on its own row gets shoved
     to the right edge and reads as belonging to nothing. The phase chip does the pushing
     on wide screens; see .lab-canvas-head .lab-phase. */
  margin-left: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.lab-count b { color: var(--text); font-weight: 500; }
.lab-phase {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.lab-phase[data-settled="true"] { color: var(--green-deep); }
/* A dark plate in BOTH themes. A thousand 2px marks need a dark ground to read,
   and it frames the canvas as a viewport into the run rather than another card. */
.lab-canvas-wrap {
  position: relative;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background:
    radial-gradient(120% 90% at 50% 0%, #1b1d27 0%, #121319 58%, #0e0f14 100%);
  overflow: hidden;
  aspect-ratio: 10 / 7;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.lab-panel-main .lab-canvas-wrap {
  width: auto;
  /* 10/7 is fixed -- the canvas backing store is 1000x700 and CSS stretches it, so any
     other ratio distorts the graph. The cap is therefore on height, set so the plate
     fills the column on a laptop viewport instead of sitting in wide white gutters. */
  max-width: min(100%, calc(58vh * 10 / 7));
  margin-inline: auto;
}

.lab-canvas-wrap canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  cursor: crosshair;
}
.lab-shock {
  position: absolute;
  top: 13px;
  left: 50%;
  transform: translateX(-50%);
  max-width: 92%;
  background: var(--amber-soft);
  border: 1px solid color-mix(in oklab, var(--amber) 55%, transparent);
  color: var(--amber-strong);
  border-radius: var(--radius-sm);
  padding: 7px 14px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  animation: labShock 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes labShock {
  from { opacity: 0; transform: translate(-50%, -8px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* ---------- persona inspector ---------- */
.lab-inspector {
  position: absolute;
  left: 14px;
  bottom: 14px;
  width: 262px;
  /* Anchored to the bottom inside a wrap that clips, so a tall persona ran off the TOP
     of the plate -- on a phone the plate is 203px and the panel was taller than it, so
     the first lines were simply gone. Bounded and scrollable keeps every persona
     readable at any plate size. */
  max-height: calc(100% - 28px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: rgba(20, 22, 30, 0.94);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: #e9edf5;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  padding: 14px;
}
.lab-insp-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
  /* The panel scrolls now, so the name and the close button stay put rather than
     scrolling away and stranding the reader inside it. */
  position: sticky;
  top: -2px;
  background: inherit;
  padding-block: 2px;
}
.lab-insp-head strong { font-size: 14px; font-weight: 700; }
.lab-insp-close {
  font: inherit;
  font-size: 16px;
  line-height: 1;
  min-width: 36px;
  min-height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: -8px -8px -8px 0;
  color: rgba(233, 237, 245, 0.8);
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0 2px;
}
.lab-insp-meta {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.07em;
  color: rgba(233, 237, 245, 0.72);
  margin: 3px 0 0;
}
.lab-insp-p {
  font-family: var(--font-mono);
  font-size: 11.5px;
  margin: 10px 0 0;
}
.lab-insp-quote {
  margin: 8px 0 0;
  font-size: 12.5px;
  font-style: italic;
  color: var(--muted);
  line-height: 1.45;
}

/* ---------- readout strip ---------- */
/* ---------- the card's own answer ---------- */
/* Sits directly under the canvas. The verdict is the largest thing in the panel because
   it is the one line a reader opened the card for; everything below it is detail. */
/* When the answer leads the panel it sits above the canvas, so it needs the panel's
   own padding rather than the main column's negative-margin trick. */
.lab-answer {
  border-top: 1px solid var(--line);
  margin: 18px -18px 0;
  padding: 16px 18px 2px;
}
.lab-answer:empty { display: none; }
.lab-panel-main .lab-answer { margin-inline: 0; padding-inline: 0; }

/* The answer is the panel's header, not a callout floating above the canvas: the
   verdict, its figure and the one-line explainer share a block that a hairline closes
   against the visual. It used to be a tinted rounded box with a 4px coloured edge, which
   at pill radius rendered as a crescent hugging the word and read as a broken border. */
.lab-answer-lead {
  margin: 0;
  padding: 12px 20px 15px;
  border-top: 0;
  border-bottom: 1px solid var(--line);
}
.lab-answer-q { margin: 0 0 6px; font-size: 12.5px; color: var(--muted); line-height: 1.45; }

/* The figure is the answer, so it takes the size; the label says whose figure it is,
   and the dot carries the lean. Same arrangement as the grid card, because the overlay
   opens on top of one. */
.lab-answer-verdict {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0;
  line-height: 1.15;
}
/* The dot belongs to the label, not to the row: as a sibling it aligned against a row
   whose height the 27px figure sets, so it sat above the 13px word it marks. Centred on
   the word's own line box it stays level with it at any type size. */
.lab-answer-word {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  /* Its own line box, not the row's 1.15 -- the dot centres on whatever box the flex
     line reports, so a compressed line-height moves the dot off the word by a pixel. */
  line-height: normal;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--muted);
}
.lab-answer-word::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--verdict-dot, var(--subtle));
}
.lab-answer-figure {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 27px;
  font-weight: 650;
  letter-spacing: -0.02em;
  color: var(--text);
  white-space: nowrap;
}
/* Tone reaches the dot through a variable, so it cannot leak into the word or the
   figure -- both set their own colour. */
.lab-answer-yes { --verdict-dot: var(--green-deep); }
.lab-answer-no { --verdict-dot: var(--rose-strong); }
.lab-answer-even { --verdict-dot: var(--subtle); }
/* The card's breakdown, restated under the verdict so the figure has something to belong
   to. Capped so it reads as support for the answer rather than competing with it. */
/* The question leads the block on the AI Swarm page, where nothing above it states what
   is being asked. At 12.5px muted it was the smallest text in the block while the answer
   under it was 27px -- the question read as a footnote to its own answer. The dashboard
   panel passes omitQuestion, so this only ever applies where it is the heading. */
.lab-answer-lead .lab-answer-q {
  margin: 0 0 9px;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text);
  text-wrap: balance;
}

/* A compact comparison, the way it reads on the card. Left to fill the column it ran
   492px of 570 and looked like two loading bars. */
.lab-answer-breakdown {
  margin: 10px 0 0;
  max-width: 380px;
}
/* The card clips these to 86px because it is one of three in a grid. The panel has the
   width to spell them out, and a clipped "Crystal Pala..." defeats the point of showing
   the bar at all -- the name is what anchors the figure above it. */
/* One grid for the whole block, rows as `display: contents`, so the label column sizes to
   the longest label instead of reserving a fixed width. "Yes" was sitting in a 150px box
   with the bar starting 150px in, so label and bar read as unrelated objects. Rows share
   the column tracks, so team names and Yes/No both stay aligned. */
.lab-answer-breakdown {
  display: grid;
  grid-template-columns: max-content minmax(70px, 1fr) auto;
  align-items: center;
  column-gap: 12px;
  row-gap: 7px;
}
.lab-answer-breakdown .breakdown-row {
  display: contents;
}
/* ...which means the row's children are laid out by the grid above, not by the card's
   stacked row template. The card names its areas (label / value / track); those names do
   not exist here, so without this reset the children land in an implicit grid and the
   bars detach from their labels. */
.lab-answer-breakdown .breakdown-row > * {
  grid-area: auto;
}
.lab-answer-lead .lab-answer-meta { margin-top: 10px; }

.lab-answer-meta {
  margin: 7px 0 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 62ch;
  text-wrap: pretty;
}
.lab-answer-meta .num {
  font-family: var(--font-mono); font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 640px) { .lab-answer-figure { font-size: 22px; } }

/* ---------- outcome summary, under the visual ---------- */
/* It answers the question the canvas raises, so it sits directly beneath it and
   spans the full column. It used to live in the side column below the move feed,
   where the answer read as a footnote to the replay. Full-bleed rule to match
   .lab-readout, which is the block immediately after it. */
.lab-outcome-block {
  border-top: 1px solid var(--line);
  margin: 18px -18px 0;
  padding: 15px 18px 0;
}
/* Two columns once there is room: the ending and its facts side by side rather
   than a single narrow strip running the width of the canvas. */
@media (min-width: 900px) {
  .lab-outcome-block .lab-outcome {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    column-gap: 26px;
    align-items: start;
  }
  .lab-outcome-block .lab-out-lede,
  .lab-outcome-block .lab-out-verdict,
  .lab-outcome-block .lab-out-answer,
  .lab-outcome-block .lab-out-rate,
  .lab-outcome-block .lab-out-desc,
  .lab-outcome-block .lab-out-caveat { grid-column: 1; }
  /* Span every row and pin to the top, otherwise auto-placement drops the facts
     table into the first FREE row -- level with the runner-up line, leaving the
     top of the column empty. */
  .lab-outcome-block .lab-out-facts {
    grid-column: 2;
    grid-row: 1 / -1;
    align-self: start;
    margin-top: 0;
  }
  .lab-outcome-block .lab-out-facts li:first-child { border-top: 0; padding-top: 0; }
}
/* The overlay's side column is narrower; keep it single-column there. */
.lab-panel-main .lab-outcome-block { margin-inline: 0; padding-inline: 0; }

.lab-readout {
  display: block;
  border-top: 1px solid var(--line);
  margin: 18px -18px 0;
  padding: 15px 18px;
}
.lab-eyebrow {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 4px;
}
.lab-prob {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--subtle);
  font-variant-numeric: tabular-nums;
}
.lab-readout-block { min-width: 172px; }
.lab-spark { width: 320px; height: 52px; flex-shrink: 0; }
.lab-conf { display: flex; align-items: center; gap: 9px; }
.lab-conf-track {
  flex: 1;
  min-width: 78px;
  height: 5px;
  border-radius: 3px;
  background: var(--track);
  overflow: hidden;
}
.lab-conf-track i {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: 3px;
  background: var(--green);
  transition: width 0.3s ease;
}
.lab-conf .num,
.lab-readout-note {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--muted);
}
.lab-readout-note {
  margin: 0 0 0 auto;
  max-width: 230px;
  line-height: 1.5;
  text-align: right;
}


/* ---------- the source card ---------- */
.lab-card {
  border-top: 1px solid var(--line);
  margin: 18px -18px 0;
  padding: 15px 18px 0;
}
.lab-card-q {
  margin: 0 0 8px;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.35;
  text-wrap: balance;
}
.lab-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 14px;
  font-size: 12.5px;
  color: var(--muted);
}
.lab-card-meta b { font-size: 15px; color: var(--text); font-weight: 600; }
.lab-card-meta a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.lab-card-note {
  margin: 10px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
  border-left: 0;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}
.lab-card-note p { margin: 0; }
.lab-card-note p + p { margin-top: 7px; }
.lab-card-note strong { color: var(--text); }

/* ---------- branches (shares of runs, never a probability) ---------- */
.lab-branches { display: grid; gap: 13px; margin-top: 4px; }
.lab-branch { display: grid; gap: 5px; }
.lab-branch-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  font-size: 13.5px; font-weight: 600;
}
.lab-branch-head .num {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13px; color: var(--muted);
}
.lab-branch-bar {
  display: block; height: 5px; border-radius: 3px; background: var(--track); overflow: hidden;
}
.lab-branch-bar i { display: block; height: 100%; border-radius: 3px; background: var(--amber); }
.lab-branch p { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--muted); }
.lab-branch-runs { font-size: 11px; color: var(--muted); }

/* ---------- provenance / diagnostics rows ---------- */
.lab-rows { display: grid; gap: 0; }
.lab-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px;
  padding: 7px 0; border-top: 1px solid var(--line); font-size: 12.5px; align-items: baseline;
}
.lab-row:first-child { border-top: 0; }
.lab-row span:first-child { color: var(--muted); }
.lab-row span:last-child { text-align: right; font-weight: 500; }
.lab-row .num { font-family: var(--font-mono); font-size: 11.5px; }
.lab-caveat {
  margin: 12px 0 0; font-size: 12px; line-height: 1.5; color: var(--muted);
  border-top: 1px solid var(--line); padding-top: 10px;
}

/* ---------- evidence ---------- */
.lab-evidence { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.lab-evidence li { display: grid; gap: 2px; font-size: 12.5px; line-height: 1.45; }
.lab-evidence a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.lab-evidence .num {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.04em; color: var(--muted);
}

/* ---------- move rationale ---------- */
.lab-msg-why {
  font-size: 12px; font-style: italic; color: var(--muted);
  line-height: 1.45; margin: 3px 0 0 14px;
}
.lab-insp-list { margin: 7px 0 0; font-size: 12px; line-height: 1.5; color: rgba(233, 237, 245, 0.75); }
.lab-insp-list b { color: #ffffff; font-weight: 600; }

/* ---------- outcome summary ---------- */
/* Hierarchy does the explaining. A muted opening line establishes what a "replay"
   is (without it, every number below is meaningless), a short lead-in sets up the
   finding, and the ending itself gets the largest type on the panel. The frequency
   sits underneath as a count -- "19 times out of 60" -- never as a percentage in
   display type, which is exactly what gets misread as a probability. */
.lab-outcome { display: grid; gap: 9px; }
.lab-out-lede {
  margin: 0; font-size: 12px; color: var(--muted); line-height: 1.45;
}
.lab-out-lede b {
  color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums;
}
.lab-out-verdict {
  margin: 2px 0 -4px; font-size: 12px; color: var(--muted); line-height: 1.4;
}
.lab-out-answer {
  margin: 0; font-size: 19px; font-weight: 600; line-height: 1.25;
  letter-spacing: -0.015em; color: var(--text); text-wrap: balance;
}
.lab-out-rate { margin: -3px 0 0; }
.lab-out-rate .num {
  font-family: var(--font-mono); font-size: 12.5px; font-weight: 500;
  font-variant-numeric: tabular-nums; color: var(--text);
}
.lab-out-desc { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--muted); }
.lab-out-desc b { font-weight: 600; color: var(--text); }
.lab-out-facts { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 0; }
.lab-out-facts li {
  display: grid; grid-template-columns: minmax(0, auto) 1fr; gap: 10px;
  align-items: baseline; padding: 6px 0; border-top: 1px solid var(--line); font-size: 12.5px;
}
.lab-out-facts li span { color: var(--muted); }
.lab-out-facts li b { font-weight: 500; text-align: right; }
.lab-out-caveat {
  margin: 4px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--muted);
  background: var(--surface-2); border-radius: var(--radius-sm); padding: 9px 11px;
}
.lab-h-sep { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); }
.lab-h-count { color: var(--muted); font-weight: 400; }

/* A long card list needs to scroll inside its own pane, not stretch the page. */
/* The card list is the primary way in, so let it run the height of the column
   rather than stopping at 520px with 470 cards still below the fold. */
.lab-scenarios { flex: 1; min-height: 320px; max-height: 78vh; overflow-y: auto; scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent; padding-right: 4px; }
.lab-scenarios::-webkit-scrollbar { width: 9px; }
.lab-scenarios::-webkit-scrollbar-thumb {
  background: var(--line-strong); border-radius: 6px; border: 3px solid var(--surface); }

.lab-canvas-hint {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--muted);
  text-align: center;
}

.lab-esc-note {
  margin: 0 0 10px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
}

/* ---------- feed ---------- */
.lab-feed {
  display: flex;
  flex-direction: column;
  gap: 11px;
  max-height: 560px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}
/* The right column stretches to the row height (see .lab-grid align-items), but
   the feed stopped at its 560px cap, leaving the column visibly empty below it.
   flex:1 hands it the leftover space. This is only safe because the column has a
   DEFINITE height from the stretched grid row -- flex:1 plus overflow:auto in an
   auto-height parent is what ballooned these columns to 13,000px once before, so
   min-height:0 stays and the cap is lifted only here. */
/* Desktop only. Below 901px the right column stacks full-width in its own row,
   so there is no sibling column to take height from -- basis 0 would collapse the
   feed to its floor. The stacked layout keeps its own 320px cap instead. */
@media (min-width: 901px) {
  .lab-col-right .lab-feed {
    /* basis 0, NOT auto. With `auto` the feed's own content height is its flex
       basis, so every message appended during a replay pushed the column taller
       and it grew without bound. Basis 0 fills the height the row already has
       and never contributes to it. No max-height: a vh cap sounds like a safe
       backstop but binds BELOW the column height on tall viewports, re-opening
       the very gap this rule closes. */
    flex: 1 1 0;
    min-height: 240px;
    max-height: none;
  }
}
.lab-feed::-webkit-scrollbar { width: 9px; }
.lab-feed::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 6px;
  border: 3px solid var(--surface);
}
.lab-feed-empty { font-family: var(--font-mono); font-size: 11.5px; color: var(--muted); }
.lab-msg { animation: labFeedIn 0.25s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes labFeedIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
.lab-msg-sys {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  line-height: 1.5;
}
.lab-msg-shock {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--amber-strong);
  background: var(--amber-soft);
  border: 1px solid color-mix(in oklab, var(--amber) 40%, transparent);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
}
.lab-msg-who { display: flex; gap: 7px; align-items: baseline; }
.lab-msg-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.lab-msg-name { font-size: 12.5px; font-weight: 600; }
.lab-msg-arch {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.lab-msg-text {
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.45;
  margin: 2px 0 0 14px;
}

/* ---------- explainer ---------- */
.lab-how { margin-top: 34px; }
.lab-how-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 16px;
}
.lab-how-grid article {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 17px 18px;
  box-shadow: var(--shadow-sm);
}
.lab-how-grid h3 {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--green-deep);
  margin: 0 0 8px;
}
.lab-how-grid p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--muted);
}

/* ---------- responsive ---------- */
@media (max-width: 1180px) {
  .lab-grid { grid-template-columns: 260px minmax(0, 1fr); }
  .lab-col-right { grid-column: 1 / -1; }
  .lab-feed { max-height: 320px; }
}
@media (max-width: 860px) {
  .lab-hero { grid-template-columns: 1fr; }
  .lab-grid { grid-template-columns: 1fr; }
  /* Answer first on a phone. Stacked in source order the card picker came first: a
     320px window holding 11,128px of list, so the reader met a scroll-trap and had to
     get past it before reaching the answer for the card already selected. The picker
     belongs after the thing it picks. */
  .lab-col-main { order: 1; }
  .lab-col-left { order: 2; }
  .lab-col-right { order: 3; }
  /* Shorter, so it reads as a picker rather than a second page. */
  .lab-col-left .lab-scenarios { max-height: 46vh; }
  /* Stacked one per row there is no trailing edge to hug, and a pushed chip hangs off
     on its own. */
  .lab-canvas-head .lab-count,
  .lab-canvas-head .lab-phase { margin-inline-start: 0; }
  .lab-readout { gap: 16px; }
  .lab-spark { width: 100%; }
  .lab-readout-note { margin-left: 0; text-align: left; max-width: none; }
  /* Full width of the plate on a phone, and anchored to the top so the head with the
     actor's name and the close button is always the first thing in view. */
  .lab-inspector {
    width: calc(100% - 28px);
    top: 14px;
    bottom: 14px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lab-msg, .lab-shock { animation: none; }
  .lab-scenario:hover, .lab-run:hover { transform: none; }
  .lab-conf-track i { transition: none; }
}

/* ============================================================================
   Scenario panel embedded in the dashboard.
   Same renderer and same tokens as the standalone Lab, laid out to sit inside
   the dashboard's main column above the card grid.
   ========================================================================== */
/* A fixed overlay, not an inline block. The dashboard grid runs to ~65,000px, so a
   panel anchored in the document is unreachable from a card three thousand pixels
   down -- selecting a card has to bring the scenario to the viewport, not send the
   reader hunting for it. */
/* MUST come first and MUST match the panel's own specificity. `[hidden]` is only a
   UA rule of `display: none`, so the `.lab-panel[data-scenario-panel]` selector below
   outranks it and the overlay paints even while the attribute is set -- which shipped
   a permanent full-screen backdrop over the dashboard, sitting under the T&C modal on
   a first visit and making the whole entry screen look broken. */
.lab-panel[data-scenario-panel][hidden] {
  display: none !important;
}

.lab-panel[data-scenario-panel] {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: clamp(12px, 3vw, 40px);
  background: rgba(12, 13, 18, 0.55);
  backdrop-filter: blur(3px);
  border: 0;
  border-radius: 0;
  margin: 0;
  box-shadow: none;
  overflow: hidden;
  animation: labPanelIn 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}
.lab-panel[data-scenario-panel] > .lab-panel-inner {
  width: min(1180px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.lab-panel[data-scenario-panel] .lab-panel-body { overflow-y: auto; }
/* The body is a nested scroll region inside a panel that already scrolls, so on a short
   viewport it clips mid-heading with nothing to say the text continues -- it reads as a
   rendering fault. Local-attachment gradients cover the edge and scroll-attachment
   shadows sit on top, so each edge shows only while there is more in that direction. */
.lab-panel[data-scenario-panel] .lab-panel-body {
  background:
    linear-gradient(var(--surface) 30%, rgba(0, 0, 0, 0)) top / 100% 24px no-repeat local,
    linear-gradient(rgba(0, 0, 0, 0), var(--surface) 70%) bottom / 100% 24px no-repeat local,
    radial-gradient(farthest-side at 50% 0, rgba(24, 26, 35, 0.13), rgba(0, 0, 0, 0))
      top / 100% 11px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%, rgba(24, 26, 35, 0.13), rgba(0, 0, 0, 0))
      bottom / 100% 11px no-repeat scroll;
}
@keyframes labPanelIn { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .lab-panel[data-scenario-panel] { animation: none; }
}
.lab-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 16px 18px 12px;
  border-bottom: 1px solid var(--line);
}
.lab-panel-head h3 {
  margin: 4px 0 0;
  font-family: var(--font-display);
  font-size: clamp(17px, 2vw, 21px);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
/* 44px minimum. It measured 24x26 in the top-right corner, and on a phone the panel is
   full-bleed with no backdrop to tap and no Escape key -- so this was the only way out of
   a full-screen modal, below the minimum target size and in the hardest corner to reach. */
.lab-panel-close {
  font: inherit;
  font-size: 22px;
  line-height: 1;
  color: var(--muted);
  background: none;
  border: 0;
  cursor: pointer;
  border-radius: 10px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  margin: -6px -8px -6px 0;
}
.lab-panel-close:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 2px;
}
.lab-panel-close:hover { color: var(--text); background: var(--surface-2); }
.lab-panel-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 0;
}

/* No top padding: the head below it owns that spacing, and the answer block above already
   closes with a hairline. Left in, it stacked to a 30px gap above the head against 0 below. */
.lab-panel-main { padding: 0 18px 0; min-width: 0; }
.lab-panel-side {
  border-left: 1px solid var(--line);
  padding: 16px 18px;
  min-width: 0;
  /* Column, so the feed can take the height the outcome summary used to occupy
     before it moved under the canvas -- otherwise the side ends after a 260px
     feed with ~800px of empty column below it. */
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.lab-panel-side .lab-feed {
  flex: 1 1 0;              /* see .lab-col-right .lab-feed -- basis 0, not auto */
  min-height: 200px;
  max-height: none;
}
.lab-panel-foot {
  margin: 0;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
  padding: 12px 18px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--muted);
}
.lab-panel-foot strong { color: var(--text); }
.lab-panel .lab-readout { margin: 16px -18px 0; padding: 15px 18px; }

/* A card that has a recorded run is selectable; one that does not stays inert. */
.forecast-card.has-scenario { cursor: pointer; transition: border-color .18s var(--ease), transform .18s var(--ease); }
.forecast-card.has-scenario:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.forecast-card.has-scenario:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

/* ---------- "this card does something" cue ---------- */
/* Always visible, never hover-only: on a phone there is no hover, and a reader who
   has not guessed the card is interactive will never produce one anyway. */
.card-foot:has(.card-run-hint) { justify-content: space-between; align-items: center; gap: 10px; }
.card-foot-hintonly { justify-content: flex-start; }
.card-run-hint {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; line-height: 1;
  color: var(--green-deep);
  background: var(--green-soft);
  border: 1px solid color-mix(in oklab, var(--green) 30%, transparent);
  border-radius: 999px; padding: 5px 10px 5px 8px;
  transition: background .18s var(--ease), border-color .18s var(--ease);
}
.card-run-play { font-size: 9px; line-height: 1; transform: translateY(0.5px); }
.forecast-card.has-scenario:hover .card-run-hint,
.forecast-card.has-scenario:focus-visible .card-run-hint {
  background: color-mix(in oklab, var(--green) 22%, var(--green-soft));
  border-color: var(--green);
}
/* Solid --green under --green-deep text measures 2.12:1. The running state should
   still read as "this one is playing", so it stays filled -- filled with the deep
   green and reversed out to the page's own surface. Hardcoding #fff would break in
   dark mode, where --green-deep inverts to a pale mint (#8ce9c4); var(--surface)
   flips with it and stays legible in both. */
.forecast-card.is-running .card-run-hint {
  background: var(--green-deep); border-color: var(--green-deep); color: var(--surface);
}

.forecast-card.is-running { border-color: color-mix(in oklab, var(--green) 55%, var(--line-strong)); }

@media (max-width: 900px) {
  .lab-panel-body { grid-template-columns: 1fr; }
  .lab-panel-side { border-left: 0; border-top: 1px solid var(--line); }
}

/* ---------- ask panel ---------- */
/* Sits in the middle column between the two side panels, and takes the slack the
   canvas does not use so an answer has room to be read. */
.lab-ask {
  border-top: 1px solid var(--line);
  margin: 16px -18px 0;
  padding: 15px 18px 18px;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.lab-ask-log { flex: 1; min-height: 90px; overflow-y: auto; scrollbar-width: thin; }
.lab-ask-log { display: grid; gap: 9px; margin-bottom: 11px; }
.lab-ask-log:empty { margin-bottom: 0; }
.lab-ask-q {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.lab-ask-a {
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}
.lab-ask-a b { color: var(--text); font-weight: 600; }
.lab-ask-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.lab-ask-chips button {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 11px;
  cursor: pointer;
}
.lab-ask-chips button:hover { border-color: var(--line-strong); color: var(--text); }
/* .lab-ask-form rules removed with the free-text box in swarm.html. */
.lab-ask-note {
  margin: 11px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--muted);
}
