/* AORI ops — the whole stylesheet.
 *
 * One hand-written file. No framework, no build step, no npm, and no remote font or asset of any
 * kind: the page most likely to be opened during an incident must not depend on somebody else's
 * CDN, and this app is served by FastAPI + Jinja out of a Python image and stays that way.
 *
 * This is an instrument, not a document. It is dense on purpose — an engineer mid-incident wants
 * every fact on one page — but density without hierarchy is a wall. Hierarchy comes from five
 * things and never from colour:
 *
 *   1. GLANCE        every panel opens with the same two devices — a headline callout and a row
 *                    of statistics — answering that panel's one question before a label is read.
 *                    Both are emitted by `_cells.html` and drawn once here, so a reader learns
 *                    the page on whichever tab they land on first rather than four times.
 *   2. RANK          one type scale of seven steps, base 13px, nothing carrying prose above 14.
 *                    Every step has one job and two things at different levels never share one.
 *   3. NESTING       panel -> environment -> process -> evidence. THREE levels, not four: the
 *                    process used to be a fourth box and is now a rule and a heavier heading,
 *                    and a group heading is drawn only where a group holds more than one
 *                    environment. Depth is a surface step plus spacing, never another border.
 *   4. VOICE         mono is for IDENTIFIERS ONLY — a prompt key, a model id, an env var, a
 *                    database, a room, a setting's name. Prose, labels, counts, figures and
 *                    headings are the UI sans. Figures carry `tabular-nums`, which is the column
 *                    alignment mono was previously being borrowed for.
 *   5. SHAPE         status is a silhouette plus a word. Filled disc = met, down triangle =
 *                    wrong, right triangle = rewritten, diamond = over but not yet a defect,
 *                    flat bar = nothing asked, hollow dashed ring = NOT MEASURED, hollow square
 *                    = not readable. Colour only ever agrees with a shape that already said it,
 *                    so the page survives greyscale, a projector and a red/green deficiency.
 *
 * The one rule this file cannot get wrong: `not_measured` is a THIRD STATE. It is not zero and it
 * is not an error. Zero is a solid figure; an error is filled and red; not-measured is hollow,
 * dashed and unfilled, in the neutral palette, with the words "not measured" in it. See
 * `.unmeasured` and `.m-unmeasured`.
 *
 * Contrast, computed from the rendered page rather than from the tokens — 1700 text elements and
 * 225 marks, every panel forced visible, in both schemes. Every text pair clears WCAG AA on the
 * surface it actually lands on, muted text inside a tinted row included; the lowest is 4.97:1
 * (light, `.sidenav-note`) and 5.08:1 (dark, `.chip.quiet`). Every meaning-bearing non-text mark
 * clears 3:1; the lowest are the absent-value hairline at 3.33 / 3.59 and the lightest bin fill
 * at 3.30 / 3.31.
 *
 * Layout target: 1280px to 2560px, verified with no horizontal overflow on any tab at 1280, 1440
 * and 2560. Nothing is fixed-width; every multi-column block is an auto-fit grid or a wrapping
 * flex row that collapses rather than overflowing, and every table lives in a `.scroller` so a
 * wide table scrolls itself instead of widening the page.
 */

:root {
  color-scheme: light dark;

  /* ---- spacing ---------------------------------------------------------------------------------
   * ONE BASE: 8px. Every page margin, section gap and component padding on this page is a whole
   * multiple of it, so two blocks that look aligned are aligned rather than four pixels apart.
   *
   * `--s-half` is the single documented exception and the only sub-8 value in the file. It is for
   * gaps INSIDE one component — a mark and the word beside it, a value and its subordinate line —
   * where 8px would separate the two halves of one thing. It is never a component padding, never
   * a section gap and never a page margin. Anything not on this ladder is a magic number.
   *
   * The 12px step the previous scale carried is gone on purpose. It was neither the base nor a
   * multiple of it, and it was doing the job of both 8 and 16 depending on where it landed — so
   * a card's padding and the gap above it agreed to within four pixels and never actually lined
   * up. Every one of its 58 uses is now 8 or 16, whichever the role asks for. */
  --s-half: 0.25rem;   /*  4px — inside one component only */
  --s-1: 0.5rem;       /*  8px — THE BASE: cell padding, chip gaps, tight stacks */
  --s-2: 1rem;         /* 16px — component padding, the gap between siblings */
  --s-3: 1.5rem;       /* 24px — card padding, the gap between blocks in a panel */
  --s-4: 2rem;         /* 32px — the gap between sections */
  --s-5: 3rem;         /* 48px — the gap between groups */
  --s-6: 4rem;         /* 64px — the floor of the page */

  /* ---- type scale ------------------------------------------------------------------------------
   * BASE 13px, and nothing carrying prose exceeds 14. A dense console is read by scanning, and a
   * scan is faster across a narrow band of sizes than a wide one: rank comes from weight, colour
   * and position, with size as the last resort rather than the first. The previous scale ran to
   * 36px and set body prose at 15, which made the largest thing in a panel the paragraph about
   * the panel.
   *
   * Seven steps, each with exactly one job, and two things at different levels of the page never
   * share one. The bottom three are a 1px dense floor rather than a ratio — at 11-13px a ratio
   * produces sizes the browser rounds back together — and the top four are ~1.3 apart, which is
   * where a ratio starts being visible at all. */
  --fs-micro: 0.6875rem;  /* 11 — a micro label naming the value under it */
  --fs-sub: 0.75rem;      /* 12 — a subordinate line under a value, and every machine value */
  --fs-body: 0.8125rem;   /* 13 — BASE. prose, table cells, notices, chips */
  --fs-lead: 0.875rem;    /* 14 — the body maximum: navigation, the breadcrumb, a flash */
  --fs-fig: 1.0625rem;    /* 17 — a figure, a process role        (base x 1.3) */
  --fs-title: 1.3125rem;  /* 21 — a card, group or panel title    (base x 1.6) */
  --fs-hero: 1.75rem;     /* 28 — the one number on a card that is a verdict  (base x 2.15) */

  /* ---- the micro label --------------------------------------------------------------------------
   * The small word naming the value under it: `Target`, `Schema`, `p95`, a column header.
   *
   * It used to be tracked at 0.11em, which is the letterspacing of a poster title applied to an
   * 11px word. Tracking defeats the one thing a label is for: a label is read by SHAPE in a single
   * fixation, and tracking dissolves the shape into a row of separate letters that have to be
   * assembled left to right. There are over two hundred of these on the page, each costing a
   * fixation it should not, which is most of why the console read as a terminal dump.
   *
   * So: one tracking value, barely above zero — enough that 11px capitals do not touch, not enough
   * to break a word apart — and sentence case wherever this file controls the text. Upper case
   * survives only where the words come from the backend and cannot be recased here. */
  --track-label: 0.015em;

  /* ---- the inset inside a token ----------------------------------------------------------------
   * A chip, a badge and a k=v token are not components on the spacing ladder — they are words with
   * a box drawn round them, and their padding has to track the word rather than the page. 8px of
   * padding on an 11px chip makes a button. So these two are `em`: they scale with whatever type
   * the token is set in, they are the ONLY spacing-like values in this file not on the 8px ladder,
   * and no layout ever uses them. */
  --inset-y: 0.2em;
  --inset-x: 0.62em;

  /* Mono runs optically larger than sans at the same px, so a machine value sits one step under
     the sans it shares a line with: 12 against the 13px base. */
  --fs-code: var(--fs-sub);
  --fs-code-sub: var(--fs-micro);

  --lh-tight: 1.2;
  --lh-snug: 1.35;
  --lh-prose: 1.55;

  /* ---- neutrals -------------------------------------------------------------------------------
   * Tinted, never pure: #000 and #fff both read as a rendering bug on a dense table. Four surfaces,
   * one per nesting level, so depth is a background step rather than another border. */
  --bg: #eceff4;
  --surface: #ffffff;
  --surface-2: #f5f7fa;
  --surface-3: #e9edf3;
  --line: #dce1e9;
  --line-2: #c3cad6;
  --line-3: #aab3c2;

  --ink: #0f1318;
  --ink-2: #39414d;
  --muted: #59636f;
  /* Column headers and field labels: one step stronger than --muted, because they are read as
     structure rather than as an aside. */
  --label: #434e5d;
  /* The hairline that stands in for an absent value, and the dashed ring that stands in for an
     unmeasured one. Not text, so held to 3:1 rather than 4.5:1 — but held to it deliberately:
     both carry meaning. */
  --nil: #798392;

  --accent: #1a4bc4;
  --accent-ink: #ffffff;
  --accent-soft: #e9effd;
  --accent-line: #bccdf5;

  --ok: #0d6238;   --ok-soft: #e6f7ec;   --ok-line: #b3e3c6;
  --warn: #7d4406; --warn-soft: #fcf3e3; --warn-line: #eed6a4;
  --bad: #a81f16;  --bad-soft: #fdedeb;  --bad-line: #f2c0bb;
  /* Prose inside a red or amber panel. Full-strength --bad is for the words that name the fault. */
  --bad-text: #78201a;
  --warn-text: #63380a;
  --ok-text: #0a4f2d;
  --bad-ink: #ffffff;

  /* ---- the latency/cost bin ramp -------------------------------------------------------------
   * Four fills for the four bins on the Performance tab, and they are NOT the four status colours
   * above. Two reasons they are their own tokens.
   *
   * First, a bin is a magnitude, not a verdict. `--ok` and `--bad` are for "this met its target"
   * and "this is broken"; a bar in a distribution is neither, it is a count.
   *
   * Second and the actual design constraint: the status colours are all within 1.06:1 of each
   * other in LUMINANCE — computed, and it is the whole problem. Four bars painted `--accent`,
   * `--ok`, `--warn`, `--bad` are four indistinguishable greys on a projector or to a reader with
   * a red/green deficiency. So this ramp is monotonic in contrast against the bar track, not just
   * in hue: 3.30 / 4.41 / 5.50 / 6.61 to 1, ascending with severity. The breach bar therefore
   * carries the most visual weight of the four whatever happens to the colour, which is exactly
   * the bin the eye is supposed to find first. Adjacent greyscale steps are 1.34 / 1.25 / 1.20,
   * and end to end good-to-breach is 2.00 — a visible lightness ramp, reinforced by the shape
   * rules in `.strip-seg` and the mark and word in every row's chip.
   *
   * Reversed in dark mode, where the same ascending-contrast rule puts the breach bar at the
   * light end. The rule is "most contrast against the background it sits on", not "darkest". */
  --bin-good: #547ede;
  --bin-target: #1d7c50;
  --bin-over: #8b500e;
  --bin-breach: #a01f16;
  /* The track every bar is drawn on, and the reference the ratios above are computed against. */
  --bin-track: var(--surface-3);
  /* The fill for a bar with NO severity — the trial tab's raw distributions, which describe rather
     than judge. It was `--line-3`, a border token, which measured 1.80:1 against the track: a bar
     whose LENGTH is its meaning, drawn in a colour you cannot see the end of. Its own token now,
     picked to clear 3:1 against the track in both schemes (3.64 light / 3.75 dark) while staying
     obviously quieter than any of the four severity fills above. */
  --bar-neutral: #727b8a;

  --radius: 8px;
  --radius-sm: 5px;
  --radius-xs: 3px;
  --shadow: 0 1px 2px rgba(15, 19, 24, 0.05);
  --shadow-2: 0 1px 3px rgba(15, 19, 24, 0.08), 0 4px 12px rgba(15, 19, 24, 0.05);

  /* Height of the sticky chrome on the sign-in page, which still uses it. */
  --chrome-h: 2.75rem;
  --sidenav-item-h: 2.25rem;

  /* The rail is sized to the longest section name plus its badge at the selected weight, so the
     canvas never reflows when the selection moves. Measured, not chosen: "Performance" + a
     "152 turns" badge is the widest pair the four sections can produce. */
  --sidenav-w: 15rem;
  /* One step back from --surface so the rail reads as chrome and the panels as content. */
  --sidenav-bg: #e4e8ef;

  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
          sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Cool rather than neutral: a blue-black keeps the amber and red warnings from turning muddy. */
    --bg: #0d1014;
    /* Darker than --bg, not lighter: in dark mode chrome recedes by losing light, so the rail sits
       under the canvas rather than floating above it. */
    --sidenav-bg: #090b0e;
    --surface: #14181e;
    --surface-2: #1a1f27;
    --surface-3: #222933;
    --line: #272f3a;
    --line-2: #3b4553;
    --line-3: #4d596a;

    --ink: #e8ecf2;
    --ink-2: #b6bfcc;
    --muted: #8f99a7;
    --label: #aeb8c6;
    --nil: #6b7686;

    --accent: #8badff;
    --accent-ink: #0a1226;
    --accent-soft: #151f38;
    --accent-line: #2c4078;

    --ok: #5fd398;   --ok-soft: #0c2317;   --ok-line: #1d4a34;
    --warn: #f0b25c; --warn-soft: #2a2010; --warn-line: #5d4516;
    --bad: #ff9189;  --bad-soft: #2b1416;  --bad-line: #65272a;
    --bad-text: #ffd6d1;
    --warn-text: #f8dcb2;
    --ok-text: #c2f0d6;
    --bad-ink: #2b0a0b;

    /* Same rule, mirrored: ascending contrast against `--surface-3`, which in dark mode means
       ascending lightness. 3.31 / 4.39 / 5.52 / 6.59 to 1. */
    --bar-neutral: #77828f;

    --bin-good: #4a74d5;
    --bin-target: #2e9f6b;
    --bin-over: #e6881c;
    --bin-breach: #f9918a;

    --shadow: none;
    --shadow-2: none;
  }
}

