/* ==========================================================================
   surfaces.css — the nine operator screens

   Operations · Approvals · Library · Scheduled · Customize
   Activity · Data & corpus · Audit · Governance

   Everything here lives in the `surfaces` layer, declared in tokens.css as
   `@layer reset, tokens, base, layout, components, chat, surfaces, utilities;`.
   Two consequences run through the whole file:

     · A layer outranks specificity. Anything written here beats components.css
       and app.css/shell.css no matter how specific those selectors are — which
       is how the drawer and the table paddings below are re-pointed — and is
       equally why any spacing rule those files own has to be *restated* here
       the moment a rule in this layer matches the same element.
     · `utilities` comes after this layer, so `.truncate`, `.mono`, `.icon` and
       the `.t-*` sizes cannot be overridden from here. Where a utility needs
       help (an inline `.truncate` that cannot clip because inline boxes ignore
       `overflow`) the fix is a property the utility does not set.

   Colour carries meaning and nothing else: amber is the model call, green is
   a pass, red is a block or a lapse, teal is the workspace's own accent. No
   purple exists in the token set and none is introduced here. Every figure in
   every table, meter, rate and stamp is tabular.
   ========================================================================== */

@layer surfaces {

  /* ══════════════════════════════════════════════════════════════════════
     1 · Surface scaffolding
     ══════════════════════════════════════════════════════════════════════ */

  /* base.html renders <main class="surface"> and each template's root element
     carries `.surface` a second time. The outer one is the scroll container
     and owns the page gutters; the inner one must repeat neither — a second
     scroller here would clip the run-trace drawer and double the padding. */
  .surface .surface {
    padding: 0;
    overflow: visible;
  }

  /* `[data-surface]` is on the nine template roots and on `.shell`, never on
     the <main> wrapper and never on the chat's own root — so it is the exact
     handle for "inside one of these nine pages". */
  .surface[data-surface] {
    min-inline-size: 0;
  }

  .surface[data-surface] > * + *,
  .surface__body > * + * {
    margin-block-start: var(--space-5);
  }

  /* app.css owns `.section + .section`; restated because the rule above is in
     a later layer and would otherwise flatten it. */
  .surface[data-surface] > .section + .section,
  .surface__body > .section + .section {
    margin-block-start: var(--space-8);
  }

  /* A rule under the title: these are reference screens, and the header is a
     masthead rather than a floating heading. */
  .surface[data-surface] > .page-header {
    padding-block-end: var(--space-5);
    border-block-end: 1px solid var(--border-subtle);
  }

  .surface__body {
    min-inline-size: 0;
  }

  /* `--stack` states the body is one column of sections; `--split` is the only
     one of the two that changes layout. */
  .surface--stack {
    display: block;
  }

  .surface--split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 21rem);
    gap: var(--space-6);
    align-items: start;
  }

  /* The gap is the spacing between the two columns; the flow rhythm above
     would otherwise push the rail a row's worth down its own column. */
  .surface--split > * + * {
    margin-block-start: 0;
  }

  .surface__main,
  .surface__rail {
    min-inline-size: 0;
  }

  /* Anchors: /governance#policy-12, /library#upload, /approvals#approval-3. */
  .section[id],
  .policy-group[id],
  .approval-card[id],
  .monitor-card[id],
  .policy-card[id],
  .overseer-card[id] {
    scroll-margin-block-start: var(--space-6);
  }

  /* The nine surfaces share one kit and differ in exactly one thing: how wide
     the reading measure runs. A table-first surface is scanned, so its prose
     may run long beside a full-width log; a card-first surface is read, and
     keeps the standard measure. Set as a property so the components below can
     consume it without a specificity contest. */
  .surface--operations,
  .surface--activity,
  .surface--audit,
  .surface--data,
  .surface--library {
    /* One step wider than the standard measure, stated AS a step so the one
       place that knows what a `ch` is really worth stays tokens.css: 74ch was
       written when a ch was believed to be a character and set lines of ~89.
       `+ 8ch` is ~10 rendered characters of extra run for a surface that is
       scanned beside a full-width table. */
    --surface-measure: calc(var(--measure) + 8ch);
  }

  .surface--approvals,
  .surface--scheduled,
  .surface--customize,
  .surface--governance {
    --surface-measure: var(--measure);
  }

  /* ══════════════════════════════════════════════════════════════════════
     2 · Page header · sections
     ══════════════════════════════════════════════════════════════════════ */

  /* app.css owns `.page-header`, `__text`, `__title` and `__actions`; the lede
     is this file's, and reads at the muted weight of a standfirst. */
  .page-header__lede {
    margin-block-start: var(--space-1);
    max-inline-size: var(--surface-measure, var(--measure));
    color: var(--fg-muted);
    font-size: var(--text-base);
    line-height: var(--lh-base);
    text-wrap: pretty;
  }

  .section {
    min-inline-size: 0;
  }

  .section > * + * {
    margin-block-start: var(--space-4);
  }

  .section__heading {
    display: grid;
    gap: var(--space-1);
    min-inline-size: 0;
  }

  .section__meta {
    max-inline-size: var(--surface-measure, var(--measure));
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  .section__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 0 0 auto;
  }

  .section__body {
    min-inline-size: 0;
  }

  /* "Saved 4 minutes ago" — a timestamp, not a control, so it sits with the
     header's baseline rather than in the action group. */
  .section__stamp {
    flex: 0 0 auto;
    color: var(--fg-faint);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .section__footnote {
    max-inline-size: var(--surface-measure, var(--measure));
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  .section--stats > .stat-row {
    margin-block-start: 0;
  }

  .section--rail {
    min-inline-size: 0;
  }

  .section--rail .section__header {
    align-items: center;
    margin-block-end: var(--space-2);
  }

  .section--rail .section__title {
    font-size: var(--text-base);
    line-height: var(--lh-base);
  }

  /* The overseers preamble is deliberately long — it is the one place the
     product explains why a silent pass is still written down. Longer than the
     surface it sits on, and derived from it, so "longer" survives a retune of
     the measure itself. */
  .section--overseers .section__meta {
    max-inline-size: calc(var(--surface-measure, var(--measure)) + 8ch);
  }

  .stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    gap: var(--space-3);
  }

  .stat-row--tight {
    gap: var(--space-2);
  }

  /* ══════════════════════════════════════════════════════════════════════
     3 · Grids · cards
     ══════════════════════════════════════════════════════════════════════ */

  .grid {
    display: grid;
    gap: var(--space-4);
    min-inline-size: 0;
  }

  /* A grid item's margins are not collapsed and are not wanted: the gap is the
     spacing. This has to undo app.css's `.section + .section` for the two
     sections that sit side by side on the data surface. */
  .grid > * + * {
    margin-block-start: 0;
  }

  .grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
  }

  /* `min(100%, …)` is the guard that stops a track outgrowing the column at
     390px, where the track minimum would otherwise force a body scrollbar. */
  .grid--cards {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  }

  .grid__empty {
    grid-column: 1 / -1;
  }

  .card__subtitle {
    margin-block-start: var(--space-1);
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  /* The stable identifier under a human name: `scope_warden`, `sla.breach`. */
  .card__key {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    overflow-wrap: anywhere;
  }

  .card__footnote {
    margin-block-start: var(--space-3);
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  .card__footer--actions {
    justify-content: flex-end;
    flex-wrap: wrap;
  }

  .card--chart {
    padding: var(--space-4);
  }

  /* ══════════════════════════════════════════════════════════════════════
     4 · Charts
     ══════════════════════════════════════════════════════════════════════ */

  .chart-frame {
    display: grid;
    gap: var(--space-3);
    min-inline-size: 0;
  }

  .chart {
    position: relative;
    min-inline-size: 0;
    block-size: clamp(11rem, 30vh, 19rem);
  }

  .chart > svg,
  .chart > canvas {
    inline-size: 100%;
    block-size: 100%;
  }

  .chart-frame__caption {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-4);
    padding-block-start: var(--space-2);
    border-block-start: 1px solid var(--border-subtle);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
  }

  .chart-frame__as-of {
    min-inline-size: 0;
    font-variant-numeric: tabular-nums;
  }

  /* ══════════════════════════════════════════════════════════════════════
     5 · Tables

     The page body never scrolls sideways (app.css sets `overflow-x: hidden`
     on <body>), so a table wider than its column has to scroll inside
     `.table-scroll`. Sticky column headers resolve against the nearest
     scrollport, which means the wrapper has to be bounded in both axes for
     them to do anything — hence the max-block-size.
     ══════════════════════════════════════════════════════════════════════ */

  .table-scroll {
    max-inline-size: 100%;
    max-block-size: min(38rem, calc(100dvh - 13rem));
    overflow: auto;
    overscroll-behavior: contain;
    background-color: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-card);
  }

  /* Cell padding as a property so `--dense` and `--compact` can be combined:
     both rules match the same element at the same specificity, and the later
     declaration — compact, the tighter of the two — wins. */
  .table {
    --table-cell-py: var(--space-3);
    --table-cell-px: var(--space-3);
  }

  .table--dense {
    --table-cell-py: var(--space-2);
  }

  .table--compact {
    --table-cell-py: var(--space-1);
    --table-cell-px: var(--space-2);
  }

  .table tbody td,
  .table tbody th {
    padding: var(--table-cell-py) var(--table-cell-px);
  }

  .table thead th {
    padding-inline: var(--table-cell-px);
  }

  /* components.css styles tbody cells as <td>. Every table on these surfaces
     names its identifying column with <th scope="row">, which needs the same
     box and the primary ink. */
  .table tbody th {
    border-block-end: 1px solid var(--border-subtle);
    color: var(--fg-primary);
    font-weight: var(--weight-medium);
    vertical-align: top;
  }

  .table tbody tr:last-child th {
    border-block-end: 0;
  }

  .table__cell--primary {
    min-inline-size: 11rem;
    max-inline-size: 34rem;
  }

  /* `.truncate` clips a block box; a bare inline element ignores `overflow`
     entirely, so cell text that must ellipsis is blockified here. The utility
     layer sets everything else and cannot be reached from this one. */
  .table td > .truncate,
  .table th > .truncate {
    display: block;
  }

  .table__sub {
    display: block;
    margin-block-start: var(--space-05);
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-weight: var(--weight-regular);
  }

  .table__unit {
    color: var(--fg-muted);
    font-size: var(--text-xs);
  }

  .table__cell--action {
    inline-size: 1%;
    text-align: end;
    white-space: nowrap;
  }

  .table__cell--flag {
    text-align: center;
  }

  .table__cell--meter {
    min-inline-size: 7rem;
  }

  /* The metric catalogue's fallback order: one chip per relation, wrapping
     inside its own cell rather than clipping. It held Python dict reprs and
     `truncate`, so every row ended in an ellipsis and no reader ever saw a
     relation name. */
  .table__cell--sources {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
    max-inline-size: 22rem;
  }

  /* A table link is a title, not a call to action: the underline waits for
     the pointer so a dense column stays a column. */
  .table .link {
    text-decoration-color: transparent;
  }

  .table .link:hover,
  .table .link:focus-visible {
    text-decoration-color: currentColor;
  }

  /* These four carry `.table tbody …` because that is the shape of the rules
     they have to beat — components.css sets the cell box and the row hover at
     that depth, and specificity is only settled inside a layer once both sides
     of the comparison live in one. */
  .table tbody .table__row--empty td {
    padding: 0;
    border-block-end: 0;
  }

  .table tbody .table__row--empty:hover,
  .table tbody .table__daybreak:hover {
    background-color: transparent;
  }

  /* The audit log is read down a day at a time; the daybreak is a rowgroup
     heading, not a record. */
  .table tbody .table__daybreak th {
    padding: var(--space-4) var(--table-cell-px) var(--space-1);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    border-block-end: 1px solid var(--border-default);
  }

  .table tbody .table__daybreak:first-child th {
    padding-block-start: var(--space-2);
  }

  /* Column floors for the two widest logs, so they scroll rather than crush.
     Everything else is held open by its own nowrap header row. */
  .table--runs {
    min-inline-size: 62rem;
  }

  .table--audit {
    min-inline-size: 58rem;
  }

  /* ══════════════════════════════════════════════════════════════════════
     6 · Toolbars · filters · form furniture
     ══════════════════════════════════════════════════════════════════════ */

  .toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    padding: var(--space-3);
    background-color: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-card);
  }

  .toolbar--filters {
    align-items: center;
  }

  .toolbar__spacer {
    flex: 1 1 var(--space-4);
    min-inline-size: 0;
  }

  .toolbar__note {
    flex: 1 1 20rem;
    min-inline-size: 0;
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    text-wrap: pretty;
  }

  /* Every flex hint a toolbar control needs is written at toolbar depth, so a
     `.field--*` modifier at class depth can never lose the specificity race to
     the generic `.toolbar .field` below it. */
  .toolbar .field,
  .toolbar .filter {
    flex: 0 1 11rem;
  }

  .toolbar .field--search {
    flex: 1 1 17rem;
  }

  .toolbar .field--grow {
    flex: 1 1 22rem;
  }

  .toolbar .field--block {
    flex: 1 1 100%;
  }

  /* The corpus search bar is one line of intent: the query takes what is left
     after the index picker and the button. */
  .toolbar--search .field--search {
    flex: 1 1 22rem;
  }

  .toolbar .btn {
    flex: 0 0 auto;
  }

  /* Not used by the nine templates today; declared so a filter added to a
     toolbar later inherits the same box as `.field`. */
  .filter {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-inline-size: 0;
  }

  .field--search {
    position: relative;
    min-inline-size: 0;
  }

  .field--grow {
    min-inline-size: 0;
  }

  .field--block {
    inline-size: 100%;
  }

  .field--file,
  .field--toggle {
    min-inline-size: 0;
  }

  /* An <input> cannot carry a pseudo-element, so the search glyph hangs off
     the label. The mask themes for free; a baked-in SVG would not. */
  .field--search::before {
    content: "";
    position: absolute;
    inset-inline-start: var(--space-3);
    inset-block-start: 50%;
    translate: 0 -50%;
    inline-size: var(--icon-sm);
    block-size: var(--icon-sm);
    background-color: var(--fg-faint);
    mask-image: var(--mask-search);
    mask-size: 100% 100%;
    -webkit-mask-image: var(--mask-search);
    -webkit-mask-size: 100% 100%;
    pointer-events: none;
  }

  .input--search {
    padding-inline-start: var(--space-8);
  }

  .field__required {
    color: var(--danger-text);
    font-size: var(--text-xs);
    font-weight: var(--weight-regular);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
  }

  .input--file {
    display: flex;
    align-items: center;
    block-size: auto;
    min-block-size: var(--control-h-md);
    padding: var(--space-1) var(--space-2);
    cursor: pointer;
  }

  .input--file::file-selector-button {
    margin-inline-end: var(--space-3);
    padding: var(--space-1) var(--space-3);
    background-color: var(--bg-sunken);
    color: var(--fg-secondary);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-control);
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
  }

  .input--file::file-selector-button:hover {
    background-color: var(--bg-hover);
    color: var(--fg-primary);
  }

  .textarea--tall {
    min-block-size: 11rem;
    line-height: var(--lh-md);
  }

  /* A form that is one control in a row of controls — a Pause button in a
     card footer, a Forget button in a table cell. */
  .inline-form {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  /* ══════════════════════════════════════════════════════════════════════
     7 · Approvals
     ══════════════════════════════════════════════════════════════════════ */

  .approval-list {
    display: grid;
    gap: var(--space-4);
  }

  .approval-list__empty {
    padding: 0;
  }

  .approval-card__header {
    align-items: flex-start;
  }

  .approval-card__identity {
    min-inline-size: 0;
  }

  .approval-card__state {
    flex: 0 0 auto;
  }

  .approval-card__body {
    display: grid;
    gap: var(--space-4);
  }

  .approval-card__requester {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
  }

  /* Who asked, under which policy, for which run, and until when — the four
     facts a decision is made on. Ruled off from what is being asked for. */
  .approval-card__facts {
    padding-block-end: var(--space-3);
    border-block-end: 1px solid var(--border-subtle);
  }

  .approval-card__payload {
    min-inline-size: 0;
  }

  /* Settled requests stay in the queue as a record. They read back a step so
     the pending ones keep the eye. */
  .approval-card.is-decided {
    background-color: var(--bg-sunken);
  }

  .approval-card.is-decided .card__title {
    color: var(--fg-secondary);
  }

  .decision {
    display: grid;
    gap: var(--space-3);
    padding: var(--space-4);
    background-color: var(--bg-sunken);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-control);
  }

  .approval-card.is-decided .decision {
    background-color: var(--bg-surface);
  }

  .decision__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .decision--settled {
    gap: var(--space-2);
  }

  .decision__verdict {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    font-variant-numeric: tabular-nums;
  }

  .decision__by {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
    color: var(--fg-primary);
    font-weight: var(--weight-medium);
  }

  /* The note is the whole point of the record — it is quoted, not paraphrased. */
  .decision__note {
    padding-inline-start: var(--space-3);
    border-inline-start: 2px solid var(--border-strong);
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  /* ══════════════════════════════════════════════════════════════════════
     8 · Scheduled — monitors and digests
     ══════════════════════════════════════════════════════════════════════ */

  .monitor-card__header {
    align-items: flex-start;
  }

  .monitor-card__identity {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  .monitor-card__flags,
  .policy-card__flags,
  .overseer-card__flags {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-1);
    flex: 0 0 auto;
  }

  .monitor-card__body {
    display: grid;
    gap: var(--space-3);
  }

  .monitor-card__question {
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  .monitor-card__facts {
    gap: var(--space-3);
  }

  .monitor-card__actions {
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: var(--space-1);
  }

  /* A monitor card carries four facts, a policy card carries its rules and an
     overseer card three rate bars — so the three grids want different
     comfortable minimums off the one `.grid--cards` track. */
  .monitor-grid {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr));
  }

  .overseer-grid {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  }

  .policy-grid {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr));
  }

  /* Running or paused is the first thing an operator needs off this card, so
     it is stated three ways: the dot, the badge, and this edge. */
  .monitor-card.is-active {
    box-shadow: inset 3px 0 0 var(--success);
  }

  .monitor-card.is-paused {
    box-shadow: inset 3px 0 0 var(--border-strong);
  }

  .monitor-card.is-paused .monitor-card__body {
    opacity: 0.72;
  }

  /* The human phrase carries the schedule; the cron expression is the truth
     behind it and lives in the title attribute. */
  .schedule {
    color: var(--fg-primary);
    font-weight: var(--weight-medium);
    text-decoration: underline dotted var(--border-strong);
    text-underline-offset: 0.2em;
    cursor: help;
  }

  .cron-chip {
    display: inline-block;
    padding-inline: var(--space-1);
    background-color: var(--bg-sunken);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-control);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    white-space: nowrap;
  }

  /* ══════════════════════════════════════════════════════════════════════
     9 · Governance — policies, rules, overseers, rates
     ══════════════════════════════════════════════════════════════════════ */

  .policy-group + .policy-group {
    margin-block-start: var(--space-6);
  }

  .policy-group__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-block-end: var(--space-3);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
  }

  .policy-group__count {
    min-inline-size: var(--space-5);
    padding-inline: var(--space-1);
    background-color: var(--bg-inset);
    border-radius: var(--radius-pill);
    color: var(--fg-secondary);
    font-size: var(--text-xs);
    letter-spacing: normal;
    text-align: center;
    font-variant-numeric: tabular-nums;
  }

  .policy-card__header,
  .overseer-card__header {
    align-items: flex-start;
  }

  .policy-card__identity,
  .overseer-card__identity {
    display: grid;
    gap: var(--space-05);
    min-inline-size: 0;
  }

  .policy-card__body {
    display: grid;
    gap: var(--space-3);
  }

  .policy-card__footer,
  .overseer-card__footer {
    gap: var(--space-2);
  }

  .policy-card__description,
  .overseer-card__question {
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  .policy-card__layer {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
  }

  .overseer-card__body {
    display: grid;
    gap: var(--space-4);
  }

  /* Three facts on one line — verdict count, window, median latency — each
     its own span. They used to be joined by leading middots, which meant the
     glyph appeared on its own whenever the fact in front of it was absent. */
  .overseer-card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-3);
    min-inline-size: 0;
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-variant-numeric: tabular-nums;
  }

  /* ---- Rules stored as data ------------------------------------------- */

  .rules {
    display: grid;
    gap: var(--space-2);
  }

  .rule {
    display: grid;
    grid-template-columns: var(--space-5) minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-2);
    background-color: var(--bg-sunken);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-control);
  }

  .rule__index {
    display: grid;
    place-items: center;
    inline-size: var(--space-5);
    block-size: var(--space-5);
    background-color: var(--bg-inset);
    border-radius: var(--radius-control);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }

  .rule__pairs {
    display: grid;
    gap: var(--space-1);
    min-inline-size: 0;
  }

  .rule__pair {
    display: grid;
    grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
    gap: var(--space-1) var(--space-3);
    align-items: baseline;
  }

  .rule__key {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-sm);
    overflow-wrap: anywhere;
  }

  .rule__value {
    color: var(--fg-primary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    min-inline-size: 0;
    overflow-wrap: anywhere;
  }

  .rule--empty {
    grid-template-columns: minmax(0, 1fr);
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  /* ---- Verdict mix ----------------------------------------------------
     pass = success, warn = warning, block = danger. Under deuteranopia the
     red–green axis collapses, so the colour is never the only channel: each
     row states its name, its percentage and its count, and the three sit in a
     fixed order. Lightness also separates them (warning is the lightest of
     the three in both themes). */

  .rates {
    display: grid;
    gap: var(--space-2);
  }

  .rate {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "head head"
      "bar  count";
    align-items: center;
    gap: var(--space-1) var(--space-2);
  }

  .rate__head {
    grid-area: head;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  .rate__label {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
  }

  .rate__value {
    color: var(--fg-primary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    font-weight: var(--weight-medium);
    font-variant-numeric: tabular-nums;
  }

  .rate__count {
    grid-area: count;
    min-inline-size: 3ch;
    text-align: end;
    color: var(--fg-faint);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-variant-numeric: tabular-nums;
  }

  .rate__bar {
    grid-area: bar;
  }

  /* The tone is declared on the row and inherited by the bar, so the row
     modifier and the bar modifier can never end up disagreeing. */
  .rate--pass  { --rate-tone: var(--success); }
  .rate--warn  { --rate-tone: var(--warning); }
  .rate--block { --rate-tone: var(--danger); }

  /* ---- <progress>: rate bars and entitlement meters --------------------
     The fill takes `currentColor` so a variant needs one declaration and the
     three vendor pseudo-elements never repeat a colour between them. */

  .rate__bar,
  progress.meter {
    appearance: none;
    -webkit-appearance: none;
    inline-size: 100%;
    block-size: var(--space-2);
    border: 0;
    border-radius: var(--radius-pill);
    background-color: var(--bg-inset);
    color: var(--accent);
    overflow: hidden;
  }

  .rate__bar {
    color: var(--rate-tone, var(--accent));
  }

  .rate__bar::-webkit-progress-bar,
  progress.meter::-webkit-progress-bar {
    background-color: var(--bg-inset);
    border-radius: inherit;
  }

  .rate__bar::-webkit-progress-value,
  progress.meter::-webkit-progress-value {
    background-color: currentColor;
    border-radius: inherit;
  }

  .rate__bar::-moz-progress-bar,
  progress.meter::-moz-progress-bar {
    background-color: currentColor;
    border-radius: inherit;
  }

  .rate__bar--pass  { color: var(--success); }
  .rate__bar--warn  { color: var(--warning); }
  .rate__bar--block { color: var(--danger); }

  .is-exhausted progress.meter {
    color: var(--danger);
  }

  /* ══════════════════════════════════════════════════════════════════════
     10 · Activity — verdict list, stage trace, run drawer
     ══════════════════════════════════════════════════════════════════════ */

  .verdict-list {
    display: grid;
    gap: var(--space-1);
  }

  .verdict {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background-color: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-inline-start-width: 3px;
    border-inline-start-color: var(--border-strong);
    border-radius: var(--radius-control);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  .verdict--pass  { border-inline-start-color: var(--success); }
  .verdict--warn  { border-inline-start-color: var(--warning); }
  .verdict--block { border-inline-start-color: var(--danger); }

  .verdict--empty {
    border-inline-start-color: var(--border-default);
    color: var(--fg-muted);
  }

  .verdict__key {
    flex: 1 1 11rem;
    min-inline-size: 0;
    color: var(--fg-primary);
    overflow-wrap: anywhere;
  }

  .verdict__score,
  .verdict__ms {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
  }

  /* Every reason carries a code, so the list is a record rather than a
     sentence — it wraps to its own full-width row under the verdict. */
  .verdict__reasons {
    flex: 1 1 100%;
    display: grid;
    gap: var(--space-05);
    margin-block-start: var(--space-1);
    padding-inline-start: var(--space-3);
    border-inline-start: 1px solid var(--border-subtle);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-sm);
  }

  /* ---- Stage trace ----------------------------------------------------
     chat.css owns a `.trace` of its own — a <details> with `.trace__row` — and
     sits in an earlier layer, so every shared name here is anchored to the
     surface trace's own element (`ol.trace`) or to `.trace__stage`. Nothing
     below can reach the live chat trace. */

  ol.trace {
    display: grid;
    min-inline-size: 0;
  }

  .trace__stage {
    position: relative;
    display: grid;
    grid-template-columns: var(--space-4) minmax(0, 1fr);
    gap: var(--space-3);
    padding-block: var(--space-2);
    min-inline-size: 0;
  }

  /* The rail runs from under one node to the next, and stops at the last. */
  .trace__stage::before {
    content: "";
    position: absolute;
    inset-block: var(--space-4) 0;
    inset-inline-start: calc(var(--space-2) - 1px);
    inline-size: 2px;
    background-color: var(--border-subtle);
  }

  .trace__stage:last-child::before,
  .trace__stage--empty::before {
    display: none;
  }

  .trace__marker {
    justify-self: center;
    align-self: start;
    position: relative;
    z-index: 1;
    inline-size: var(--size-node);
    block-size: var(--size-node);
    margin-block-start: calc((var(--lh-sm) - var(--size-node)) / 2);
    border-radius: var(--radius-pill);
    background-color: var(--bg-surface);
    box-shadow: inset 0 0 0 2px var(--accent);
  }

  .trace__body {
    display: grid;
    gap: var(--space-1);
    min-inline-size: 0;
  }

  .trace__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  .trace__stage .trace__label {
    color: var(--fg-primary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    font-weight: var(--weight-medium);
  }

  .trace__key {
    color: var(--fg-muted);
    font-size: var(--text-xs);
  }

  .trace__stage .trace__ms {
    margin-inline-start: auto;
    color: var(--fg-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .trace__stage .trace__detail {
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  /* The model call is the one non-deterministic step in the pipeline. Amber
     here is meaning, not emphasis — the same amber the planner badge, the
     `is-model-call` column and the route chip use. */
  .trace__stage--model .trace__marker {
    background-color: var(--warning-subtle);
    box-shadow: inset 0 0 0 2px var(--warning);
  }

  .trace__stage--model .trace__label {
    color: var(--warning-text);
    font-weight: var(--weight-semibold);
  }

  .trace__stage--error .trace__marker {
    background-color: var(--danger-subtle);
    box-shadow: inset 0 0 0 2px var(--danger);
  }

  .trace__stage--error .trace__label {
    color: var(--danger-text);
  }

  .trace__stage--skipped .trace__marker {
    background-color: var(--bg-sunken);
    box-shadow: inset 0 0 0 2px var(--border-strong);
  }

  .trace__stage--skipped .trace__body {
    opacity: 0.7;
  }

  .trace__stage--empty {
    grid-template-columns: minmax(0, 1fr);
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  /* ---- Drawer ---------------------------------------------------------
     components.css ships a drawer whose root element *is* the sliding panel,
     hidden by a transform and revealed by `[data-state="open"]`. These
     templates use a different shape: `.drawer` is the whole overlay, holds its
     own scrim and panel, and is hidden by the `hidden` attribute. Every
     declaration that made the root a panel therefore has to be undone. */

  .drawer-layer {
    display: contents;
  }

  .drawer {
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer);
    display: flex;
    justify-content: flex-end;
    inline-size: auto;
    background: none;
    border: 0;
    box-shadow: none;
    transform: none;
    visibility: visible;
    transition: none;
  }

  .drawer__scrim {
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 1;
    visibility: visible;
    background-color: var(--bg-overlay);
    animation: agp-scrim-in var(--dur-base) var(--ease-out);
  }

  .drawer__panel {
    --drawer-from: var(--space-6);

    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    inline-size: min(100%, 40rem);
    block-size: 100%;
    background-color: var(--bg-surface);
    border-inline-start: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    animation: agp-drawer-in var(--dur-slow) var(--ease-out);
  }

  [dir="rtl"] .drawer__panel {
    --drawer-from: calc(var(--space-6) * -1);
  }

  @keyframes agp-drawer-in {
    from { translate: var(--drawer-from) 0; opacity: 0; }
    to   { translate: 0 0; opacity: 1; }
  }

  @keyframes agp-scrim-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }

  .drawer__heading {
    display: grid;
    gap: var(--space-1);
    min-inline-size: 0;
  }

  .drawer__subtitle {
    color: var(--fg-muted);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  .drawer__close {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    inline-size: var(--control-h-sm);
    block-size: var(--control-h-sm);
    border-radius: var(--radius-control);
    color: var(--fg-muted);
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
  }

  .drawer__close:hover {
    background-color: var(--bg-hover);
    color: var(--fg-primary);
  }

  .drawer__body {
    display: grid;
    align-content: start;
    gap: var(--space-5);
  }

  .drawer__section {
    display: grid;
    gap: var(--space-3);
    min-inline-size: 0;
  }

  .drawer__section-title {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
  }

  .drawer__footer {
    flex-wrap: wrap;
    justify-content: flex-start;
  }

  /* ══════════════════════════════════════════════════════════════════════
     11 · Key/value blocks
     ══════════════════════════════════════════════════════════════════════ */

  .kv {
    display: grid;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  .kv__pair {
    display: grid;
    gap: var(--space-05);
    min-inline-size: 0;
  }

  .kv__key {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
  }

  .kv__value {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    min-inline-size: 0;
    color: var(--fg-primary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    overflow-wrap: anywhere;
  }

  .kv--inline {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
    gap: var(--space-3) var(--space-5);
  }

  .kv--grid {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
    gap: var(--space-3) var(--space-4);
  }

  /* The policy legend is prose in a grid, not a fact list: its values wrap as
     sentences and its keys read as the term being defined. */
  .kv--legend {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
    gap: var(--space-3) var(--space-5);
    padding: var(--space-4);
    background-color: var(--bg-sunken);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-card);
  }

  .kv--legend .kv__key {
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    font-weight: var(--weight-semibold);
  }

  .kv--legend .kv__value {
    display: block;
    color: var(--fg-secondary);
    text-wrap: pretty;
  }

  /* Four terms that mean something specific in this product. A rule beside
     each keeps them reading as separate definitions across a wide grid. */
  .policy-legend .kv__pair {
    padding-inline-start: var(--space-3);
    border-inline-start: 2px solid var(--border-default);
  }

  /* ══════════════════════════════════════════════════════════════════════
     12 · Operations rail
     ══════════════════════════════════════════════════════════════════════ */

  .rail-list {
    display: grid;
    gap: var(--space-1);
  }

  .rail-item {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-3);
    background-color: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-control);
    min-inline-size: 0;
  }

  .rail-item__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  .rail-item__who {
    display: grid;
    min-inline-size: 0;
  }

  .rail-item__actor {
    color: var(--fg-primary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    font-weight: var(--weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .rail-item__when {
    color: var(--fg-faint);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-variant-numeric: tabular-nums;
  }

  .rail-item__body {
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  .rail-item__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
  }

  .rail-item__stat {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
  }

  .rail-item__trace {
    color: var(--fg-faint);
    font-size: var(--text-xs);
  }

  .rail-item__trace:hover {
    color: var(--link);
  }

  .rail-item--empty {
    padding: 0;
    background: none;
    border: 0;
  }

  /* ══════════════════════════════════════════════════════════════════════
     13 · Audit timeline
     ══════════════════════════════════════════════════════════════════════ */

  .timeline__time {
    inline-size: 1%;
    white-space: nowrap;
    color: var(--fg-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
  }

  /* Nothing on an audit row is actionable — it is a record, not a target — so
     it settles back on hover rather than lifting the way a run row does. */
  .table tbody .timeline__row:hover {
    background-color: var(--bg-sunken);
  }

  .timeline__actor  { min-inline-size: 12rem; }
  .timeline__resource { min-inline-size: 13rem; }
  .timeline__scope  { min-inline-size: 11rem; }

  .actor {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    max-inline-size: 100%;
    min-inline-size: 0;
  }

  /* An agent and the platform have no avatar to show, so they get a mark of
     the same size and weight — never a stand-in face. */
  .actor__glyph {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    inline-size: var(--space-5);
    block-size: var(--space-5);
    background-color: var(--bg-inset);
    border-radius: var(--radius-pill);
    color: var(--fg-muted);
  }

  .resource {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
    min-inline-size: 0;
  }

  .table--audit .action {
    color: var(--fg-primary);
    font-size: var(--text-xs);
    white-space: nowrap;
  }

  .timeline__scope .disclosure__summary .truncate,
  .timeline__resource .resource .truncate {
    max-inline-size: 16rem;
  }

  /* ══════════════════════════════════════════════════════════════════════
     14 · Data & corpus
     ══════════════════════════════════════════════════════════════════════ */

  .meta-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    padding: var(--space-3) var(--space-4);
    background-color: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-card);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  .meta-strip__item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
    color: var(--fg-primary);
  }

  .meta-strip__key {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    white-space: nowrap;
  }

  .meta-strip__spacer {
    flex: 1 1 var(--space-4);
  }

  .meta-strip .truncate {
    max-inline-size: 14ch;
  }

  .search-results {
    display: grid;
    gap: var(--space-3);
  }

  /* Where the answer came from and what it cost, stated before the hits. */
  .search-results__provenance {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-sm);
  }

  .search-results__note {
    color: var(--warning-text);
  }

  .search-results__list {
    display: grid;
    gap: var(--space-1);
  }

  .search-hit {
    display: grid;
    gap: var(--space-1);
    padding: var(--space-3);
    background-color: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-control);
    min-inline-size: 0;
  }

  .search-hit__title {
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    font-weight: var(--weight-medium);
  }

  .search-hit__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
  }

  .search-hit__snippet {
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  .search-hit--empty {
    padding: 0;
    background: none;
    border: 0;
  }

  /* ══════════════════════════════════════════════════════════════════════
     15 · Library uploads · Customize privacy
     ══════════════════════════════════════════════════════════════════════ */

  /* Sunken, because it is the input to the table directly beneath it rather
     than another card floating beside it. */
  .upload-form {
    background-color: var(--bg-sunken);
  }

  .upload-form__body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
    gap: var(--space-4);
    align-items: start;
  }

  .upload-form__actions {
    justify-content: flex-end;
  }

  .privacy-grid {
    align-items: start;
  }

  .privacy-card .card__title {
    font-size: var(--text-base);
    line-height: var(--lh-base);
  }

  .privacy-card .card__title > .icon {
    color: var(--fg-muted);
  }

  .privacy-card .card__body > * + * {
    margin-block-start: var(--space-3);
  }

  /* ══════════════════════════════════════════════════════════════════════
     16 · Shared atoms
     ══════════════════════════════════════════════════════════════════════ */

  /* ---- Notices --------------------------------------------------------
     components.css expects `.notice__icon` / `.notice__content`; these
     templates put a bare <svg class="icon"> and a <p> straight in the box. */
  .notice > .icon {
    flex: 0 0 auto;
    margin-block-start: var(--space-05);
  }

  .notice > p {
    min-inline-size: 0;
    text-wrap: pretty;
  }

  .notice--muted {
    background-color: var(--bg-sunken);
    border-color: var(--border-subtle);
    color: var(--fg-secondary);
  }

  /* A statement about the system's own guarantees (the append-only log) is a
     `.callout` now — titled, toned, from components.css — so the old
     `.notice--strong` variant styles nothing and is gone. */

  /* ---- Disclosure ------------------------------------------------------ */

  .disclosure {
    background-color: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-control);
    min-inline-size: 0;
  }

  .disclosure__summary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
    font-weight: var(--weight-medium);
    border-radius: inherit;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
  }

  .disclosure__summary::after {
    content: "";
    flex: 0 0 auto;
    margin-inline-start: auto;
    inline-size: var(--icon-sm);
    block-size: var(--icon-sm);
    background-color: var(--fg-faint);
    mask-image: var(--mask-chevron-down);
    mask-size: 100% 100%;
    -webkit-mask-image: var(--mask-chevron-down);
    -webkit-mask-size: 100% 100%;
    transition: rotate var(--dur-fast) var(--ease-out);
  }

  .disclosure[open] > .disclosure__summary::after {
    rotate: 180deg;
  }

  .disclosure__summary:hover {
    background-color: var(--bg-hover);
    color: var(--fg-primary);
  }

  .disclosure__body {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-3);
    border-block-start: 1px solid var(--border-subtle);
    min-inline-size: 0;
  }

  .disclosure__body > .table-scroll {
    max-block-size: 22rem;
  }

  .disclosure__footnote {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
  }

  /* Inside a table cell or a trace stage the disclosure is a word, not a box. */
  .disclosure--inline {
    background: none;
    border: 0;
    border-radius: 0;
  }

  .disclosure--inline > .disclosure__summary {
    padding: 0;
    gap: var(--space-1);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-sm);
    font-weight: var(--weight-regular);
  }

  .disclosure--inline > .disclosure__summary::after {
    margin-inline-start: var(--space-1);
    inline-size: var(--icon-xs);
    block-size: var(--icon-xs);
  }

  .disclosure--inline > .disclosure__summary:hover {
    background: none;
    color: var(--link);
  }

  .disclosure--inline > .disclosure__body {
    padding: var(--space-2) 0 0;
    border-block-start: 0;
  }

  /* ---- Code and diffs -------------------------------------------------
     Both sit inside a `.table-scroll`, which owns the scrolling; the reset's
     `pre { overflow: auto }` would otherwise put a second scrollbar inside the
     first. `inline-size: max-content` with a 100% floor is what lets a line
     background run the full scrolled width. */

  /* The block scrolls itself. `inline-size: max-content; overflow: visible`
     relied on every caller providing a scrolling wrapper; the one that did not
     (an unwrapped payload on the audit surface) clipped its content with no
     way to reach it. A pre that owns its own overflow-x can never do that,
     wrapped or not. */
  .code-block,
  .diff {
    inline-size: auto;
    min-inline-size: 100%;
    padding: var(--space-3);
    overflow-x: auto;
    background-color: var(--bg-sunken);
    color: var(--fg-secondary);
    font-size: var(--text-xs);
    line-height: var(--lh-sm);
    white-space: pre;
  }

  .diff > code {
    display: grid;
    min-inline-size: max-content;
  }

  .diff__line {
    display: block;
    padding-inline: var(--space-2);
    border-inline-start: 2px solid transparent;
  }

  /* The leading + / - is in the markup, so the colour is a second channel and
     never the only one. */
  .diff__line--add {
    background-color: var(--success-subtle);
    border-inline-start-color: var(--success);
    color: var(--success-text);
  }

  .diff__line--remove {
    background-color: var(--danger-subtle);
    border-inline-start-color: var(--danger);
    color: var(--danger-text);
  }

  .diff__line--context {
    color: var(--fg-muted);
  }

  /* ---- Chips ----------------------------------------------------------- */

  .chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  .chip__count {
    padding-inline: var(--space-1);
    background-color: var(--bg-inset);
    border-radius: var(--radius-pill);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
  }

  /* A dimension name in a catalogue row: a token, not a control. */
  .chip--tiny {
    min-block-size: var(--space-4);
    padding-inline: var(--space-1);
    border-radius: var(--radius-control);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    font-weight: var(--weight-regular);
  }

  /* ---- Dots, flags, status -------------------------------------------- */

  .dot {
    display: inline-block;
    flex: 0 0 auto;
    inline-size: var(--size-dot);
    block-size: var(--size-dot);
    border-radius: var(--radius-pill);
    background-color: var(--fg-faint);
  }

  .dot--success { background-color: var(--success); }
  .dot--warning { background-color: var(--warning); }
  .dot--danger  { background-color: var(--danger); }
  .dot--muted   { background-color: var(--fg-faint); }

  /* `.dot-sep` is gone. It painted a middot between items of a row that was
     already a flex line with its own gap, so the glyph separated nothing the
     layout had not separated. The three rows that carried it — the corpus
     search provenance, the approval footnote and the dashboards card
     subtitle — now rely on the gap alone. */

  .status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    white-space: nowrap;
  }

  /* A yes/no cell. "No" is an em dash rather than a red cross: absence is not
     a failure on these tables. */
  .flag {
    display: inline-grid;
    place-items: center;
    min-inline-size: var(--space-5);
    block-size: var(--space-5);
    padding-inline: var(--space-1);
    border-radius: var(--radius-control);
    font-size: var(--text-xs);
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }

  .flag--on {
    background-color: var(--success-subtle);
    color: var(--success-text);
    box-shadow: inset 0 0 0 1px var(--success-border);
  }

  .flag--off {
    color: var(--fg-faint);
  }

  /* ---- Lists ----------------------------------------------------------- */

  .list {
    display: grid;
    gap: var(--space-2);
    min-inline-size: 0;
  }

  /* The reset strips markers from any list carrying a class, so the marker is
     redrawn here — a dot the same weight as a rule, not a bullet glyph. */
  .list--plain {
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  .list--plain > li {
    position: relative;
    padding-inline-start: var(--space-4);
    text-wrap: pretty;
  }

  .list--plain > li::before {
    content: "";
    position: absolute;
    inset-inline-start: var(--space-1);
    inset-block-start: calc((var(--lh-sm) - var(--size-dot)) / 2);
    inline-size: var(--size-dot);
    block-size: var(--size-dot);
    border-radius: var(--radius-pill);
    background-color: var(--border-strong);
  }

  /* ---- Pager ----------------------------------------------------------- */

  .pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-block-start: var(--space-4);
    padding-block-start: var(--space-3);
    border-block-start: 1px solid var(--border-subtle);
  }

  .pager__status {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
  }

  .pager__controls {
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  .pager__link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-block-size: var(--control-h-sm);
    padding-inline: var(--space-3);
    background-color: var(--bg-surface);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-control);
    color: var(--fg-secondary);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    white-space: nowrap;
    transition: background-color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
  }

  .pager__link:hover {
    background-color: var(--bg-hover);
    border-color: var(--border-strong);
    color: var(--fg-primary);
  }

  /* ---- Links and text -------------------------------------------------- */

  /* An inline <svg class="icon"> is `display: block` from the reset, so a link
     carrying one has to be a flex line or the glyph drops to its own row.
     Scoped to the nine roots: the chat surface has its own link treatments.
     `--icon` is exempt — it is a square target, not a line of text. */
  .surface[data-surface] .link:has(> .icon):not(.link--icon) {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
  }

  .link--small {
    font-size: var(--text-sm);
    line-height: var(--lh-sm);
  }

  .link--block {
    display: block;
  }

  .link--icon {
    display: inline-grid;
    place-items: center;
    inline-size: var(--control-h-sm);
    block-size: var(--control-h-sm);
    border-radius: var(--radius-control);
    color: var(--fg-muted);
    text-decoration: none;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
  }

  .link--icon:hover {
    background-color: var(--bg-hover);
    color: var(--fg-primary);
  }

  .fg-muted {
    color: var(--fg-muted);
  }

  /* Every figure on these screens is compared down a column. */
  .num,
  .is-num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
  }

  .table thead th.is-num,
  .table tbody td.num,
  .table tbody th.num {
    text-align: end;
    white-space: nowrap;
  }

  .truncate-2 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
  }

  /* ---- Empty state ----------------------------------------------------
     `components/empty_state.html` renders `.empty-state`, owned by
     components.css beside its sibling `.error-state`. chat.css's `.empty`
     — the assistant's opening screen — is a different thing, reaches only
     the chat surface, and no rule here may collide with it. */

  /* ══════════════════════════════════════════════════════════════════════
     17 · State classes

     `is-*` is the server's word for a row's condition. Each one is a second
     channel beside a badge or a dot that already says the same thing in text.
     ══════════════════════════════════════════════════════════════════════ */

  /* components.css keys its selected states off ARIA; these templates ship
     `is-active` beside the same ARIA, so the two are bridged here. */
  .segmented__item.is-active {
    background-color: var(--bg-surface);
    color: var(--fg-primary);
    box-shadow: var(--shadow-xs);
  }

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

  .segmented__item.is-active .segmented__count {
    color: var(--fg-muted);
  }

  .tab.is-active {
    color: var(--fg-primary);
  }

  .chip.is-active {
    --chip-bg: var(--accent-subtle);
    --chip-border: var(--accent-border);
    --chip-fg: var(--accent-text);
  }

  .chip.is-active .chip__count {
    background-color: var(--bg-surface);
    color: var(--accent-text);
  }

  /* A whole row opens the run drawer, so it has to look and focus like a
     control even though it is a <tr>. */
  .table__row.is-clickable {
    cursor: pointer;
  }

  .table__row.is-clickable:focus-visible {
    outline-offset: calc(var(--focus-ring-offset) * -1);
  }

  /* The row whose drawer is open. `app.js` has always flipped `aria-expanded`
     on it, and the only `[aria-expanded="true"]` rule in any sheet belonged to
     the composer's tools — so an open row looked exactly like the other forty,
     and closing the drawer left nothing on screen saying which one you had
     just had open. That is the moment a reader needs it most. The selected
     ground plus the accent edge is the same vocabulary the drawer's own panel
     uses, and the edge is drawn in `box-shadow` for the same reason the
     failed/refused rows above draw theirs that way: a `<tr>` cannot take a
     border without the cells disagreeing about where it goes. */
  .table__row[aria-expanded="true"] {
    background-color: var(--bg-selected);
  }

  .table__row[aria-expanded="true"] > :first-child {
    box-shadow: inset 2px 0 0 var(--accent);
  }

  .table__row[aria-expanded="true"] .table__cell--primary {
    font-weight: var(--weight-semibold);
  }

  .table__row.is-overdue > :first-child,
  .table__row.is-failed > :first-child,
  .table__row.is-exhausted > :first-child {
    box-shadow: inset 2px 0 0 var(--danger);
  }

  .table__row.is-refused > :first-child {
    box-shadow: inset 2px 0 0 var(--warning);
  }

  .table__row.is-overdue .table__cell--primary,
  .table__row.is-failed .table__cell--primary {
    color: var(--danger-text);
  }

  /* The count of model calls, wherever it is shown — a run row's LLM column
     and the same figure in the drawer. Amber is the same amber as the planner
     route and the model stage: one meaning, one colour. The second selector
     is what outranks components.css's `.table tbody td` ink. */
  .is-model-call,
  .table tbody .is-model-call {
    color: var(--warning-text);
    font-weight: var(--weight-semibold);
  }

  .is-expiring {
    color: var(--warning-text);
  }

  .policy-card.is-disabled,
  .overseer-card.is-disabled {
    opacity: 0.66;
  }

  .policy-card.is-disabled .card__title,
  .overseer-card.is-disabled .card__title {
    color: var(--fg-muted);
  }

  /* ══════════════════════════════════════════════════════════════════════
     18 · Responsive

     app.css fixes the product's breakpoints at 1440 / 1200 / 900 / 640. The
     split body needs one more: its rail stops being readable before the
     sidebar needs to leave, so it folds at 1100.
     ══════════════════════════════════════════════════════════════════════ */

  @media (max-width: 1100px) {
    .surface--split {
      grid-template-columns: minmax(0, 1fr);
      gap: var(--space-8);
    }
  }

  @media (max-width: 900px) {
    .grid--2 {
      grid-template-columns: minmax(0, 1fr);
    }

    .rule__pair {
      grid-template-columns: minmax(0, 8rem) minmax(0, 1fr);
    }

    .drawer__panel {
      inline-size: min(100%, 34rem);
    }
  }

  @media (max-width: 640px) {
    .surface[data-surface] > .page-header {
      padding-block-end: var(--space-4);
    }

    .section__header {
      flex-direction: column;
      align-items: stretch;
      gap: var(--space-2);
    }

    .section__actions {
      flex-wrap: wrap;
    }

    /* Every control in a toolbar takes the full row rather than wrapping into
       an uneven two-up. */
    .toolbar {
      flex-direction: column;
      align-items: stretch;
    }

    .toolbar .field,
    .toolbar .filter,
    .toolbar__note {
      flex: 1 1 auto;
    }

    .toolbar__spacer {
      display: none;
    }

    .toolbar .segmented {
      overflow-x: auto;
      scrollbar-width: none;
    }

    .chart {
      block-size: 12rem;
    }

    .table-scroll {
      max-block-size: min(30rem, calc(100dvh - 10rem));
    }

    .kv--inline,
    .kv--grid,
    .kv--legend {
      grid-template-columns: minmax(0, 1fr);
    }

    .rule__pair {
      grid-template-columns: minmax(0, 1fr);
      gap: 0;
    }

    .drawer__panel {
      inline-size: 100%;
      border-inline-start: 0;
    }

    .decision,
    .kv--legend {
      padding: var(--space-3);
    }

    .card__footer {
      flex-wrap: wrap;
    }

    .pager {
      justify-content: flex-start;
    }
  }

  /* ── The row-card collapse (≤ 767px) ────────────────────────────────────
     A horizontal scroller inside a vertically scrolling phone page is the
     wrong answer, so below 768px an adopted table stops being a table: the
     SAME rows — one template loop, no duplicated markup — re-lay themselves
     as tappable cards. The reference build shipped this as a second, hidden
     copy of every row; two copies of one row is a drift waiting to happen,
     so here the collapse is CSS-only over the single copy.

     The contract a template signs, per table:
       · `table-scroll--rowcards` on the wrapper, `table--rowcards` on the
         table;
       · the identifying cell carries `.table__cell--primary` and holds the
         row's link (stretched over the whole card down here);
       · badge cells that lead the card carry `data-rc="top"`;
       · the two-or-three cells worth keeping carry `data-rc="meta"`, with
         `data-rc-label` where the bare value would not say what it is;
       · a full-width cell (the empty-state row) carries `data-rc="full"`.
     Every unmarked cell is dropped from the card — marking what survives is
     the design decision, and it is made in the template, next to the data.

     This block lives HERE, not in components.css: it re-points cell padding,
     the .table--runs column floor and the .table-scroll ceiling, all of which
     this layer owns — a components-layer rule can never win those. It also
     sits after the 640px block above, so its .table-scroll override outranks
     that block's max-block-size by order. Trade-off, stated: `display: block`
     on a table strips its semantics for a screen reader at phone widths; the
     reader gets the same content linearised, which is exactly what the
     reference's hidden-table variant gave it.

     ── Two conditions, one recipe ──────────────────────────────────────────
     The collapse is split across a media query and a container query, and the
     split is a statement about what each rule is *about*:

       · `@media (max-width: 767px)` — the WRAPPER stops being a bounded,
         bordered scroller. That is a page-level decision ("no horizontal
         scroller inside a vertically scrolling phone page"), it is about the
         viewport, and it has to be able to style the wrapper itself, which a
         container query evaluated on that same wrapper cannot do.
       · `@container rowcards (max-width: 767px)` — the ROWS become cards.
         That is about the space the table actually has, not about the
         viewport: a table in a narrow rail on a 27" monitor has the same
         problem a table on a phone has. The wrapper carries
         `container-type: inline-size`, so every rule below reads the width
         the table was actually given.

     On a phone both fire and the result is exactly what the media query alone
     used to produce. Elsewhere the container query alone fires — which is how
     `/design` can show a bounded specimen at any window width without a
     second copy of these forty declarations. `contain: layout` on the wrapper
     is safe here because the card's stretched row link resolves against
     `tbody tr`, which is `position: relative` below. */
  @media (max-width: 767px) {
    .table-scroll--rowcards {
      max-block-size: none;
      overflow: visible;
      background-color: transparent;
      border: 0;
      border-radius: 0;
    }
  }

  /* The wrapper is the container the rules below measure. Declared outside
     both queries: a container cannot be established from inside a query that
     depends on it. */
  .table-scroll--rowcards {
    container-type: inline-size;
    container-name: rowcards;
  }

  @container rowcards (max-width: 767px) {
    /* The column floors (.table--runs, .table--audit) exist to force a
       scroller; a card list must never have one. */
    .table--rowcards {
      min-inline-size: 0;
      display: block;
      inline-size: 100%;
    }

    .table--rowcards thead { display: none; }

    .table--rowcards tbody { display: block; }

    /* One row, one card — the reference's rowcard recipe on this system's
       tokens: bordered, rounded, surface ground, accent border on hover. */
    .table--rowcards tbody tr {
      position: relative;
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: var(--space-1) var(--space-2);
      padding: var(--space-3);
      background-color: var(--bg-surface);
      /* A card, so it draws the card's hairline. `.card` and `.artifact` are
         `--border-subtle`; this recipe was the one card in the product still
         drawn in the heavier line. */
      border: 1px solid var(--border-subtle);
      border-radius: var(--radius-card);
      transition: background-color var(--dur-fast) var(--ease-out),
        border-color var(--dur-fast) var(--ease-out);
    }

    .table--rowcards tbody tr + tr { margin-block-start: var(--space-2); }

    .table--rowcards tbody tr:hover {
      background-color: var(--bg-surface);
      border-color: var(--accent-border);
    }

    /* Cells stop being boxes; the card's padding is the only padding. */
    .table--rowcards tbody td,
    .table--rowcards tbody th {
      display: block;
      min-inline-size: 0;
      padding: 0;
      border-block-end: 0;
    }

    /* Badges and identifiers marked data-rc="top" lead the card… */
    .table--rowcards tbody [data-rc="top"] { order: 0; }

    /* …the primary cell is the card's own full-width line… */
    .table--rowcards tbody .table__cell--primary {
      order: 1;
      flex: 1 1 100%;
      max-inline-size: none;
    }

    /* …and the marked metas trail it, mono and muted, each clipped rather
       than allowed to push the card wider than the page. */
    .table--rowcards tbody [data-rc="meta"] {
      order: 2;
      max-inline-size: 100%;
      overflow: hidden;
      color: var(--fg-muted);
      font-family: var(--font-mono);
      font-size: var(--text-xs);
      line-height: var(--lh-xs);
      text-align: start;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .table--rowcards tbody [data-rc="meta"][data-rc-label]::before {
      content: attr(data-rc-label) " ";
      color: var(--fg-faint);
    }

    .table--rowcards tbody [data-rc="full"] {
      order: 3;
      flex: 1 1 100%;
    }

    /* Everything unmarked has no place on a card. */
    .table--rowcards tbody td:not([data-rc]):not(.table__cell--primary),
    .table--rowcards tbody th:not([data-rc]):not(.table__cell--primary) {
      display: none;
    }

    /* The empty-state row is a message, not a record: no card chrome. */
    .table--rowcards tbody .table__row--empty {
      padding: 0;
      background-color: transparent;
      border: 0;
    }

    /* The row's link covers the whole card. Every other control on the card
       (a copy button, an inner link) lifts above the stretched overlay so it
       keeps its own press — and the stretched link itself must stay
       unpositioned, or its overlay would resolve against the anchor instead
       of the card. */
    .table--rowcards tbody .table__cell--primary :is(.link, .entity-link)::after {
      content: "";
      position: absolute;
      inset: 0;
    }

    .table--rowcards tbody tr :is(a, button) {
      position: relative;
      z-index: 1;
    }

    .table--rowcards tbody .table__cell--primary > :is(.link, .entity-link) {
      position: static;
    }

    /* §17 paints row states as an inset shadow on the first cell; on a card
       the state moves to the card's own edge. */
    .table--rowcards tbody .table__row.is-overdue > :first-child,
    .table--rowcards tbody .table__row.is-failed > :first-child,
    .table--rowcards tbody .table__row.is-exhausted > :first-child,
    .table--rowcards tbody .table__row.is-refused > :first-child {
      box-shadow: none;
    }

    .table--rowcards tbody tr.is-overdue,
    .table--rowcards tbody tr.is-failed,
    .table--rowcards tbody tr.is-exhausted {
      border-inline-start: 2px solid var(--danger);
    }

    .table--rowcards tbody tr.is-refused {
      border-inline-start: 2px solid var(--warning);
    }
  }

  /* ══════════════════════════════════════════════════════════════════════
     19 · Reduced motion

     reset.css already collapses every duration to 1ms globally; these are
     stated anyway so the drawer and the caret are unambiguously still rather
     than merely instantaneous.
     ══════════════════════════════════════════════════════════════════════ */

  @media (prefers-reduced-motion: reduce) {
    .drawer__panel,
    .drawer__scrim {
      animation: none;
    }

    .disclosure__summary::after,
    .pager__link,
    .link--icon,
    .drawer__close,
    .input--file::file-selector-button {
      transition: none;
    }
  }
}