/* ================================================================================================
   base
   =============================================================================================== */

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: var(--fs-body)/var(--lh-prose) var(--sans);
  -webkit-font-smoothing: antialiased;
  /* Versions, commits, hashes, poll counts and metric values are all compared down a column by eye.
     Proportional digits make 12 and 19 different widths, which is precisely the comparison being
     attempted. Set on the root so no figure anywhere can forget it. */
  font-variant-numeric: tabular-nums;
  scrollbar-color: var(--line-2) transparent;
}

code {
  font-family: var(--mono);
  font-size: var(--fs-code);
  overflow-wrap: anywhere;
}

a { color: var(--accent); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Available to a screen reader, absent from the page. Used for a table caption that would be
   redundant beside its own visible heading but is the only orientation a row-by-row reader gets. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* An absent value. A short hairline rather than an em dash: a column of dashes reads as a column of
   content that has to be parsed and discarded, and — critically — a blank commit on production must
   not read either as a difference from staging or as a failed render. It is a mark, not a glyph. */
.nil {
  display: inline-block;
  width: 0.8em;
  height: 2px;
  border-radius: 1px;
  background: var(--nil);
  vertical-align: 0.22em;
}

/* ================================================================================================
   status marks — shape first, colour second

   Five silhouettes that cannot be confused with one another at 10px, each inheriting currentColor
   from the chip it sits in so one rule serves every palette. Remove all colour from this page and
   every status is still readable.
   =============================================================================================== */

.mark {
  display: inline-block;
  flex: none;
  width: 0.6em;
  height: 0.6em;
  background: currentColor;
}
/* met — the only solid round mark */
.mark-met { border-radius: 50%; }
/* wrong — a down triangle, which reads as "under" as well as "alarm" */
.mark-below {
  clip-path: polygon(50% 100%, 0 12%, 100% 12%);
  transform: translateY(0.02em);
}
/* rewritten — a right-pointing triangle, because the statement is directional: configured BECAME
   something else. Deliberately not the down triangle, which on this page means "wrong": a model the
   provider rewrote is a different fault from a model two environments disagree on, and the two are
   never allowed to wear the same shape. */
.mark-rewritten {
  clip-path: polygon(100% 50%, 12% 0, 12% 100%);
  transform: translateY(0.02em);
}
/* nothing was asked for — a flat bar, the quietest mark here */
.mark-neutral {
  height: 2px;
  width: 0.7em;
  border-radius: 1px;
  transform: translateY(-0.18em);
}
/* NOT MEASURED — hollow and dashed. The only unfilled mark on the page, which is the whole point:
   a state with no value in it is drawn as a shape with nothing in it. */
.mark-unmeasured {
  background: none;
  border: 1.5px dashed currentColor;
  border-radius: 50%;
  width: 0.72em;
  height: 0.72em;
}
/* OVER TARGET BUT NOT YET A DEFECT — a diamond. Its own silhouette rather than a borrowed one:
   amber and red differ only in hue, and hue is the single channel this page refuses to rely on.
   Reading the ramp by shape alone gives disc, disc, diamond, down triangle — "inside, inside,
   watch it, broken". */
.mark-over {
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
  width: 0.66em;
  height: 0.66em;
}
/* NOT READABLE — a hollow SQUARE with a solid border. The third empty state on this dashboard and
   the newest, so it is worth saying what it is not: it is not `.mark-unmeasured` (hollow, dashed,
   ROUND), which means "there is traffic and this figure has no source"; and it is not
   `.mark-neutral` (a flat bar), which on the Performance tab means "we read this environment and
   nothing happened in it". This one means "we could not read it at all" — the ops box's Atlas
   credential is not scoped to that database. Round vs square vs bar survives greyscale; amber vs
   neutral only says it twice. */
.mark-blocked {
  background: none;
  border: 1.5px solid currentColor;
  border-radius: 1px;
  width: 0.66em;
  height: 0.66em;
}

/* ================================================================================================
   chip — one small labelled token, used for every status on the page
   =============================================================================================== */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.36em;
  padding: var(--inset-y) var(--inset-x);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  background: var(--surface);
  color: var(--ink-2);
  font-size: var(--fs-micro);
  font-weight: 650;
  line-height: 1.45;
  letter-spacing: 0.02em;
  text-transform: lowercase;
  white-space: nowrap;
}
.chip.quiet { color: var(--muted); border-color: var(--line); background: transparent; }
.chip.ok { color: var(--ok-text); border-color: var(--ok-line); background: var(--ok-soft); }
.chip.warn { color: var(--warn-text); border-color: var(--warn-line); background: var(--warn-soft); }
/* The only solid fill among the chips. Reserved for a sentence that is expensive to misread —
   "process down", "not serving calls", "differs" — so its rarity is itself information. */
.chip.bad {
  color: var(--bad-ink);
  border-color: var(--bad);
  background: var(--bad);
}
/* Deliberately not the deployed state: somebody installed this on purpose. Blue, never red. */
.chip.live { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
/* A chip that needs its own line because it follows another chip in the same cell. */
.chip.block { display: flex; width: fit-content; margin-top: var(--s-half); }

.chip.s-ok { color: var(--ok-text); border-color: var(--ok-line); background: var(--ok-soft); }
.chip.s-over { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.chip.s-warn { color: var(--warn-text); border-color: var(--warn-line); background: var(--warn-soft); }
.chip.s-fault { color: var(--bad-ink); border-color: var(--bad); background: var(--bad); }

/* Metric status. `met` and `below` are tinted; `neutral` is silent; `unmeasured` is hollow and
   dashed on no fill at all, and shares nothing visually with either the ok or the bad palette. */
.chip.st-met { color: var(--ok-text); border-color: var(--ok-line); background: var(--ok-soft); }
.chip.st-below { color: var(--bad-text); border-color: var(--bad-line); background: var(--bad-soft); }
.chip.st-neutral { color: var(--muted); border-color: var(--line); background: transparent; }
.chip.st-unmeasured {
  color: var(--label);
  border: 1px dashed var(--nil);
  background: transparent;
}

/* Bin severity, on the Performance tab. Text pairs computed on the surface they land on:
   6.40 / 8.70 / 9.08 / 7.31 to 1 (light) and 7.41 / 13.19 / 12.09 / 8.40 (dark). `bin-breach` is
   the only solid fill among these, for the same reason `.chip.bad` is the only solid fill among
   those: its rarity is itself information. */
.chip.bin-good { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.chip.bin-target { color: var(--ok-text); border-color: var(--ok-line); background: var(--ok-soft); }
.chip.bin-over { color: var(--warn-text); border-color: var(--warn-line); background: var(--warn-soft); }
.chip.bin-breach { color: var(--bad-ink); border-color: var(--bad); background: var(--bad); }
.chip.bin-none { color: var(--muted); border-color: var(--line); background: transparent; }

/* NOT READABLE and NO TRAFFIC. Amber for the first because the numbers on the page are silently
   incomplete while it is true; neutral for the second because a quiet environment is not a
   problem. The words differ, the marks differ in silhouette, and neither is ever a zero. */
.chip.st-blocked { color: var(--warn-text); border-color: var(--warn-line); background: var(--warn-soft); }
.chip.st-idle { color: var(--muted); border-color: var(--line); background: transparent; }

/* ================================================================================================
   figures and the third state
   =============================================================================================== */

/* A number meant to be compared down a column. Never used for a NULL metric.
 *
 * SANS, not mono, and this is the single change that does most of the work in rule 3 below.
 * Mono is this page's mark for "an identifier a machine reported" — a prompt key, a model id, a
 * room name, a database. A count is not one of those: it is something the page computed or read,
 * and dressing it as an identifier was half of why prose and values looked alike. Tabular figures
 * do the column-alignment job that mono was being used for, and they do it without borrowing
 * mono's meaning. */
.figure {
  font-size: var(--fs-fig);
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
/* Every numeric cell, so a column of them aligns whatever it is wrapped in. Inherited from `body`
 * already; restated here because a cell whose figure is inside a `code` or a form control would
 * otherwise pick up that element's own numeric defaults. */
.hist-n,
.col-value,
.binbars-v,
.tab-badge,
td .figure,
th .figure,
code { font-variant-numeric: tabular-nums; }
.unit {
  font-size: var(--fs-sub);
  color: var(--muted);
  margin-left: 0.2em;
}

/* THE THIRD STATE.
 *
 * "We did not measure this" — not zero, not a failure. Hollow, dashed, on no fill, in the neutral
 * palette, with the words in it. It shares no property with a figure (which is solid mono at
 * --fs-fig) and none with an error (which is filled and red), so the difference between "0" and "we
 * never looked" is legible before a single word is read. The whole trial tab's credibility rests
 * on this, which is why it is the most explicit block in this file. */
.unmeasured {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: var(--inset-y) var(--inset-x);
  border: 1px dashed var(--nil);
  border-radius: var(--radius-xs);
  background: none;
  color: var(--label);
  font-size: var(--fs-sub);
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

/* ================================================================================================
   chrome
   =============================================================================================== */

header.chrome {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--chrome-h);
  padding: 0 var(--s-3);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.brand {
  font-size: var(--fs-lead);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: var(--ink);
  text-decoration: none;
}
/* "ops" in mono: the same device the tables use — the machine half of a name is always mono. */
.tag {
  font-weight: 600;
  color: var(--accent);
}
.chrome-say { flex: 1; color: var(--muted); font-size: var(--fs-sub); }
form.inline { display: inline; margin: 0; }

main {
  max-width: 104rem;
  margin: 0 auto;
  padding: var(--s-3) var(--s-3) var(--s-6);
}

/* ================================================================================================
   console shell — rail, top bar, canvas

   A two-column grid rather than a centred column. The rail is fixed and full-height so the four
   section names are always in the same place; the canvas is the only thing that scrolls, so the
   selected section's name does not leave the screen when you read to the bottom of a long panel.
   =============================================================================================== */

.app {
  display: grid;
  grid-template-columns: var(--sidenav-w) minmax(0, 1fr);
  align-items: start;
  min-height: 100vh;
}

.sidenav {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  height: 100vh;
  padding: var(--s-2) 0;
  background: var(--sidenav-bg);
  border-right: 1px solid var(--line-2);
}
.sidenav-brand {
  padding: 0 var(--s-2) var(--s-2);
  font-size: var(--fs-lead);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
/* Pushed apart from the nav so the page metadata reads as a footer of the rail and not as a fifth
   destination. `margin-top: auto` rather than a fixed offset, because the nav's height is the
   number of sections and that is not this rule's business. */
.sidenav-foot {
  margin-top: auto;
  padding: var(--s-2) var(--s-2) 0;
  border-top: 1px solid var(--line);
}
.sidenav-note {
  margin: var(--s-1) 0 var(--s-1);
  font-size: var(--fs-micro);
  line-height: var(--lh-snug);
  color: var(--muted);
}

.workspace { min-width: 0; }

/* Crumb, one-line claim, provenance — left, middle, right. The provenance is what gives the right
   end of this bar a job: at 1600px and up it was empty while the tables underneath were being
   squeezed into their own scrollers, which is a header taking width from content and returning
   nothing for it. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-1) var(--s-3);
  padding: var(--s-1) var(--s-3);
  background: var(--surface);
  border-bottom: 1px solid var(--line-2);
}
.crumbs {
  display: flex;
  align-items: baseline;
  gap: var(--s-1);
  margin: 0;
  font-size: var(--fs-lead);
  white-space: nowrap;
}
.crumb-root { color: var(--muted); }
/* `--muted`, not `--nil`. The hairline token is held to 3:1 because it is a MARK; this is a
   glyph, and a glyph is text whatever it separates — it measured 3.84:1 and now clears 4.5. */
.crumb-sep { color: var(--muted); }
.crumb-leaf { font-weight: 700; color: var(--ink); letter-spacing: -0.01em; }
/* The provenance sentence. It was the page's h1 at 24px, which made the first thing you read a
   paragraph about where numbers come from rather than the numbers; then it was three lines of
   chrome repeated on all four tabs. One line now, and the clauses it shed are stated on the two
   panels they actually govern. */
.topbar-say {
  flex: 1 1 20rem;
  margin: 0;
  font-size: var(--fs-sub);
  line-height: var(--lh-snug);
  color: var(--muted);
}
.topbar-say strong { color: var(--ink-2); font-weight: 650; }
/* Pushed to the right edge and allowed to disappear before the sentence does: it is provenance
   rather than a finding, and it is still in the page source when the viewport cannot hold it. */
.topbar-stamp {
  margin-left: auto;
  grid-auto-flow: column;
  gap: 0 var(--s-2);
  white-space: nowrap;
}

/* 120rem, not 104. At 2560px the old cap left ~900px of empty page beside tables that were
   still scrolling themselves horizontally, which is the one arrangement that is wrong at both
   ends. Every block of prose here is capped in `ch` by its own rule, so the extra width reaches
   the tables and never the reading measure. */
.canvas {
  max-width: 120rem;
  margin: 0;
  padding: var(--s-3) var(--s-3) var(--s-6);
}

/* ================================================================================================
   prose inside panels
   =============================================================================================== */

/* A panel's opening sentence, and the sentences between its cards.

   Both are set one step BELOW the figures they introduce, which is the inversion that turned this
   page from an article into an instrument. They used to be 15px prose at reading line-height, so
   the largest text in a panel was the paragraph about the panel rather than the number in it, and
   a reader scanning for a value had to read past an argument to find one. The argument still has
   to be here — every figure on this page is contestable and the sentence is how it defends itself
   — so it is demoted, not deleted, and `strong` still lifts the load-bearing clause. */
.lede {
  color: var(--muted);
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  margin: var(--s-1) 0 0;
  max-width: 108ch;
}
.lede strong { color: var(--ink-2); font-weight: 650; }

.prose {
  color: var(--muted);
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  margin: 0 0 var(--s-1);
  max-width: 108ch;
}
.prose code { color: var(--ink); }
.muted { color: var(--muted); }
.foot-note {
  color: var(--muted);
  font-size: var(--fs-sub);
  margin: var(--s-2) 0 0;
}

/* Machine metadata about the page itself, as a definition list rather than a paragraph: each value
   is a fact with a name, and naming them in markup is what lets them be read in any order. */
.stamp {
  display: grid;
  gap: var(--s-half) var(--s-2);
  margin: 0;
  font-size: var(--fs-sub);
  color: var(--muted);
  text-align: right;
}
.stamp > div { display: flex; gap: var(--s-1); justify-content: flex-end; }
.stamp dt { font-weight: 600; color: var(--label); }
.stamp dd { margin: 0; color: var(--ink-2); }
.stamp code { font-size: var(--fs-code-sub); color: var(--ink-2); }
.stamp-inline { text-align: left; margin-top: var(--s-1); }
.stamp-inline > div { justify-content: flex-start; }
/* Provenance on one wrapping line rather than a stack. None of these is a finding — which period,
   which database, which day 0 — and read as a column they were a screenful before the first
   number. Wrapped, the whole set is two lines and still reachable in any order. */
.stamp-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-half) var(--s-3);
}
.stamp-row > div { flex: 0 1 auto; min-width: 0; }
.stamp-why { margin: var(--s-half) 0 0; max-width: 96ch; }

/* ================================================================================================
   rail navigation

   Selection is a filled row with an accent bar on its leading edge — the convention every
   operations console uses, and the one that survives the panels below spending their colour on
   faults. The bar is on the edge rather than a coloured label so a selected row and a red status
   chip inside it are never the same signal.
   =============================================================================================== */

.tabs {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 0;
  padding: 0 var(--s-1);
  overflow-y: auto;
}
.tab {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  min-height: var(--sidenav-item-h);
  padding: var(--s-1) var(--s-1);
  color: var(--ink-2);
  font-size: var(--fs-body);
  font-weight: 550;
  text-decoration: none;
  border-radius: var(--radius-xs);
  /* The accent edge is always present and usually transparent: painting it only when selected
     would shift every label by 2px as the selection moves. */
  border-left: 2px solid transparent;
  transition: color 0.12s ease-out, background 0.12s ease-out;
}
.tab:hover { color: var(--ink); background: var(--surface-3); }
.tab[aria-selected="true"] {
  color: var(--ink);
  font-weight: 700;
  background: var(--surface);
  border-left-color: var(--accent);
}
.tab-label { flex: 1; }

/* Without the script there is no selected row, because nothing is hidden and every section is
   simply on the page. The rail is then a set of jump links, and marking one of them "current"
   would be a claim about state that does not exist. */
.tabs:not([role="tablist"]) .tab:hover { border-left-color: var(--line-3); }

/* A count the backend computed, printed verbatim. Mono and tabular so "7/12" and "152 turns" do
   not change the row's width as the numbers move. */
.tab-badge {
  font-size: var(--fs-code-sub);
  font-weight: 600;
  color: var(--ink-2);
  background: var(--surface-3);
  border-radius: 999px;
  padding: var(--inset-y) var(--inset-x);
  white-space: nowrap;
}
.tab[aria-selected="true"] .tab-badge { background: var(--surface-3); color: var(--ink); }

/* Stacked, script-free reading: each panel is a section of one long page, so it needs a rule above
   it that the tabbed version does not. */
.canvas .panel + .panel {
  margin-top: var(--s-6);
  padding-top: var(--s-4);
  border-top: 2px solid var(--line-2);
}
/* ...but not once the script has taken over, when exactly one panel is ever on screen and a rule
   above it would be a divider from nothing. */
.canvas .panel[role="tabpanel"] + .panel[role="tabpanel"] {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.panel:focus-visible { outline-offset: 6px; }

/* A panel opens with a title, its one-line explanation, and a row of statistics — in about 90px
 * rather than the ~200px it used to spend. The title and the explanation share a baseline because
 * they are one statement, and a laptop's fold is worth more than the line break between them. */
.panel-head {
  display: grid;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
}
.panel-title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-half) var(--s-2);
}
.panel-head h2 {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.panel-title-row .lede { flex: 1 1 24rem; margin: 0; }

/* ================================================================================================
   notices — one shape for "the page has something to say about what is below it"
   =============================================================================================== */

.notice {
  margin: var(--s-1) 0;
  padding: var(--s-1) var(--s-2);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--line-3);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: var(--fs-body);
  line-height: var(--lh-prose);
}
.notice strong { color: var(--ink); }
.notice.ok {
  background: var(--ok-soft);
  border-color: var(--ok-line);
  border-left-color: var(--ok);
  color: var(--ok-text);
}
.notice.ok strong { color: var(--ok); }
.notice.warn {
  background: var(--warn-soft);
  border-color: var(--warn-line);
  border-left-color: var(--warn);
  color: var(--warn-text);
}
.notice.warn strong { color: var(--warn); }
.notice.error {
  background: var(--bad-soft);
  border-color: var(--bad-line);
  border-left-color: var(--bad);
  color: var(--bad-text);
}
.notice.error strong { color: var(--bad); }
.flash { margin: 0 0 var(--s-2); font-size: var(--fs-lead); }

/* A machine string inside a notice: its own line, wrapped and never clipped. */
.reason { margin: var(--s-1) 0 0; }
.verbatim {
  display: block;
  padding: var(--s-1) var(--s-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-code);
  /* `pre-wrap` keeps a multi-line traceback's own breaks; `anywhere` lets a 300-character URL wrap
     instead of widening the card past the viewport. Never truncated: for an unreachable box this
     string is the only diagnostic the page has. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* A reason that is a sentence rather than a machine token — a sidecar that is unreachable, a
   feature that is not configured. Prose gets prose treatment. */
.reason-prose {
  margin: var(--s-1) 0 0;
  overflow-wrap: anywhere;
}

.empty-block {
  margin: var(--s-1) 0;
  padding: var(--s-2);
  border: 1px dashed var(--line-2);
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: var(--fs-body);
  text-align: center;
}

/* ================================================================================================
   section labels and small print
   =============================================================================================== */

/* Small caps trailing a hairline to the right edge, so four sections inside one card read as four
   sections and not as one wall with bold words in it. */
h5 {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
  margin: var(--s-3) 0 var(--s-1);
}
h5::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}
/* One qualification about a whole section, riding on its label. Sentence case and no tracking, so
   it reads as the aside it is next to the small caps it follows, and it costs the page no line of
   its own. */
.h5-note {
  flex: 0 1 auto;
  min-width: 0;
  font-size: var(--fs-sub);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
.h5-note code { font-size: var(--fs-code-sub); color: var(--ink-2); }

/* ================================================================================================
   facts — a dense name/value grid, used at every level of the page

   auto-fit rather than a fixed column count: the same markup has to read at 1280px, where it is two
   columns, and at 2560px, where it is six, without either a media query per level or a row of
   stretched cells.
   =============================================================================================== */

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--s-1) var(--s-2);
  margin: 0;
}
.facts > div { min-width: 0; }
.facts dt {
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.facts dd {
  margin: 0.15em 0 0;
  font-size: var(--fs-body);
  color: var(--ink);
  min-width: 0;
}
/* The one fact in a group that carries the verdict for it, so it is allowed to start the row. */
.facts > .lead dt { color: var(--ink-2); }
/* A gloss under a machine value — the vocabulary spelled out, not a derived claim. */
.dd-sub {
  display: block;
  font-size: var(--fs-sub);
  line-height: var(--lh-snug);
  color: var(--muted);
}

/* ================================================================================================
   THE GLANCE PRIMITIVES — the same two devices on all four tabs

   The Performance tab had these and the other three did not, which is the whole of why it read
   better: it opened with a verdict and a row of statistics, and they opened with a paragraph and
   a table. A console's first job is to answer "is anything wrong" before a label is read, and
   these are the two shapes that do it. Both are drawn here once, and `_cells.html` is the only
   place that emits them.
   =============================================================================================== */

/* A ROW OF STATISTICS, directly under a panel's title. Sits on the page rather than in a box: the
   panel below it already has boxes, and a summary inside another border is a fifth level of
   nesting bought for no information. The rule underneath is what separates it. */
/* Flex, not the `.facts` grid it borrows the rest of its type from. A grid column sizes to the
   widest thing in it, and the widest thing in a statistic is its subordinate sentence — so on a
   grid one long caveat stretched every column on the row and left the figures acres apart. Flex
   lets each statistic be as wide as it needs and the sentence wrap inside it. */
.statrow {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--s-1) var(--s-4);
  margin: 0;
}
.statrow > div { flex: 0 1 auto; min-width: 0; max-width: 34rem; }
/* The hairline is a modifier, not part of the row. At a panel's top it is what separates the
   summary from the evidence; inside a card the card's own border already does that, and a second
   rule there is the nesting this pass is removing. */
.statrow-rule { padding-bottom: var(--s-2); border-bottom: 1px solid var(--line-2); }
.statrow dd {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 var(--s-half);
  margin-top: 0;
}
.statrow .dd-sub { flex: 1 0 100%; }
/* The mark rides with the label rather than the figure — see the note in `_cells.html`: a flat
   bar in front of a numeral is a minus sign. */
.statrow dt { display: flex; align-items: center; gap: var(--s-half); }
/* The one statistic carrying the panel's verdict: the figure a step larger, the label in full ink.
   Exactly one per row — a row where everything is emphasised has emphasised nothing. */
.statrow > .lead .figure { font-size: var(--fs-title); }
.statrow > .lead dt { color: var(--ink); }
/* Tone colours the FIGURE and the mark, never the row: a tinted summary band would compete with
   the faults below it, which are the thing it is pointing at. Each tone always arrives with its
   own silhouette from `statrow`, so none of these is carrying the state on its own. */
.statrow > .st-ok .figure, .statrow > .st-ok .mark { color: var(--ok); }
.statrow > .st-warn .figure, .statrow > .st-warn .mark { color: var(--warn); }
.statrow > .st-bad .figure, .statrow > .st-bad .mark { color: var(--bad); }
.statrow > .st-quiet .figure, .statrow > .st-quiet .mark { color: var(--muted); }

/* THE HEADLINE CALLOUT. One figure at the top of the type scale, because the number that matters
   most is routinely the smallest one on the page: a 13% breach share is a short bar, and a
   distribution draws it faithfully and faithfully makes it small. */
.kpi {
  max-width: 46rem;
  padding: var(--s-2);
  border: 1px solid var(--line-2);
  border-left: 4px solid var(--line-3);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
/* Inside the Performance headline it is already in a sized grid column, so the standalone cap
   would fight the grid rather than help it. */
.perf-headline > .kpi { max-width: none; }
.kpi-bad { border-color: var(--bad-line); border-left-color: var(--bad); background: var(--bad-soft); }
.kpi-ok { border-color: var(--ok-line); border-left-color: var(--ok); background: var(--ok-soft); }
.kpi-label {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  margin: 0 0 var(--s-1);
  font-size: var(--fs-micro);
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.kpi-bad .kpi-label { color: var(--bad); }
.kpi-ok .kpi-label { color: var(--ok); }
.kpi-figure {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin: 0;
}
.kpi-bad .kpi-figure .figure { color: var(--bad); }
.kpi-ok .kpi-figure .figure { color: var(--ok); }
.kpi-say {
  margin: var(--s-1) 0 0;
  font-size: var(--fs-body);
  line-height: var(--lh-prose);
  color: var(--ink-2);
}
/* Inside the Performance headline the callout is a narrow grid column beside the stat row, so its
   sentence is measured in characters; standing alone it fills the box it is given. */
.perf-headline > .kpi .kpi-say { max-width: 46ch; }
.kpi-bad .kpi-say { color: var(--bad-text); }
.kpi-ok .kpi-say { color: var(--ok-text); }
/* The hero step, used by the callout and by the two inline alarms that are the same statement in
   a sentence rather than in a box. Nothing else on the page is allowed this size. */
.fig-hero { font-size: var(--fs-hero); line-height: 1; }

/* Two fact groups side by side, each boxed, for a readout with two independent halves. */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  gap: var(--s-1);
}
.stat-group {
  padding: var(--s-1) var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}

/* k=v tokens, for settings with no column of their own. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-half) var(--s-1);
  list-style: none;
  margin: var(--s-1) 0 0;
  padding: 0;
}
.chips li {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3em;
  padding: var(--inset-y) var(--inset-x);
  border: 1px solid var(--line);
  border-radius: var(--radius-xs);
  background: var(--surface-2);
}
/* The key half of a k=v token, and MONO: a setting's name is an identifier the process reported,
   exactly like the value beside it. It was sans and letter-spaced, which dressed an env-var name
   as a piece of the interface's own vocabulary. Weight and colour keep the two apart now — the
   key recedes, the value is in full ink — without giving the key a typeface that says it is
   something the dashboard wrote. */
.chip-k {
  font-family: var(--mono);
  font-size: var(--fs-code-sub);
  font-weight: 600;
  color: var(--muted);
}
.chip-v { font-size: var(--fs-code-sub); color: var(--ink); }

/* ================================================================================================
   tables

   Every table is wrapped in a `.scroller`, so a table too wide for the viewport scrolls itself
   rather than widening the page and pushing the layout sideways — which at 1280px it will.
   =============================================================================================== */

.scroller {
  overflow-x: auto;
  /* A scroll container is not focusable by default, so a keyboard user cannot scroll it. Making it
     a tab stop is the accessible fix for the pattern. */
  scrollbar-width: thin;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-body);
}
caption { text-align: left; }
thead th {
  position: relative;
  padding: var(--s-1) var(--s-1);
  text-align: left;
  vertical-align: bottom;
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
  white-space: nowrap;
  border-bottom: 1px solid var(--line-2);
}
tbody th,
tbody td {
  padding: var(--s-1) var(--s-1);
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
}
tbody th { font-weight: 600; }
tbody tr:last-child > * { border-bottom: 0; }
table.narrow { font-size: var(--fs-body); }
table.narrow tbody th,
table.narrow tbody td { padding: var(--s-half) var(--s-1); }

/* A subordinate fact under the value in a cell: a file under a prompt key, a provider under a role,
   a source under a metric. Always smaller, always muted, never its own column. */
.cell-sub {
  display: block;
  margin-top: 0.15em;
  font-size: var(--fs-sub);
  line-height: var(--lh-snug);
  color: var(--muted);
  font-weight: 400;
}
.cell-sub code { font-size: var(--fs-code-sub); color: var(--ink-2); }
.cell-sub .figure { font-size: var(--fs-body); font-weight: 600; color: var(--ink-2); }

/* The column the table is read for. One step heavier than its neighbours, never a different size. */
.effective code { font-weight: 650; }
/* "There is no override", as a word — because null and false mean different things here and only
   one of them is drawn as a mark. */
.none {
  font-size: var(--fs-sub);
  color: var(--muted);
  font-style: normal;
}
.empty {
  padding: var(--s-2) var(--s-1);
  color: var(--muted);
  font-size: var(--fs-body);
}
.ident { display: inline-block; }
.sha { display: block; }
.sha code { font-size: var(--fs-code-sub); color: var(--muted); }
.pname { margin-left: var(--s-1); }
.pname code { font-size: var(--fs-code-sub); color: var(--muted); }

/* Row emphasis. A left rail rather than a full tint wherever possible: a tinted row competes with
   the chips inside it, and the rails stack down a column into a readable profile of the table. */
tbody tr.row-live > *:first-child { box-shadow: inset 3px 0 0 var(--accent); }
tbody tr.row-warn > *:first-child { box-shadow: inset 3px 0 0 var(--warn); }
tbody tr.row-bad > *:first-child { box-shadow: inset 3px 0 0 var(--bad); }
tbody tr.row-bad { background: var(--bad-soft); }
tbody tr.row-bad > * { color: var(--bad-text); }
tbody tr.row-bad code { color: var(--bad-text); }

/* Settings and notes belonging to the row above, so the border between them is suppressed and the
   background steps back one level. */
tbody tr.detail-row > td {
  padding-top: 0;
  background: var(--surface-2);
}
tbody tr.detail-row .chips { margin-top: 0; }
/* A settings row belonging to a marked row above keeps that row's tint. Without this the `td`
   background wins over the `tr` background and punches a neutral hole through the middle of a
   drifted or broken group, which reads as the group ending there. */
tbody tr.row-bad.detail-row > td { background: var(--bad-soft); }
.t-drift tbody tr.row-drift.detail-row > td { background: var(--bad-soft); }
.detail-note {
  margin: 0 0 var(--s-half);
  font-size: var(--fs-sub);
  line-height: var(--lh-snug);
  color: var(--muted);
  max-width: 96ch;
}

/* ================================================================================================
   instances — group / environment / process
   =============================================================================================== */

.group { margin-bottom: var(--s-5); }
.group-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-1) var(--s-2);
  padding-bottom: var(--s-1);
  margin-bottom: var(--s-2);
  border-bottom: 2px solid var(--line-2);
}
.group-title {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.014em;
}
/* reachable-of-total, at a glance. Tabular figures so the counts of stacked groups line up. */
.group-count {
  margin: 0;
  font-size: var(--fs-body);
  color: var(--muted);
}
.group-count .figure { font-size: var(--fs-fig); color: var(--ink); }
/* The one thing a group heading must be able to say on its own: which box is silent. Takes the full
   width of the heading rather than sharing the baseline, so it cannot be skimmed past. */