@layer surfaces {
  /* ── Dashboards ─────────────────────────────────────────────────────────
     Saved collections + the drill-down walk. Everything here is links and
     server-rendered state; there is deliberately no dashboard JavaScript. */

  .dash-create__row {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: var(--space-3);
  }
  .dash-create__name { flex: 1 1 16rem; }
  .dash-create__error {
    margin: 0;
    padding: 0 var(--space-4) var(--space-3);
    color: var(--danger-text);
    font-size: var(--text-sm);
  }

  .dash-card { position: relative; display: flex; align-items: stretch; padding: 0; }
  .dash-card__main { flex: 1; min-width: 0; text-decoration: none; color: inherit; border-radius: inherit; }
  .dash-card__main:hover { background: var(--bg-hover); }
  .dash-card__remove { position: absolute; top: var(--space-2); right: var(--space-2); }

  /* One row-entity, card form. The whole card is the link. */
  .entity-card { display: block; text-decoration: none; color: inherit; }
  .entity-card:hover { border-color: var(--border-strong); background: var(--bg-hover); }
  .entity-card__title {
    display: flex; align-items: center; gap: var(--space-2);
    margin: 0; font-size: var(--text-md); font-weight: var(--weight-semibold);
    color: var(--fg-primary);
  }
  .entity-card__subtitle {
    margin: var(--space-05) 0 0; font-size: var(--text-sm); color: var(--fg-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .entity-card__facts {
    display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5);
    margin: var(--space-3) 0 0;
  }
  .entity-card__fact dt {
    font-size: var(--text-xs); color: var(--fg-faint);
    letter-spacing: var(--tracking-caps); text-transform: uppercase;
  }
  .entity-card__fact dd { margin: 0; font-size: var(--text-sm); color: var(--fg-secondary); }

  .entity-link { color: var(--fg-primary); font-weight: var(--weight-medium); text-decoration: none; }
  .entity-link:hover { color: var(--accent-text); text-decoration: underline; }

  /* The view switcher — links, not buttons: each view is an address. */
  .viewswitch {
    display: inline-flex; align-items: center; gap: var(--space-05);
    padding: var(--space-05);
    background: var(--bg-sunken);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-control);
  }
  .viewswitch__item {
    display: inline-flex; align-items: center; gap: var(--space-1);
    min-block-size: var(--control-h-sm); padding-inline: var(--space-2);
    border-radius: var(--radius-control);
    color: var(--fg-muted); font-size: var(--text-sm); font-weight: var(--weight-medium);
    text-decoration: none; white-space: nowrap;
  }
  .viewswitch__item:hover { color: var(--fg-primary); }
  .viewswitch__item.is-active { background: var(--bg-surface); color: var(--fg-primary); box-shadow: var(--shadow-xs); }

  /* The map: the workspace's own dots on an inline SVG. Text sizes are in
     viewBox units on purpose — the SVG scales as one picture. */
  .map-frame { margin: 0; }
  .map-frame__canvas { display: block; inline-size: 100%; block-size: auto; }
  .map-frame__ground { fill: var(--bg-sunken); stroke: var(--border-default); stroke-width: 0.3; }
  .map-frame__dot { fill: var(--accent); stroke: var(--bg-surface); stroke-width: 0.4; }
  .map-frame__canvas a:hover .map-frame__dot,
  .map-frame__canvas a:focus .map-frame__dot { r: 2.2; }
  .map-frame__label { fill: var(--fg-secondary); font-size: 2.6px; }
  .map-frame__caption { margin-top: var(--space-2); font-size: var(--text-xs); color: var(--fg-faint); }
  .map-frame__rest { margin-top: var(--space-4); }
  .map-frame__rest-list { margin: var(--space-1) 0 0; padding: 0; display: grid; gap: 2px; }

  /* Profile facts strip. */
  .facts {
    display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-8);
    margin: 0; padding: var(--space-4);
    background: var(--bg-surface); border: 1px solid var(--border-subtle);
    border-radius: var(--radius-card);
  }
  .facts__label {
    font-size: var(--text-xs); color: var(--fg-faint);
    letter-spacing: var(--tracking-caps); text-transform: uppercase;
  }
  .facts__value { margin: 0; font-size: var(--text-md); color: var(--fg-primary); font-weight: var(--weight-medium); }
}