.group-alarm {
  flex: 1 0 100%;
  display: flex;
  align-items: baseline;
  gap: var(--s-1);
  margin: var(--s-half) 0 0;
  padding: var(--s-1) var(--s-1);
  border-left: 3px solid var(--bad);
  border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
  background: var(--bad-soft);
  color: var(--bad-text);
  font-size: var(--fs-body);
}
.group-alarm strong { color: var(--bad); }
.group-alarm .mark { color: var(--bad); transform: translateY(0.1em); }
.has-down .group-count .figure { color: var(--bad); }

.group-body { display: grid; gap: var(--s-3); }

/* One environment. The rail on the left carries its state and is never spent on anything else. */
.env {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.env::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--line-2);
}
.env.s-over::before { background: var(--accent); }
.env.s-warn::before { background: var(--warn); }
.env.s-fault::before { background: var(--bad); width: 4px; }
/* Only a fault tints an environment header. Nothing else on the page does, which is what makes it
   carry. */
.env.s-fault > .env-head { background: var(--bad-soft); border-bottom-color: var(--bad-line); }

.env-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-2);
  padding: var(--s-2) var(--s-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.env-name {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.014em;
}
.s-fault .env-name { color: var(--bad); }
.env-facts { flex: 1 0 100%; }
.env-body { padding: var(--s-2) var(--s-3) var(--s-3); }

/* An environment that said nothing at all. The loudest thing the page can draw, and a different
   shape from a dead process card inside a healthy environment: "nothing is known about this
   environment" and "this box answered and one process is down" are different sentences with
   different next actions. */
.void { padding: var(--s-3); background: var(--bad-soft); }
.void-eyebrow {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--bad);
}
.void-lead {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-fig);
  line-height: var(--lh-snug);
  color: var(--bad-text);
  max-width: 80ch;
}
.void-lead strong { color: var(--bad); }
.void-reason { margin: 0; }

/* One process inside an environment — and NO LONGER A CARD.
 *
 * This tab used to be four nested boxes: panel, group, environment card, process card, and then a
 * table inside that. Five borders between the page edge and a value is depth nobody can hold, and
 * each one costs its own padding on both sides — on a laptop the innermost table had lost about a
 * fifth of the canvas to frames drawn around it.

 * So the process level is drawn with SPACING AND TYPE WEIGHT instead of a frame: a heavier rule
 * above it, the role at figure size, and the kind colour kept as a short tick on that rule rather
 * than as a border running the height of the block. Nothing is lost — the process is still
 * unambiguously a level, and a screen reader never saw the box in the first place, it saw the
 * `h4`.
 *
 * A process that did NOT answer keeps its frame, and that asymmetry is the point: it is the one
 * process-level thing on the page that has to stop the eye, and it can only do that if it is the
 * only one wearing a box. */
.proc {
  position: relative;
  margin-top: var(--s-3);
  padding-top: var(--s-2);
  border-top: 2px solid var(--line-2);
}
.proc:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* The kind, as a tick on the rule rather than a border down the side. */
.proc:not(:first-child)::before {
  content: "";
  position: absolute;
  top: -2px;
  left: 0;
  width: 2.5rem;
  height: 2px;
  background: var(--line-3);
}
.proc.k-api:not(:first-child)::before { background: var(--accent); }
.proc.proc-down {
  margin-top: var(--s-3);
  padding: var(--s-2);
  border: 1px solid var(--bad-line);
  border-left: 3px solid var(--bad);
  border-radius: var(--radius-sm);
  background: var(--bad-soft);
}
.proc.proc-down::before { display: none; }
.proc-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-half) var(--s-1);
  margin-bottom: var(--s-1);
}
.proc-role {
  font-family: var(--mono);
  font-size: var(--fs-fig);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.proc-shape {
  flex: 1 1 auto;
  margin: 0;
  font-size: var(--fs-sub);
  color: var(--muted);
}
.proc-head .chip { align-self: center; }
/* The process's own facts, on one quiet line under its name rather than in a tinted header band:
   a pid and a start time are provenance, not findings. */
.proc-head .facts {
  flex: 1 0 100%;
  grid-template-columns: repeat(auto-fit, minmax(9rem, max-content));
  gap: var(--s-half) var(--s-3);
  margin-top: var(--s-half);
}
.proc-body { padding: 0; }
.proc-body > h5:first-child { margin-top: var(--s-1); }

/* The only block on this page where a click changes a running system, so it does not wear the
   clothes of the read-only cards around it. Inset, on its own surface, and rail-marked in accent
   when it is actually armed to write. */
.live-zone {
  margin: var(--s-1) 0 var(--s-2);
  padding: var(--s-2);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--line-3);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.live-zone.is-armed {
  border-color: var(--accent-line);
  border-left-color: var(--accent);
  background: var(--accent-soft);
}
.live-zone-eyebrow {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.live-zone.is-armed .live-zone-eyebrow { color: var(--accent); }
.live-zone .notice { background: var(--surface); }

/* The deepest table on a card, and the only one nobody reads unless they are diffing two
   environments — a deliberate act, so a click is fair. */
details.deep {
  margin-top: var(--s-2);
  border-top: 1px solid var(--line);
  padding-top: var(--s-1);
}
details.deep > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-1);
  cursor: pointer;
  padding: var(--s-half) 0;
  border-radius: var(--radius-xs);
}
details.deep > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.deep-h {
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.deep-note { font-size: var(--fs-sub); color: var(--muted); }

/* ================================================================================================
   models — a drift table

   The reader's question is "do the environments disagree, and where". So the answer is stated once
   at the top as a stat row and a callout, then the slot bands carry it, then the rows carry it.
   Three chances to see the same fact, at three ranks.

   The callout used to be a `.verdict` block private to this tab, doing in different markup what
   the Performance tab's headline did in its own. Both are `.kpi` now; only this aside is local.
   =============================================================================================== */

/* The second and third faults, which the callout cannot hold: it carries one figure, and these
   are two more. A line rather than a box, because ranking them alongside the headline is exactly
   the mistake — a rewritten row is a real fault and an inactive one is a deployment choice. */
/* BLOCK, not flex — the same trap `.perf-scope-say` documents. As a flex container every inline
   child becomes its own flex item, so `<strong>rewritten</strong>` was torn off the word "mark"
   that follows it and the sentence broke mid-phrase. This is a sentence with a mark in front of
   it, so it is set as one. */
.kpi-aside {
  display: block;
  margin: var(--s-1) 0 var(--s-3);
  padding-left: var(--s-2);
  border-left: 2px solid var(--line-2);
  font-size: var(--fs-body);
  line-height: var(--lh-prose);
  color: var(--ink-2);
  max-width: 96ch;
}
.kpi-aside .mark { margin-right: var(--s-half); color: var(--accent); }
.kpi-aside strong { color: var(--ink); }

.t-drift tbody.slot { border-bottom: var(--s-1) solid transparent; }
/* One band per slot, so the group is a real row group to a screen reader and a visually separated
   band to everybody else — rather than a bold row that happens to sit above some others. */
.t-drift tr.slot-head > th {
  padding: var(--s-1);
  background: var(--surface-3);
  border-bottom: 1px solid var(--line-2);
  border-top: 1px solid var(--line-2);
}
/* Flex on the wrapper, never on the `th`. A table cell given `display: flex` leaves table flow and
   stops honouring `colspan`, so the band shrink-wrapped its own text instead of spanning the
   table — it read as a stray label rather than as the head of a row group. */
.slot-band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-1);
}
.t-drift tbody.slot-drift tr.slot-head > th {
  background: var(--bad-soft);
  border-color: var(--bad-line);
  box-shadow: inset 3px 0 0 var(--bad);
}
.slot-name {
  font-family: var(--mono);
  font-size: var(--fs-fig);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-transform: none;
}
.slot-count {
  margin-left: auto;
  font-size: var(--fs-sub);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
/* The one cell this tab is read for. Figure-sized, because comparing two model ids down a column is
   the entire job. */
.model-cell code {
  font-size: var(--fs-fig);
  font-weight: 650;
  letter-spacing: -0.01em;
}
/* "This box is not running what it was configured with." A within-environment fault, so it is
   accent and not red: the red palette on this tab means "the environments disagree", and spending
   it here would make two different problems with two different next actions look like one.

   Declared BEFORE the drift rules on purpose. A row can be both drifted and rewritten; when it is,
   drift's red rail overrides this one because cross-environment disagreement is the louder fault,
   and the rewritten fact stays visible on the value itself via its own chip. */
.t-drift tr.row-rewritten > *:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.t-drift tr.row-rewritten .model-cell code { color: var(--accent); }

/* Configured and deliberately not on the live path. No tint and no alarm colour: it is a
   deployment choice, and a page that draws it as a fault teaches people to ignore it. A neutral
   rail marks it as "reported, not live" without ranking it alongside the two real faults.
   `--nil` rather than `--line-3` because this rail carries meaning, and every mark on this page
   that carries meaning is held to 3:1 — `--line-3` is a border token and only reaches 2.1:1. */
.t-drift tr.row-inactive > *:first-child { box-shadow: inset 3px 0 0 var(--nil); }
/* The id is real but unused, so it steps back rather than competing with the rows that are live. */
.t-drift tr.row-inactive td code { color: var(--muted); }

.t-drift tr.row-drift { background: var(--bad-soft); }
.t-drift tr.row-drift > *:first-child { box-shadow: inset 3px 0 0 var(--bad); }
.t-drift tr.row-drift > * { color: var(--bad-text); }
/* Underlined as well as tinted: the value that disagrees is marked on the value itself, so the row
   does not have to be traced back to its chip. */
.t-drift tr.row-drift .model-cell code {
  color: var(--bad);
  text-decoration: underline;
  text-decoration-color: var(--bad-line);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

/* ================================================================================================
   trial metrics
   =============================================================================================== */

.plan-section {
  margin-bottom: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.plan-head {
  padding: var(--s-2) var(--s-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
/* The plan reference is the heading's own eyebrow, not a footnote: somebody holding the measurement
   plan open beside this page navigates by § number, not by our wording. */
.plan-ref {
  margin: 0 0 var(--s-half);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--accent);
}
.plan-title {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.014em;
}
.plan-owner {
  margin: var(--s-1) 0 0;
  font-size: var(--fs-sub);
  color: var(--muted);
}
.plan-owner strong { color: var(--ink-2); }
.plan-note { margin: var(--s-1) 0 0; }
.plan-section > .scroller,
.plan-section > .empty-block { margin: var(--s-1) var(--s-3) var(--s-2); }

.t-metrics .col-value { width: 14rem; }
.t-metrics tbody th { width: 26%; }

/* Metric row emphasis. `met` gets nothing — a page where every healthy row is tinted green has
   spent its colour before the first problem appears. */
.t-metrics tr.m-below > *:first-child { box-shadow: inset 3px 0 0 var(--bad); }
.t-metrics tr.m-below { background: var(--bad-soft); }
.t-metrics tr.m-below > * { color: var(--bad-text); }

/* NOT MEASURED, at row scale.
 *
 * A diagonal hatch — the only hatch on the page — on the neutral surface, with a dashed rail. It
 * reads as "nothing here" down a column of otherwise solid rows, and it is unmistakably not the
 * solid red of `.m-below`. No fill, no tint, no alarm: a row nobody has measured is not a row
 * anybody has failed. */
.t-metrics tr.m-unmeasured {
  background-image: repeating-linear-gradient(
    135deg,
    transparent 0 5px,
    var(--line-2) 5px 6px
  );
}
.t-metrics tr.m-unmeasured > *:first-child {
  box-shadow: inset 3px 0 0 var(--nil);
}
.t-metrics tr.m-unmeasured > * { color: var(--ink-2); }

/* -- not recorded ------------------------------------------------------------------------------
 * Deliberately as prominent as the measured sections above it, and deliberately not a footnote or
 * a `<details>`. A reader who does not notice this list will conclude the plan is fully
 * instrumented, and a metric nobody knows is absent is worse than one everybody knows is absent. */
.not-recorded {
  border-color: var(--line-3);
  border-left: 4px solid var(--label);
}
.not-recorded .plan-head { background: var(--surface-3); }
.not-recorded .plan-ref { color: var(--label); }
.t-notrec tbody th {
  white-space: nowrap;
  color: var(--ink);
}
.t-notrec td { font-size: var(--fs-body); }
.reason-cell { color: var(--ink-2); max-width: 60ch; }

/* -- the gate ---------------------------------------------------------------------------------- */

.gate {
  margin-bottom: var(--s-4);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}
.gate-head {
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--line);
}
.gate-ready .gate-head { background: var(--ok-soft); border-bottom-color: var(--ok-line); }
.gate-blocked .gate-head { background: var(--warn-soft); border-bottom-color: var(--warn-line); }
.gate-ref {
  margin: 0 0 var(--s-half);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
}
.gate-ready .gate-ref { color: var(--ok); }
.gate-blocked .gate-ref { color: var(--warn); }
.gate-title {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.014em;
}
.gate-ready .gate-title { color: var(--ok-text); }
.gate-blocked .gate-title { color: var(--warn-text); }
.gate-body {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--s-2) var(--s-4);
  padding: var(--s-3);
}
/* The one verdict number on the page, so it gets the top of the type scale and nothing else does. */
.gate-ratio {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin: 0;
  font-size: var(--fs-body);
  color: var(--muted);
}
.gate-ratio .mark {
  width: 0.85rem;
  height: 0.85rem;
  align-self: center;
}
.gate-ready .gate-ratio .mark { color: var(--ok); }
.gate-blocked .gate-ratio .mark { color: var(--warn); }
.gate-live,
.gate-required { font-size: var(--fs-hero); line-height: 1; color: var(--ink); }
.gate-blocked .gate-live { color: var(--warn); }
.gate-ready .gate-live { color: var(--ok); }
.gate-of { font-size: var(--fs-lead); }
.gate-unit { flex: 1 0 100%; }
.gate-missing h4 {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.blockers { display: grid; gap: var(--s-1); margin: 0; }
.blockers > div {
  padding-left: var(--s-1);
  border-left: 2px solid var(--warn-line);
}
.blockers dt { margin-bottom: 0.1rem; }
.blockers dd {
  margin: 0;
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  color: var(--ink-2);
}
.blockers dt .cell-sub { display: inline; margin-left: var(--s-1); }

/* Every gate check, satisfied ones included. A gate that lists only its blockers cannot be
   audited: "4 of 6" plus two named problems leaves the reader trusting that the other four were
   actually tested. Spanning both columns of `.gate-body` because it is the evidence for the ratio
   above it rather than a third fact beside it. */
.gate-checks { grid-column: 1 / -1; }
.gate-checks h4 {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.checks { display: grid; gap: var(--s-half); list-style: none; margin: 0; padding: 0; }
.checks > li {
  display: grid;
  grid-template-columns: 0.8rem minmax(10rem, 18rem) minmax(0, 1fr);
  align-items: baseline;
  gap: var(--s-1) var(--s-1);
  padding: var(--s-half) 0;
  border-bottom: 1px solid var(--line);
}
.checks > li:last-child { border-bottom: 0; }
.checks .mark { align-self: center; }
.checks > li.is-ready .mark { color: var(--ok); }
.checks > li.is-blocked .mark { color: var(--warn); }
.checks-k { font-size: var(--fs-body); font-weight: 650; color: var(--ink); }
.checks-v { font-size: var(--fs-body); line-height: var(--lh-snug); color: var(--ink-2); min-width: 0; }

/* -- two bars on one row -----------------------------------------------------------------------
 * §3 sets an aim AND a feasibility floor for two of the nine numbers, and records the
 * inconsistency on purpose: Sapienza is to confirm which one is in the protocol. So both are
 * rendered, labelled, and neither is picked. A single collapsed bar would be this page deciding a
 * question the contract explicitly left open, and whichever it picked half the readers would be
 * measuring against the other one. */
.bars { display: grid; gap: var(--s-half); list-style: none; margin: 0; padding: 0; }
.bars > li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-half) var(--s-1);
  padding-left: var(--s-1);
  border-left: 2px solid var(--line-2);
}
/* Upper case survives here and in `.series-k` only, and the reason is a constraint rather than a
   preference: both take their words from the backend — a threshold's own name, a week's own label
   — so this file cannot sentence-case them and CSS cannot either. Capitals are the one casing that
   is right whatever arrives. */
.bars-k {
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.bars-v { font-size: var(--fs-body); color: var(--ink); }

/* -- a distribution or a weekly series, in a detail row ----------------------------------------
 * The contract keeps the raw rows so a threshold can be re-checked later without a rebuild, and
 * these are what that buys the reader: a median of 11.2 minutes with six sessions under five is a
 * different system from one with none, and only the distribution says which this is.
 *
 * Same bar grammar as the Performance tab's histogram, so the two tabs do not teach two ways to
 * read a bar — but neutral fills throughout. A trial distribution is a description, not a verdict,
 * and tinting these bins by severity would be the dashboard inventing a judgement §3 did not ask
 * for. */
.detail-label {
  margin: var(--s-1) 0 var(--s-half);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.binbars { display: grid; gap: var(--s-half); list-style: none; margin: 0 0 var(--s-1); padding: 0; max-width: 46rem; }
.binbars > li {
  display: grid;
  grid-template-columns: minmax(6rem, 9rem) minmax(0, 1fr) 4rem;
  align-items: center;
  gap: var(--s-1);
}
.binbars-k { font-size: var(--fs-sub); color: var(--ink-2); white-space: nowrap; }
.binbars-v {
  font-size: var(--fs-code-sub);
  font-weight: 650;
  color: var(--ink);
  text-align: right;
}
.bar-thin { height: 0.6rem; }

.series { display: flex; flex-wrap: wrap; gap: var(--s-1); list-style: none; margin: 0 0 var(--s-1); padding: 0; }
.series-pt {
  display: flex;
  align-items: baseline;
  gap: var(--s-1);
  padding: var(--s-half) var(--s-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-xs);
  background: var(--surface-2);
}
/* A week with no value is dashed and unfilled, never interpolated and never a zero. Four points do
   not support a line, which is why this is a row of labelled figures rather than a sparkline. */
.series-pt.is-unmeasured { background: transparent; border-style: dashed; border-color: var(--nil); }
.series-k {
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}

/* -- export ------------------------------------------------------------------------------------ */

.export {
  padding: var(--s-3);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
}
.export-eyebrow {
  margin: 0 0 var(--s-half);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--accent);
}
.export-title {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0 0 var(--s-1);
  font-weight: 700;
  letter-spacing: -0.014em;
}
.export-facts { margin-bottom: var(--s-2); }
.export-form { margin: 0; }
.export-period {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 14rem));
  gap: var(--s-1) var(--s-2);
  margin: 0 0 var(--s-2);
  padding: var(--s-1) var(--s-2) var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.export-period legend {
  padding: 0 var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
/* Each action with its explanation beside it. Four bare buttons whose only explanation was the
   wording of a confirm() dialog is how somebody presses the wrong one. */
.export-actions {
  display: grid;
  gap: var(--s-1);
  list-style: none;
  margin: 0;
  padding: 0;
}
.export-actions > li {
  display: grid;
  grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr);
  align-items: center;
  gap: var(--s-1) var(--s-2);
  padding-bottom: var(--s-1);
  border-bottom: 1px solid var(--line);
}
.export-actions > li:last-child { border-bottom: 0; padding-bottom: 0; }
.export-actions button { width: 100%; }
.export-actions .help { margin: 0; }

/* A caveat that applies to some of the actions and not to others. It is indented under the buttons
   it constrains and carries a bracket up the left edge, so the scope is drawn rather than only
   asserted — placed above the whole list it would read as though it had disabled everything, which
   would stop somebody running the one action it does not affect. */
.export-actions > li.action-note {
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-half);
  margin-left: var(--s-2);
  padding-left: var(--s-2);
  border-left: 2px solid var(--warn-line);
  border-bottom: 0;
}
.scope-label {
  margin: 0;
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--warn-text);
}
.export-actions > li.action-note .notice { margin: 0; }
.export-latest { margin-bottom: var(--s-1); }