@layer surfaces {
  /* ── Design system page ── swatch grid + icon grid; everything else on the
     page is the real component styling itself. */
  .design-swatches { display: flex; flex-wrap: wrap; gap: var(--space-3); }
  .design-swatch { margin: 0; display: grid; gap: var(--space-1); justify-items: center; }
  .design-swatch__chip {
    inline-size: 56px; block-size: 36px; border-radius: var(--radius-control);
    border: 1px solid var(--border-default);
  }
  .design-swatch__name { font-size: var(--text-xs); color: var(--fg-faint); }
  .design-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: var(--space-2) 0; }
  .design-icons {
    list-style: none; margin: 0; padding: 0;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: var(--space-2);
  }
  .design-icon {
    display: flex; align-items: center; gap: var(--space-2);
    padding: var(--space-1) var(--space-2); border-radius: var(--radius-control);
    color: var(--fg-secondary); font-size: var(--text-xs);
  }
  .design-icon:hover { background: var(--bg-hover); color: var(--fg-primary); }

  /* The section index. Sticky under the topbar so "where was that?" never
     costs a scroll to the top; `scroll-margin` on the sections it points at so
     a jump does not park the heading underneath it. */
  .design-index {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--z-sticky);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-block-end: var(--space-5);
    padding-block: var(--space-3);
    background-color: var(--bg-canvas);
    border-block-end: 1px solid var(--border-subtle);
  }

  .design-index__label {
    color: var(--fg-faint);
    font-size: var(--text-xs);
    line-height: var(--lh-xs);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
  }

  .surface--design .section { scroll-margin-block-start: var(--space-16); }

  /* A specimen box narrow enough to put a component into its narrow state.
     `.table-scroll--rowcards` inside this is under 768px of inline size, so
     the row-card container query fires here at any window width — which is the
     only way a desktop reader ever sees that state. */
  .design-bound { max-inline-size: 21rem; }

  /* Provenance under a specimen: which producer emits this, or that nothing
     does. A specimen with no producer is a fact worth printing, not a fact
     worth hiding — this page is where "what exists?" gets answered. */
  .design-source {
    max-inline-size: var(--measure);
    margin-block: var(--space-1) var(--space-3);
    color: var(--fg-muted);
    font-size: var(--text-xs);
    line-height: var(--lh-sm);
    text-wrap: pretty;
  }

  .design-source strong { color: var(--warning-text); }
}