@media (max-width: 40rem) {
  .export-actions > li { grid-template-columns: minmax(0, 1fr); }
}

/* ================================================================================================
   performance — internal engineering telemetry

   A DIFFERENT KIND OF PAGE from the trial tab, and the chrome says so before a word is read. The
   trial tab is document-like: white cards, accent-blue § references, tables of stated values,
   built to be audited by somebody holding the contract open beside it. This is instrument-like:
   neutral mono eyebrows with no § to cite, a left rail in plain `--line-3` rather than accent, and
   bar geometry as the dominant element instead of a column of figures. Colour appears here in
   exactly one role — severity against a measured target — which is why the rest of the panel is
   deliberately grey.

   Nothing in here needs JavaScript. A bin chart that only renders once a script has run is a blank
   page at the exact moment somebody opens it to find out why AORI got slow.
   =============================================================================================== */

/* Block, NOT flex. As a flex container the trailing text node became its own flex item and the
   sentence broke after `<strong>not trial data</strong>`, leaving a full stop alone at the start
   of the next line. This is a sentence with a badge in front of it, so it is set as one. */
.perf-head .perf-scope-say {
  display: block;
  margin: var(--s-1) 0 0;
  padding: var(--s-1) var(--s-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--ink-2);
  font-size: var(--fs-body);
  line-height: var(--lh-prose);
  max-width: 88ch;
}
.perf-head .perf-scope-say strong { color: var(--ink); }
/* Stated at the top rather than footnoted, because somebody will be asked "can Sapienza have the
   performance numbers" while looking at this page and the answer has to be on it. */
.perf-badge {
  display: inline-block;
  margin-right: var(--s-1);
  padding: var(--inset-y) var(--inset-x);
  border-radius: var(--radius-xs);
  background: var(--label);
  color: var(--accent-ink);
  font-size: var(--fs-micro);
  font-weight: 700;
  text-transform: none;
  letter-spacing: var(--track-label);
}

/* -- environments asked ------------------------------------------------------------------------
 * Above every number, because it decides whether the numbers mean what they say. The sidecar is
 * asked once per environment and the ops box's Atlas credential is not guaranteed to reach all
 * three databases, so "spend fell 30%" and "production never answered" render identically without
 * this block. */
.perf-envs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  list-style: none;
  margin: 0 0 var(--s-3);
  padding: 0;
}
.perf-env {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-half) var(--s-1);
  min-width: 0;
  padding: var(--s-1) var(--s-1);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-3);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.perf-env.is-blocked { border-left-color: var(--warn); background: var(--warn-soft); }
.perf-env.is-live { border-left-color: var(--accent); }
.perf-env-name { font-weight: 650; font-size: var(--fs-body); }
.perf-env .cell-sub { display: inline; margin: 0; }
.perf-env-turns { display: inline-flex; align-items: baseline; }
/* The environment the headline figures came from. A filled accent badge, because this is the one
   fact on the card that changes what every number above it means: the percentiles are not merged
   across environments, so "p95 1163 ms" is one environment's p95 and nobody else's. 7.37:1. */
.perf-env-pick {
  padding: var(--inset-y) var(--inset-x);
  border-radius: var(--radius-xs);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--fs-micro);
  font-weight: 700;
  text-transform: none;
  letter-spacing: var(--track-label);
}
.perf-env.is-selected { border-left-color: var(--accent); border-left-width: 4px; }
/* The backend's sentence about this environment — today "read and had no traffic in the window".
   Its own line, because it is prose and the rest of the card is tokens. */
.perf-env-note { flex: 1 0 100%; margin-top: var(--s-half); }

/* A QUALIFICATION THAT CHANGES WHAT THE FIGURE MEANS, and therefore not a footnote.
 *
 * "4902 of 5127 turns priced; the mean is over the priced ones" is the difference between a cost
 * per turn and a cost per turn-we-happened-to-price, and the second is lower than anything
 * observed. So it gets a rail and full-strength body ink rather than the muted `.help` grey that
 * the eye is trained to skip. 10.31:1. */
.perf-honesty {
  margin: var(--s-1) 0 var(--s-1);
  padding-left: var(--s-1);
  border-left: 2px solid var(--warn);
  color: var(--ink-2);
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  max-width: 88ch;
}
/* "One mean and its band, not a distribution." Said out loud and kept quiet: by this point the
   page has taught the reader to expect four bars, and three absent bars would otherwise read as a
   rendering failure rather than as a source that does not bin. */
.perf-nodist {
  margin: var(--s-1) 0 var(--s-1);
  padding: var(--s-1) var(--s-1);
  border: 1px dashed var(--line-2);
  border-radius: var(--radius-sm);
  max-width: 88ch;
}
/* The scope caveat, beside the figure rather than under it. `llm only` next to a
   whole-conversation baseline is the difference between a comparison and a mistake. */
.perf-scope-chip { margin-left: var(--s-1); }

.perf-blocked { list-style: none; margin: var(--s-1) 0 0; padding: 0; display: grid; gap: var(--s-1); }
.perf-blocked > li {
  padding-left: var(--s-1);
  border-left: 2px solid var(--warn-line);
}
.perf-blocked-name { font-weight: 700; margin-right: var(--s-1); }
.perf-excluded .reason-prose { margin-top: var(--s-half); }

/* -- the card ----------------------------------------------------------------------------------
 * Neutral rail, not accent. The trial tab's export card uses an accent rail to mark the one
 * write-capable control on the page; nothing here writes anything, so claiming that colour would
 * be borrowing an emphasis this panel has not earned. */
.perf-card {
  margin-bottom: var(--s-4);
  border: 1px solid var(--line);
  border-left: 4px solid var(--line-3);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.perf-card-head {
  padding: var(--s-2) var(--s-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
/* Mono small caps in the label neutral — 7.06:1 on `--surface-2`. Deliberately NOT the trial tab's
   accent-blue `.plan-ref`: that colour means "this is a reference into the contract", and this
   page references no contract. */
.perf-eyebrow {
  margin: 0 0 var(--s-half);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.perf-card-title {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.014em;
}
.perf-card-head .prose { margin: var(--s-1) 0 0; }
/* What the number actually is. Mono-flavoured and always present, because the wrong field is
   conveniently available and somebody will find it again. */
.perf-source { color: var(--ink-2); }
.perf-source code { color: var(--ink); }
.perf-card-body { padding: var(--s-2) var(--s-3) var(--s-3); }
.perf-card-body > .scroller,
.perf-card-body > .empty-block { margin-bottom: var(--s-1); }
.perf-card-body > h5:first-child { margin-top: 0; }

/* -- the headline row --------------------------------------------------------------------------
 * The callout and the stat row that support it, side by side. Both are the shared primitives
 * below; only the two-column arrangement is this panel's. */

.perf-headline {
  display: grid;
  grid-template-columns: minmax(16rem, 22rem) minmax(0, 1fr);
  gap: var(--s-2) var(--s-4);
  align-items: start;
  margin-bottom: var(--s-2);
}
.perf-stats { align-self: center; }

/* -- the stacked strip --------------------------------------------------------------------------
 * The shape of a distribution in one line, above the table that carries its numbers. `aria-hidden`
 * and purely decorative.
 *
 * The bottom rule THICKENS with severity — 1px, 2px, 3px, 4px — and that is not ornament. It is the
 * only encoding in the strip that is not colour, and the strip is the one place on this panel where
 * a bin has no label and no chip beside it. A monotonic shape ramp keeps it readable in greyscale.
 * The rule and the separators are drawn in `--surface`, which by construction contrasts with every
 * fill in the ramp (3.88 : 1 at worst, on the lightest bin). */
.strip {
  display: flex;
  height: 1.4rem;
  margin: 0 0 var(--s-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  overflow: hidden;
  background: var(--bin-track);
}
.strip-seg { min-width: 2px; border-right: 1px solid var(--surface); }
.strip-seg:last-child { border-right: 0; }
.strip-seg.bin-good { background: var(--bin-good); box-shadow: inset 0 -1px 0 var(--surface); }
.strip-seg.bin-target { background: var(--bin-target); box-shadow: inset 0 -2px 0 var(--surface); }
.strip-seg.bin-over { background: var(--bin-over); box-shadow: inset 0 -3px 0 var(--surface); }
.strip-seg.bin-breach { background: var(--bin-breach); box-shadow: inset 0 -4px 0 var(--surface); }
.strip-seg.bin-none { background: var(--bar-neutral); }

/* -- the histogram ------------------------------------------------------------------------------
 * A table, because that is what a bar chart is: rows with a label and a number. The bar is an
 * `aria-hidden` layer in a cell whose neighbours already carry the count and the share, so a
 * screen reader reads the distribution rather than being told there is a picture of one. */
.hist { font-size: var(--fs-body); }
.hist thead th { border-bottom-color: var(--line-2); }
.hist tbody th { width: 11rem; white-space: nowrap; font-weight: 650; }
.hist tbody th .cell-sub { white-space: normal; }
/* The bar column takes whatever is left: the geometry is the point of the table, and a 6rem bar
   next to four wide text columns is a chart nobody can read. */
.hist .hist-bar-col { width: auto; min-width: 12rem; }
.hist-n { width: 6rem; text-align: right; }
.hist td.hist-n, .hist th.hist-n { text-align: right; }
.fig-cell { font-size: var(--fs-body); font-weight: 650; }
.figure .pre { font-size: 0.78em; font-weight: 600; margin-right: 0.04em; opacity: 0.85; }

.bar {
  display: block;
  height: 1.05rem;
  border-radius: 2px;
  background: var(--bin-track);
  box-shadow: inset 0 0 0 1px var(--line-2);
  overflow: hidden;
}
.bar-fill {
  display: block;
  height: 100%;
  /* So a 0.3% bin is still a visible mark rather than nothing. A share too small to draw is still
     not the same statement as a share of zero. */
  min-width: 3px;
  border-radius: 2px 0 0 2px;
  background: var(--bar-neutral);
}
/* A MEASURED ZERO. Not the hollow dashed mark — that means "we did not look". This is a flat
   baseline stub: we looked, and nothing landed in this bin, which on the breach row is the best
   news the page can carry. The count beside it is a solid `0`. */
.bar.is-zero .bar-fill { min-width: 0; }
.bar.is-zero { box-shadow: inset 0 0 0 1px var(--line-2), inset 3px 0 0 var(--nil); }

.bar-fill.bin-good { background: var(--bin-good); }
.bar-fill.bin-target { background: var(--bin-target); }
.bar-fill.bin-over { background: var(--bin-over); }
/* The only bar with a second wall. Contrast, hue, luminance rank, two inset rules, a tinted row
   and a solid chip all say the same thing, because this is the one bin the contract calls a defect
   rather than a measurement.

   TOP AND BOTTOM ONLY, not a ring. A full `inset 0 0 0 2px` ring ate the entire fill on the bin
   that matters most: a 0.5% breach share is 3px wide at 1280px (measured), and a 2px ring on every
   side of a 3px bar leaves no colour at all — the breach bin rendered blank, which is the one
   thing it must never do. Horizontal rules never clip a narrow bar. */
.bar-fill.bin-breach {
  background: var(--bin-breach);
  box-shadow: inset 0 2px 0 var(--surface), inset 0 -2px 0 var(--surface);
}

/* The row, echoing the trial tab's `.m-below` language so the two tabs agree about what a fault
   looks like. Only the breach row is tinted: a table where every healthy row is coloured has spent
   its colour before the first problem appears. */
.hist tr.bin-row-breach { background: var(--bad-soft); }
.hist tr.bin-row-breach > *:first-child { box-shadow: inset 3px 0 0 var(--bad); color: var(--bad-text); }
.hist tr.bin-row-breach > th { font-weight: 700; }
.hist tr.bin-row-over > *:first-child { box-shadow: inset 3px 0 0 var(--warn); }

/* Where a percentile falls, pinned on the bin that contains it. The backend names them, so the
   template does not have to decide which bin a p95 is in. */
.pins { display: inline-flex; gap: var(--s-half); margin-left: var(--s-1); vertical-align: 0.1em; }
.pin {
  padding: 0 0.3rem;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--ink-2);
  font-size: var(--fs-code-sub);
  font-weight: 700;
}

/* -- legs ------------------------------------------------------------------------------------- */

.perf-splits {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(26rem, 1fr));
  gap: var(--s-2);
}
.perf-split {
  min-width: 0;
  padding: var(--s-1) var(--s-2) var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.perf-split-title {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-fig);
  line-height: var(--lh-tight);
  font-weight: 700;
}
.perf-split-stats { margin-bottom: var(--s-1); }
.perf-split .strip { margin-bottom: var(--s-1); }
.perf-split .bar { background: var(--surface-3); }
/* A leg with no instrumentation. Dashed and unfilled — the same visual grammar as every other
   not-measured state on this dashboard — so it cannot be read as a leg that is fast. */
.perf-split-void {
  border: 1px dashed var(--nil);
  border-left: 1px dashed var(--nil);
  background: transparent;
  color: var(--ink-2);
}

/* -- unpriced calls ----------------------------------------------------------------------------
 * First on the cost card, ahead of every spend figure, because it governs whether any of them can
 * be believed: a model with no rate contributes $0.00 to every sum, so one unpriced call makes the
 * whole card an understatement — and it understates in the flattering direction. */
.perf-unpriced { margin-bottom: var(--s-2); }
/* `> strong` and not `strong`: the alarm's prose names $0.00 inline, and a descendant selector
   turned that into its own line mid-sentence. Only the headline strong is a flex row, because it
   is the one carrying the mark beside the count. */
.perf-unpriced.is-alarm > strong { display: flex; align-items: center; gap: var(--s-1); }
.perf-unpriced.is-unknown > strong { display: flex; align-items: center; gap: var(--s-1); }
.perf-unpriced.is-alarm .fig-hero { color: var(--bad); }
/* Zero unpriced calls is a measured zero and a good one, so it is a quiet line of prose rather
   than a green banner: a page that celebrates every healthy state has no attention left for the
   one that is not. */
.perf-unpriced.is-clear {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-1);
  margin: 0 0 var(--s-2);
  padding: var(--s-1) var(--s-1);
  border-left: 3px solid var(--ok-line);
  color: var(--ok-text);
  font-size: var(--fs-body);
}
.perf-unpriced.is-clear .mark { color: var(--ok); align-self: center; }
.perf-unpriced.is-clear .figure { color: var(--ok); }
.perf-unpriced-say { flex: 1 1 24rem; min-width: 0; }

/* -- cache hit rate against its measured band --------------------------------------------------
 * The one place a single number beats a distribution: "68%" means nothing until you know the band,
 * and the band — 61 to 77 per cent — is one of the numbers the deleted metric definitions carried.
 *
 * The band is drawn as a 2px bracket rather than a pale fill. A fill in `--accent-line` measured
 * 1.36:1 against the track, which is invisible; the bracket's edges are `--accent` at 6.28:1, and
 * the edges are the meaning-bearing part — where the band starts and stops. */
.perf-cache { max-width: 72rem; }
.rail {
  position: relative;
  height: 1.25rem;
  margin: var(--s-1) 0 var(--s-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  background: var(--bin-track);
}
.rail-band {
  position: absolute;
  top: -1px;
  bottom: -1px;
  border: 2px solid var(--accent);
  border-radius: 2px;
  background: var(--accent-soft);
}
.rail-mark {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 3px;
  margin-left: -1.5px;
  border-radius: 1px;
  background: var(--ink);
}
.perf-rail-key { margin-top: var(--s-half); }

/* -- the trend, as small multiples -------------------------------------------------------------
 * An ordered list, one item per period, each carrying its own figures as visible text under the
 * plot. So the markup reads "week of 8 Sep: p95 1140 ms, p50 690 ms, $0.0061 per turn" in order,
 * and the bars above are decoration over numbers that are already there.
 *
 * The case this chart exists to get right is a period with no data. A zero-height bar is
 * indistinguishable from a very fast week, so an unmeasured period is drawn as a FULL-HEIGHT
 * hatched column — the same hatch the trial tab uses for an unmeasured row, in `--nil` at 3.57:1
 * rather than `--line-2`, which measured 1.54:1 and was therefore not a mark at all. */
.trend {
  display: flex;
  gap: var(--s-1);
  align-items: stretch;
  list-style: none;
  margin: 0 0 var(--s-1);
  padding: 0 0 var(--s-1);
}
.trend-col {
  /* 8rem, not 7: the "not measured" pill is `nowrap` by design and measured 94px, which overflowed
     a 7rem column's 96px of inner width by the time it had its border. The column is sized to the
     widest thing it must hold, and that thing is an absent value rather than a number. */
  flex: 1 1 8rem;
  min-width: 8rem;
  display: flex;
  flex-direction: column;
  padding: var(--s-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.trend-col.is-unmeasured { background: transparent; border-style: dashed; border-color: var(--nil); }
.trend-plot {
  position: relative;
  height: 7rem;
  margin-bottom: var(--s-1);
  border-bottom: 2px solid var(--line-2);
  background: var(--surface-2);
}
.trend-col.is-unmeasured .trend-plot { background: transparent; }
.trend-bar {
  position: absolute;
  left: 15%;
  right: 15%;
  bottom: 0;
  min-height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--bin-target);
}
/* No second wall here, unlike the histogram's breach fill. The signal a trend column already
   carries is geometric and better: the bar visibly crosses the dashed ceiling rule, which is
   readable with every colour removed and cannot be swallowed by a short bar the way an inset ring
   can. The red `BREACHES` count under the column says it in words. */
.trend-bar.is-breach { background: var(--bin-breach); }
/* p50 inside the p95 bar: the median and the tail in one column, which is the comparison that says
   whether the whole distribution moved or only its tail grew.

   It protrudes 4px past both edges of the bar on purpose. Drawn flush and full-width in
   `--surface` it read as a GAP dividing the column into two stacked bars rather than as a marker
   across one; overhanging both sides makes it unambiguously a crossbar laid over the bar. */
.trend-p50 {
  position: absolute;
  left: -4px;
  right: -4px;
  height: 3px;
  border-radius: 1px;
  background: var(--surface);
  box-shadow: 0 0 0 1px var(--ink-2);
}
/* The ceiling drawn where it falls on the scale, not where the tallest column puts it. This is what
   turns a column chart into a verdict. */
.trend-ceiling {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  border-top: 2px dashed var(--bad);
}
.trend-hatch {
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(135deg, transparent 0 5px, var(--nil) 5px 6px);
}
.trend-cost {
  height: 0.55rem;
  margin-bottom: var(--s-1);
  border: 1px solid var(--line-2);
  border-radius: 2px;
  background: var(--bin-track);
  overflow: hidden;
}
.trend-cost-bar { display: block; height: 100%; min-width: 2px; background: var(--label); }
/* Cost not measured for this period: a dashed rail, never an empty solid one that reads as $0. */
.trend-cost-none {
  display: block;
  height: 100%;
  background-image: repeating-linear-gradient(135deg, transparent 0 4px, var(--nil) 4px 5px);
}
.trend-label {
  margin: 0 0 var(--s-half);
  font-size: var(--fs-sub);
  font-weight: 700;
  color: var(--ink);
  line-height: var(--lh-snug);
}
.trend-facts { display: grid; gap: 0.1rem; margin: 0; }
/* `wrap` because a "not measured" pill cannot shrink: it is nowrap by design, and beside its own
   label in a 7rem column the pair overflowed into the next column. Given its own line it stays
   legible, and the measured case — a short figure — still sits on one line beside its label. */
.trend-facts > div {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0 var(--s-1);
  min-width: 0;
}
.trend-facts dt {
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
.trend-facts dd { margin: 0; font-size: var(--fs-sub); color: var(--ink-2); }
.trend-facts .fig-cell { font-size: var(--fs-body); }
.trend-facts .unmeasured-cell { font-size: var(--fs-micro); padding: 0 0.3rem; letter-spacing: 0; }
.trend-facts .trend-breaches dt { color: var(--bad); }
.trend-facts .trend-breaches .fig-cell { color: var(--bad); }

/* -- breakdowns -------------------------------------------------------------------------------- */

.t-breakdown tbody th { width: 18rem; }
.t-breakdown tbody th .cell-sub { white-space: normal; }
/* NOT READABLE collapses to its sentence instead of showing six "not measured" cells: six of those
   says "we looked and found nothing", and the truth is "we could not look". */
.bd-row.bd-blocked { background: var(--warn-soft); }
.bd-row.bd-blocked > *:first-child { box-shadow: inset 3px 0 0 var(--warn); }
.bd-row.bd-blocked > * { color: var(--warn-text); }
.bd-reason { max-width: 60ch; }
/* NO TRAFFIC: read, and nothing happened. A real measured zero, so no tint and no rail — just the
   flat-bar mark and the words in the state column. */
.bd-row.bd-idle > * { color: var(--muted); }
/* NOT MEASURED: the hatch, at row scale, exactly as the trial tab draws it. */
.bd-row.bd-unmeasured {
  background-image: repeating-linear-gradient(135deg, transparent 0 5px, var(--line-2) 5px 6px);
}
.bd-row.bd-unmeasured > *:first-child { box-shadow: inset 3px 0 0 var(--nil); }

/* Nothing on this panel was drawn at all. Dashed rather than red: a tab with no telemetry is not a
   tab reporting a fault. */
.perf-void { border-left-width: 4px; }

/* A histogram inside a leg card is the same table in half the width, so the text columns give up
   what they can and the bar column keeps the rest. Measured at 1280px: without this the leg's
   `.scroller` clipped at 548px against 634px of table, which hid the verdict chip — the column
   that carries the shape and the word. */
.perf-split .hist tbody th { width: 8rem; }
.perf-split .hist-n { width: 4.25rem; }
.perf-split .hist .hist-bar-col { min-width: 7rem; }

/* 1280px is the narrow end of the target range. Two things stop earning their width before the
   bars do, and the bars never collapse because they are the content.

   The leg grid gives up at 96rem rather than 72rem, which is measured rather than guessed: two
   legs side by side at 1280px leave each histogram 548px against the 634px it needs even after
   the compaction above, and a clipped verdict column is worse than a stacked pair. At 2560px both
   legs sit side by side, which is the comparison they exist for. */
@media (max-width: 72rem) {
  .perf-headline { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 96rem) {
  .perf-splits { grid-template-columns: minmax(0, 1fr); }
}

/* ================================================================================================
   forms
   =============================================================================================== */

.field { display: grid; gap: var(--s-half); min-width: 0; }
.field label {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--label);
}
input,
select {
  width: 100%;
  padding: var(--s-1);
  font: 600 var(--fs-body) var(--mono);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  font-variant-numeric: tabular-nums;
}
input:focus-visible,
select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.help {
  margin: var(--s-half) 0 0;
  font-size: var(--fs-sub);
  line-height: var(--lh-snug);
  color: var(--muted);
  max-width: 76ch;
}
.help strong { color: var(--ink-2); }
.help-deployed { display: block; }
.help-deployed code { font-size: var(--fs-code-sub); color: var(--ink-2); }

button {
  padding: var(--s-1) var(--s-2);
  font: 650 var(--fs-body) var(--sans);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  cursor: pointer;
}
button:hover:not(:disabled) { background: var(--surface-3); border-color: var(--line-3); }
button:disabled { opacity: 0.55; cursor: not-allowed; }
button.primary {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}
button.primary:hover:not(:disabled) { filter: brightness(1.08); background: var(--accent); }
button.ghost { background: transparent; font-size: var(--fs-sub); }

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  align-items: center;
  margin: var(--s-1) 0 0;
}

.tuning {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--s-2);
  margin: var(--s-1) 0 0;
}
.tuning-field {
  padding: var(--s-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.tuning-field.is-over { border-color: var(--accent-line); box-shadow: inset 3px 0 0 var(--accent); }
.tuning .actions { grid-column: 1 / -1; }

/* ================================================================================================
   sign-in
   =============================================================================================== */

.signin {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(22rem, 26rem);
  gap: var(--s-5);
  align-items: start;
  margin-top: var(--s-4);
}
.signin-say { max-width: 62ch; }
.signin-eyebrow {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-micro);
  text-transform: none;
  letter-spacing: var(--track-label);
  font-weight: 700;
  color: var(--accent);
}
.signin-say h2 {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  margin: 0;
  font-weight: 650;
  letter-spacing: -0.018em;
}
.signin-panel {
  padding: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-2);
}
/* SSO is how people sign in. The password is how you get in when SSO itself is broken, so the two
   are not presented as equal options: the primary route owns the panel, and the break-glass route
   is a disclosed `<details>` below a rule. */
.signin-primary h3 {
  font-size: var(--fs-fig);
  line-height: var(--lh-tight);
  margin: 0 0 var(--s-1);
  font-weight: 700;
}
.signin-primary button { width: 100%; padding: var(--s-1) var(--s-2); font-size: var(--fs-lead); }
.breakglass {
  margin-top: var(--s-3);
  padding-top: var(--s-2);
  border-top: 1px solid var(--line);
}
.breakglass > summary {
  cursor: pointer;
  font-size: var(--fs-sub);
  font-weight: 650;
  color: var(--muted);
  border-radius: var(--radius-xs);
}
.breakglass > summary:hover { color: var(--ink-2); }
.breakglass[open] > summary { color: var(--ink-2); margin-bottom: var(--s-1); }
.breakglass form { margin: var(--s-1) 0 0; }
.breakglass button { width: 100%; }

@media (max-width: 64rem) {
  .signin { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }

  /* Below this width a 15rem rail is a quarter of the viewport spent on four words. It becomes a
     horizontal strip at the top of the page: the same links, the same script, no longer sticky —
     a fixed rail and a fixed strip together would leave a phone about nothing to read with. */
  .app { grid-template-columns: minmax(0, 1fr); }
  .sidenav {
    position: static;
    height: auto;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-1);
    padding: var(--s-1) var(--s-2);
    border-right: 0;
    border-bottom: 1px solid var(--line-2);
  }
  .sidenav-brand { padding: 0; }
  .tabs { flex-direction: row; flex-wrap: wrap; padding: 0; overflow: visible; }
  .tab { border-left: 0; border-bottom: 2px solid transparent; }
  .tab[aria-selected="true"] { border-left: 0; border-bottom-color: var(--accent); }
  .tab-label { flex: 0 1 auto; }
  /* The page metadata is the first thing to go: it is provenance for numbers that are now below
     the fold anyway, and it is still in the page source. */
  .sidenav-foot { margin: 0 0 0 auto; padding: 0; border-top: 0; }
  .sidenav-note { display: none; }
  .topbar-stamp { display: none; }
}

/* ================================================================================================
   print — a trial report gets printed and pasted into an email more often than anyone admits
   =============================================================================================== */

@media print {
  header.chrome,
  .sidenav,
  .tabs,
  .export-form,
  form.inline { display: none !important; }
  /* Tabs hide panels with the `hidden` attribute; on paper every section should be there. */
  .panel[hidden] { display: block !important; }
  main { max-width: none; padding: 0; }
  .env,
  .plan-section,
  .perf-card,
  .gate { break-inside: avoid; box-shadow: none; }
  /* The bars are `background` and browsers drop backgrounds when printing, so a printed histogram
     would be four empty tracks. The count and share columns are text and survive; the hatch that
     means "not measured" is a background too, which is why every unmeasured state on this panel
     also carries the words. */
  .bar, .strip, .rail, .trend-cost { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  details.deep,
  .breakglass { display: block; }
  details.deep > *:not(summary) { display: revert !important; }
}
