/* The console's stylesheet, written to CUBE CSS (cube.fyi): global styles
   first, then Composition (layout skeletons that carry no visual
   treatment), Utility (one job each), Block (the console's components, each
   a handful of rules), and Exception (a block's variations, always a data
   attribute so script and stylesheet share the hook). The cascade does the
   work: a block is what is left once the global styles, a composition and
   a utility or two have done theirs.

   Markup groups its classes with brackets, in this order:
   class="[ block ] [ compositions ] [ utilities ]". The brackets are
   ignored tokens; they are for the reader.

   Colours are Catppuccin Frappé. The five names the rest of the repo
   relies on (--acc, --ok, --warn, --err, --bd, --txt, --bright, --dim) are
   the tokens below and must keep their names: an invalid var() silently
   paints nothing. This file is the whole console: nothing else is linked.

   The icon font is a Phosphor Bold subset, embedded. Regenerate it with
   scripts/phosphor_subset.py (ADMIN_WANTED) and paste its output over the
   block below; the .ph rules it emits are part of the global layer. */

/* ═══════════════════════════════════════════════════════════════════════
   Tokens
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  color-scheme: dark;

  /* Ground and surfaces */
  --bg: #303446;       /* base: page ground */
  --pane: #292c3c;     /* mantle: topbar, nav, cards, panels */
  --term: #232634;     /* crust: log terminal, wells */
  --hov: #333849;      /* row and button hover */

  /* Lines. Solid, hue-matched, never alpha: an alpha border glows on a
     ground this dark. */
  --bd: #414559;       /* surface0 */
  --bd-soft: #3a3e51;  /* quiet row separators */
  --line-ctl: #51576d; /* control border */
  --line-ctl-hi: #626880;
  --line-acc: #5e6da3; /* the accent's own border */
  --line-err: #6b4145;

  /* Ink */
  --txt: #b5bfe2;
  --bright: #c6d0f5;
  --dim: #838ba7;      /* labels, kickers */
  --mut: #737994;      /* faint, disabled */
  --on-acc: #232634;   /* ink on the accent, which is light */

  /* Hues */
  --acc: #8caaee;
  --ok: #a6d189;
  --warn: #e5c890;
  --err: #e78284;
  --acc-tint: rgba(140, 170, 238, 0.13);
  --acc-tint-hi: rgba(140, 170, 238, 0.22);
  --ok-tint: rgba(166, 209, 137, 0.12);
  --warn-tint: rgba(229, 200, 144, 0.12);
  --err-tint: rgba(231, 130, 132, 0.12);
  --err-tint-hi: rgba(231, 130, 132, 0.22);
  --mut-tint: rgba(115, 121, 148, 0.12);

  /* Space. Every gap and padding in the console is one of these. */
  --space-3xs: 0.15rem;
  --space-2xs: 0.31rem;
  --space-xs: 0.46rem;
  --space-s: 0.62rem;
  --space-m: 0.77rem;
  --space-l: 0.92rem;
  --space-xl: 1.08rem;
  --space-2xl: 1.4rem;
  --space-3xl: 1.7rem;
  --space-4xl: 2.15rem;

  /* Type. The root rides a clamp (below), so every step is rem. */
  --step--3: 0.72rem;
  --step--2: 0.78rem;
  --step--1: 0.85rem;
  --step-0: 1rem;
  --step-1: 1.08rem;
  --step-2: 1.31rem;
  --step-3: 1.46rem;
  --step-4: 1.7rem;
  --step-5: 2rem;
  --kicker-track: 0.08em;

  --radius-s: 5px;
  --radius-m: 8px;
  --radius-l: 12px;
  --radius-pill: 999px;

  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  --nav-width: 16rem;
  --touch: 44px;
  /* The one literal floor: iOS zooms a field smaller than 16px. */
  --field-size: max(16px, 1rem);
}

/* ═══════════════════════════════════════════════════════════════════════
   Global
   ═══════════════════════════════════════════════════════════════════════ */
/* Phosphor bold v2.1.1, subset to the console's glyphs. */
@font-face{font-family:"Phosphor-Bold-Admin";src:url(data:font/woff2;base64,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) format("woff2");font-weight:normal;font-style:normal;font-display:block}
.ph{font-family:"Phosphor-Bold-Admin"!important;speak:never;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;width:1em;height:1em}
.ph.ph-caret-left:before{content:"\e138"}
.ph.ph-briefcase:before{content:"\e0ee"}
.ph.ph-gear:before{content:"\e270"}
.ph.ph-globe:before{content:"\e288"}
.ph.ph-play:before{content:"\e3d0"}
.ph.ph-power:before{content:"\e3da"}
.ph.ph-prohibit:before{content:"\e3de"}
.ph.ph-pulse:before{content:"\e000"}
.ph.ph-robot:before{content:"\e762"}
.ph.ph-terminal-window:before{content:"\eae8"}
.ph.ph-warning:before{content:"\e4e0"}
.ph.ph-squares-four:before{content:"\e464"}
.ph.ph-list-dashes:before{content:"\e2f4"}
.ph.ph-arrow-square-out:before{content:"\e5de"}
.ph.ph-clock:before{content:"\e19a"}
.ph.ph-check-circle:before{content:"\e184"}
.ph.ph-x-circle:before{content:"\e4f8"}
.ph.ph-circle-dashed:before{content:"\e602"}
.ph.ph-cpu:before{content:"\e610"}
.ph.ph-gauge:before{content:"\e628"}
.ph.ph-memory:before{content:"\e9c4"}
.ph.ph-hard-drive:before{content:"\e29e"}
.ph.ph-hard-drives:before{content:"\e2a0"}
.ph.ph-shield-check:before{content:"\e40c"}
.ph.ph-arrows-clockwise:before{content:"\e094"}
.ph.ph-sign-in:before{content:"\e428"}
.ph.ph-tag:before{content:"\e478"}
.ph.ph-users:before{content:"\e4d6"}
.ph.ph-user:before{content:"\e4c2"}
.ph { font-size: 1.05em; vertical-align: -0.14em; }

* { box-sizing: border-box; }
/* A background on the root, not only on body: between two loads the browser
   paints its own canvas first, and on a console this dark that is a white
   flash. The fluid root is ~13px on a phone, ~15px at 1440, ~17px on a big
   display; every size in this file rides on it. */
html { background: var(--bg); font-size: clamp(13px, 11.8px + 0.22vw, 17px); height: 100%; }
body { margin: 0; height: 100dvh; display: flex; flex-direction: column;
  background: var(--bg); color: var(--txt); font-family: var(--font-mono); font-size: var(--step-0);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
h1, h2, h3, p { margin: 0; font-size: inherit; font-weight: inherit; }
a { color: var(--acc); text-decoration: none; }
b, strong { font-weight: 600; }
em { font-style: normal; }
:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
/* The author's display beats the UA's [hidden] at any specificity — three
   times this console shipped a flex element that would not hide. Once, here. */
[hidden] { display: none !important; }

button { display: inline-flex; align-items: center; justify-content: center; gap: 0.46em;
  min-height: 2.31rem; padding: 0.31em 0.92em; border: 1px solid var(--line-ctl); border-radius: var(--radius-s);
  background: var(--bd); color: var(--txt); font: inherit; font-size: 0.92rem; cursor: pointer;
  touch-action: manipulation; transition: background-color 120ms ease-out, border-color 120ms ease-out; }
button .ph { font-size: 1em; }
button:active { transform: scale(0.96); }
button[disabled] { color: var(--mut); cursor: default; }
input, select { padding: 0.38em 0.77em; border: 1px solid var(--line-ctl); border-radius: var(--radius-s);
  background: var(--term); color: var(--bright); font-family: inherit; font-size: var(--field-size); }
table { border-collapse: collapse; }

@media (hover: hover) and (pointer: fine) {
  a:hover { text-decoration: underline; }
  button:not([disabled]):hover { background: var(--hov); }
}
@media (pointer: coarse) { button { min-height: var(--touch); } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Composition
   Skeletons: how things sit beside and under each other. No colour, no
   type, no decoration — those belong to the blocks placed inside.
   ═══════════════════════════════════════════════════════════════════════ */
/* Vertical rhythm between siblings; a block sets --flow-space in context. */
.flow > * + * { margin-block-start: var(--flow-space, var(--space-l)); }

/* Things in a row that may wrap. */
.cluster { display: flex; flex-wrap: wrap; align-items: var(--cluster-align, center);
  gap: var(--cluster-gap, var(--space-s)); }

/* Two ends pushed apart, wrapping when they cannot both fit. */
.repel { display: flex; flex-wrap: wrap; justify-content: space-between;
  align-items: var(--repel-align, center); gap: var(--repel-gap, var(--space-m) var(--space-xl)); }

/* As many columns as fit, each at least --grid-min. */
.grid { display: grid; gap: var(--grid-gap, var(--space-l));
  grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min, 13rem), 100%), 1fr)); }

/* Fixed counts, for rows that must never leave a straggler: two, three or
   six across, stepping down together. */
.two-up { display: grid; gap: var(--grid-gap, var(--space-l)); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.thirds { display: grid; gap: var(--grid-gap, var(--space-l)); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.sixths { display: grid; gap: var(--grid-gap, var(--space-l)); grid-template-columns: repeat(6, minmax(0, 1fr)); }
.span-all { grid-column: 1 / -1; }
@media (max-width: 1400px) { .sixths { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 1240px) { .thirds { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 1020px) { .two-up { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 900px) { .sixths { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 700px) { .thirds { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 600px) { .sixths { grid-template-columns: minmax(0, 1fr); } }

/* A fixed column beside a fluid one; the two stack below --sidebar-break. */
.with-sidebar { display: flex; flex: 1; min-height: 0; }
.with-sidebar > :first-child { flex: none; }
.with-sidebar > :last-child { flex: 1; min-width: 0; min-height: 0; }
@media (max-width: 840px) { .with-sidebar { flex-direction: column; } }

/* The padded area a page draws in. Uncapped on purpose: the console
   stretches to fill a big display. */
.region { padding: var(--space-l) var(--space-3xl) var(--space-4xl); }
@media (max-width: 840px) { .region { padding: var(--space-2xl) var(--space-xl) var(--space-4xl); } }

/* A page that fills the viewport and gives its last child the slack, so a
   log or a run history scrolls inside its panel rather than the page. On
   a stacked layout the panels take fixed heights instead. */
@media (min-width: 1021px) {
  .fill { height: 100%; display: flex; flex-direction: column; }
  .fill > :last-child { flex: 1; min-height: 24rem; }
  .fill > .two-up:last-child { grid-template-rows: minmax(0, 1fr); align-items: stretch; }
  .fill > :last-child > * { min-height: 0; }
}

/* A column whose one marked child takes the slack, inside a filling page;
   everything else keeps its size. Stacked, it is a plain column. */
.column-fill { display: flex; flex-direction: column; gap: var(--space-l); min-height: 0; }
.column-fill > * { flex: none; }
@media (min-width: 1021px) { .fill .column-fill > [data-grow] { flex: 1; min-height: 0; } }

/* ═══════════════════════════════════════════════════════════════════════
   Utility
   One job each. Token utilities apply a token; the rest are helpers.
   ═══════════════════════════════════════════════════════════════════════ */
.kicker { font-size: var(--step--1); text-transform: uppercase; letter-spacing: var(--kicker-track); color: var(--dim); }
.kicker-s { font-size: var(--step--2); text-transform: uppercase; letter-spacing: var(--kicker-track); color: var(--dim); }
.tabular { font-variant-numeric: tabular-nums; }
.truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wrap { overflow-wrap: break-word; }
.nowrap { white-space: nowrap; }
.grow { flex: 1; min-width: 0; }
.push-end { margin-inline-start: auto; }
.text-end { text-align: end; }
.text-center { text-align: center; }
.scroll-x { overflow-x: auto; }
.measure { max-width: 64ch; }
.step--2 { font-size: var(--step--2); }
.step--1 { font-size: var(--step--1); }
.step-1 { font-size: var(--step-1); }
.text-txt { color: var(--txt); }
.text-bright { color: var(--bright); }
.text-dim { color: var(--dim); }
.text-mut { color: var(--mut); }
.text-acc { color: var(--acc); }
.text-ok { color: var(--ok); }
.text-warn { color: var(--warn); }
.text-err { color: var(--err); }
.bg-term { background: var(--term); }
.pad { padding: var(--space-xl); }
.pad-x { padding-inline: var(--space-xl); }
/* Screen-reader only. position:absolute, which is why .main below is a
   positioned scroll port (admin_style_test pins the pair). */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
/* A hairline between things in a cluster. */
.rule-y { width: 1px; height: 1.4rem; background: var(--bd); flex: none; }
/* Thin scrollbars on the console's own scroll regions. */
.scroll-thin { scrollbar-width: thin; scrollbar-color: var(--line-ctl) transparent; }

/* ═══════════════════════════════════════════════════════════════════════
   Block
   ═══════════════════════════════════════════════════════════════════════ */

/* ── topbar ── */
.topbar { flex: none; padding: 0.85rem var(--space-2xl); background: var(--pane); border-bottom: 1px solid var(--bd); }
.topbar .title { color: var(--bright); font-weight: 600; }
.topbar .title a { color: var(--bright); }
.topbar .title .ph { color: var(--dim); margin-right: 6px; }
.topbar .clock { color: var(--dim); font-size: 0.92rem; white-space: nowrap; }
.topbar form { margin: 0; }
.topbar form button { padding: 0.25rem 0.7rem; font-size: var(--step--1); }

/* ── nav ── */
.nav { width: var(--nav-width); padding: 1.23rem var(--space-m) var(--space-l); background: var(--pane);
  border-right: 1px solid var(--bd); overflow-y: auto; display: flex; flex-direction: column; gap: 1.54rem;
  scrollbar-width: thin; scrollbar-color: var(--line-ctl) transparent; }
.nav .group { display: flex; flex-direction: column; gap: 4px; }
.nav .group > .kicker-s { padding: 0 var(--space-m); margin-bottom: var(--space-xs); color: var(--mut); letter-spacing: 0.1em; }
.nav a { display: flex; align-items: center; gap: 0.7rem; padding: 0.54rem var(--space-m); border-radius: 6px;
  color: var(--txt); font-size: 0.96rem; white-space: nowrap; }
.nav a .ph { font-size: 1.12em; color: var(--dim); flex: none; }
.nav a[aria-current="page"] { background: var(--acc-tint); color: var(--acc); }
.nav a[aria-current="page"] .ph { color: var(--acc); }
@media (hover: hover) and (pointer: fine) {
  .nav a:hover { background: var(--hov); text-decoration: none; }
  .nav a[aria-current="page"]:hover { background: var(--acc-tint); }
}
/* Narrow: a horizontal rail under the topbar. */
@media (max-width: 840px) {
  .nav { width: auto; flex-direction: row; align-items: center; gap: 2px; padding: 8px 10px;
    border-right: 0; border-bottom: 1px solid var(--bd); overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
  .nav::-webkit-scrollbar { display: none; }
  .nav .group { display: contents; }
  .nav .group > .kicker-s { display: none; }
  .nav a { flex: none; padding: 0.54rem 0.92rem; }
}

/* ── main: the page's scroll port ──
   position:relative is load-bearing: a visually-hidden label is absolutely
   positioned, and without a positioned scroll port it resolves against the
   initial containing block, escapes this scroller, and grows the document's
   overflow — the whole shell then scrolled off the top. */
.main { position: relative; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line-ctl) transparent; }

/* ── page-head ── */
.page-head { --flow-space: 4px; margin-bottom: var(--space-2xl); }
.page-head .kicker-s { color: var(--mut); letter-spacing: 0.1em; }
.page-head .kicker-s a { color: var(--mut); }
.page-head h1 { font-size: var(--step-3); font-weight: 600; color: var(--bright); }
.page-head .sub { font-size: 0.92rem; color: var(--dim); }
.page-head .sub b { color: var(--bright); }

/* ── tabs: one row of tabs under a page head, the selected one underlined
   in the accent. State is aria-selected, which is the exception hook. ── */
.tabs { display: flex; gap: 2px; margin-bottom: var(--space-l); border-bottom: 1px solid var(--bd); }
.tabs [role="tab"] { min-height: 2.31rem; margin-bottom: -1px; padding: 0.4em 1em; border: 0; border-bottom: 2px solid transparent;
  border-radius: 0; background: transparent; color: var(--dim); }
.tabs [role="tab"][aria-selected="true"] { color: var(--acc); border-bottom-color: var(--acc); }
@media (hover: hover) and (pointer: fine) { .tabs [role="tab"]:not([aria-selected="true"]):hover { background: transparent; color: var(--bright); } }
@media (pointer: coarse) { .tabs [role="tab"] { min-height: var(--touch); } }

/* ── health: the verdict band. A hairline mosaic — each cell draws its own
   left rule and the -1px shift clips the outer one, whatever the count. ── */
.health { display: flex; flex-wrap: wrap; margin-left: -1px; }
.health .cell { flex: 1 1 13rem; min-width: 0; padding: var(--space-l) 1.23rem 1rem; border-left: 1px solid var(--bd-soft); }
.health .cell .value { display: flex; align-items: center; gap: var(--space-s); margin-top: 0.54rem; font-size: var(--step-1); color: var(--bright); }
.health .cell .note { margin-top: 4px; font-size: var(--step--1); color: var(--dim); overflow-wrap: break-word; }
.health .cell[data-role="verdict"] { flex: 2 1 21rem; }
.health .cell[data-role="verdict"] .value { font-size: var(--step-2); }
.health .cell[data-role="verdict"] .led { width: 0.77rem; height: 0.77rem; }
/* Tone paints the word and its LED together: a red word beside a grey LED
   reads as a half-repainted cell. */
.health .cell[data-tone="ok"] .value { color: var(--ok); }
.health .cell[data-tone="ok"] .led { background: var(--ok); }
.health .cell[data-tone="warn"] .value { color: var(--warn); }
.health .cell[data-tone="warn"] .led { background: var(--warn); }
.health .cell[data-tone="err"] .value { color: var(--err); }
.health .cell[data-tone="err"] .led { background: var(--err); }

/* ── card: one reading ── */
.card { padding: 1rem 1.15rem var(--space-xl); background: var(--pane); border: 1px solid var(--bd); border-radius: var(--radius-m); }
.card .head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.card .head .ph { font-size: var(--step-1); color: var(--mut); }
.card .value { display: block; margin: var(--space-s) 0 3px; font-size: var(--step-5); font-weight: 600; color: var(--bright); font-variant-numeric: tabular-nums; }
.card .value[data-text] { font-size: var(--step-3); padding: var(--space-2xs) 0 var(--space-3xs); }
/* Wraps, never ellipses: the sub is where the reading lives. */
.card .sub { font-size: 0.88rem; color: var(--dim); overflow-wrap: break-word; }
.card[data-tone="ok"] .value, .card[data-tone="ok"] .head .ph { color: var(--ok); }
.card[data-tone="live"] .value, .card[data-tone="live"] .head .ph { color: var(--warn); }
.card[data-tone="warn"] .value, .card[data-tone="warn"] .head .ph { color: var(--err); }
.card[data-tone="muted"] .value { color: var(--dim); }

/* ── panel: a bordered section with a titled head ── */
.panel { display: flex; flex-direction: column; min-width: 0; overflow: hidden;
  background: var(--pane); border: 1px solid var(--bd); border-radius: var(--radius-m); }
.panel > .head { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-s); padding: 0.7rem var(--space-xl);
  min-height: 3.23rem; border-bottom: 1px solid var(--bd); flex: none; }
.panel > .head > .ph { color: var(--dim); font-size: 1rem; }
.panel > .head .note { margin-left: auto; font-size: var(--step--1); color: var(--dim); white-space: nowrap; }
.panel > .head .note + .link { margin-left: var(--space-xl); }
.panel > .head .link { margin-left: auto; font-size: 0.88rem; white-space: nowrap; }
.panel > .head .filter { display: inline-flex; align-items: center; padding: 0.15em 0.7em; border-radius: var(--radius-pill);
  background: var(--mut-tint); font-size: var(--step--1); color: var(--dim); }
.panel > .body { flex: 1; min-height: 0; }
/* The reference's little (i): a real button with a real tooltip. */
.panel .info { display: grid; place-items: center; width: 1.15rem; height: 1.15rem; min-height: 0; padding: 0;
  border: 1px solid var(--bd); border-radius: 50%; background: transparent; color: var(--mut); font-size: 0.68rem; line-height: 1; cursor: help; }
.panel[data-variant="danger"] { border-color: var(--line-err); }
.panel[data-variant="danger"] > .head { border-bottom: 0; }
.panel[data-variant="danger"] > .head > .ph, .panel[data-variant="danger"] > .head > .kicker { color: var(--err); }
/* A panel whose body is a scrolling list (a run history, a log) takes a
   fixed height wherever the page does not fill the viewport. flex:none is
   load-bearing: a body with flex:1 has a zero flex-basis, and in a panel
   with no height of its own that basis beats the height and the body
   collapses to its content. Inside a filling page the body fills instead. */
.panel[data-scroll] > .body, .panel[data-scroll] > .log { flex: none; height: var(--panel-height, 30rem); overflow: auto; }
@media (max-width: 840px) { .panel[data-scroll] > .body, .panel[data-scroll] > .log { height: 23rem; } }
@media (min-width: 1021px) {
  .fill .panel[data-scroll] > .body, .fill .panel[data-scroll] > .log { flex: 1; height: auto; min-height: 0; }
}

/* ── led ── */
.led { flex: none; display: inline-block; width: 0.62rem; height: 0.62rem; border-radius: 50%; background: var(--line-ctl); }
.led[data-state="running"] { background: var(--warn); animation: ledpulse 1.2s ease-in-out infinite; }
.led[data-state="ok"] { background: var(--ok); }
.led[data-state="error"] { background: var(--err); }
.led[data-state="aborted"] { background: var(--mut); }
.led[data-state="disabled"] { background: transparent; box-shadow: inset 0 0 0 1.5px var(--mut); }
@keyframes ledpulse { 50% { opacity: 0.3; } }

/* ── pill: a tinted word with a hue ── */
.pill { display: inline-flex; align-items: center; gap: 0.46em; padding: 0.15em 0.7em 0.15em 0.54em;
  border-radius: var(--radius-pill); font-size: var(--step--1); color: var(--dim); background: var(--mut-tint); }
.pill[data-tone="ok"] { color: var(--ok); background: var(--ok-tint); }
.pill[data-tone="running"] { color: var(--warn); background: var(--warn-tint); }
.pill[data-tone="error"] { color: var(--err); background: var(--err-tint); }

/* ── status-mark: a crawler's state as a glyph in a fixed box, so a change
   repaints in place instead of reflowing the column; the word is the
   accessible name. ── */
.status-mark { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 1.55rem; color: var(--dim); }
.status-mark .ph { font-size: 1.05rem; }
.status-mark[data-state="ok"] { color: var(--ok); }
.status-mark[data-state="running"] { color: var(--warn); }
.status-mark[data-state="running"] .ph { animation: ledpulse 1.2s ease-in-out infinite; }
.status-mark[data-state="error"] { color: var(--err); }

/* ── button variants ── */
button[data-variant="run"]:not([disabled]) { background: var(--acc-tint); border-color: var(--line-acc); color: var(--acc); }
button[data-variant="danger"] { background: var(--err-tint); border-color: var(--line-err); color: var(--err); }
button[data-variant="quiet"] { background: transparent; }
button[data-variant="bare"] { min-height: 0; padding: 0; border: 0; background: transparent; color: var(--dim); }
button[data-size="s"] { min-height: 2rem; padding: 0.15em 0.77em; }
@media (hover: hover) and (pointer: fine) {
  button[data-variant="run"]:not([disabled]):hover { background: var(--acc-tint-hi); }
  button[data-variant="danger"]:not([disabled]):hover { background: var(--err-tint-hi); }
  button[data-variant="bare"]:hover { background: transparent; color: var(--bright); }
}
@media (pointer: coarse) { button[data-size="s"] { min-height: var(--touch); } }

/* ── chip: a toggle in a row of them ── */
.chips { display: flex; gap: 4px; }
.chip { min-height: 2rem; padding: 0.15em 0.77em; }
.chip[aria-pressed="true"] { color: var(--bright); border-color: var(--line-ctl-hi); background: var(--hov); }
.chip[data-level="warn"][aria-pressed="true"] { color: var(--warn); }
.chip[data-level="error"][aria-pressed="true"] { color: var(--err); }
@media (pointer: coarse) { .chip { min-height: var(--touch); } }

/* ── table ── */
.table { width: 100%; font-size: 0.96rem; }
.table th { padding: var(--space-s); border-bottom: 1px solid var(--bd); text-align: left; white-space: nowrap;
  color: var(--dim); font-weight: 400; font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.06em; }
.table td { padding: var(--space-s); border-bottom: 1px solid var(--bd-soft); vertical-align: middle; white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.table th:first-child, .table td:first-child { padding-left: var(--space-xl); }
.table th:last-child, .table td:last-child { padding-right: var(--space-xl); }
.table tr:last-child > td { border-bottom: 0; }
.table .name { color: var(--bright); font-weight: 600; }
.table .name a { color: var(--bright); }
.table [data-numeric] { text-align: right; }
.table td[data-tone="warn"] { color: var(--warn); }
.table td[data-tone="err"] { color: var(--err); }
/* The first column absorbs the slack, and gives it back: max-width:0 lets
   the cell shrink under its content and truncate, so a long name or a
   wide reading ("on schedule check" beside dates) never pushes the
   actions past the panel; the cell's title carries the whole name. */
.table[data-lead] th:first-child { width: 100%; }
.table[data-lead] td:first-child { max-width: 0; overflow: hidden; text-overflow: ellipsis; }
.table[data-lead] td:first-child > * { overflow: hidden; text-overflow: ellipsis; }
/* Under 1240px the row buttons keep their glyph and drop their word (the
   word stays as the tooltip and the accessible name), and the readings
   sit closer: what the actions and the gutters gave up, the name gets. */
@media (max-width: 1240px) {
  .table[data-lead] th:not(:first-child), .table[data-lead] td:not(:first-child) { padding-left: var(--space-l); }
  .table button .label { display: none; }
  .table button[data-size="s"] { padding-inline: 0.62em; }
}
.table[data-lead] th:not(:first-child), .table[data-lead] td:not(:first-child) { padding-left: 1.54rem; }
.table[data-compact] { font-size: 0.92rem; }
.table[data-compact] th, .table[data-compact] td { padding: var(--space-xs) var(--space-s); }
.table[data-compact] th { position: sticky; top: 0; background: var(--pane); }
.table[data-compact] td { vertical-align: top; }
.table td[data-wrap] { white-space: normal; overflow-wrap: break-word; min-width: 18ch; max-width: 40ch; }
.table tr[data-link] { cursor: pointer; }
.table tr[data-link] .name .ph { display: inline-block; transform: rotate(180deg); color: var(--mut); font-size: 0.85em; margin-right: 0.54em; }
@media (hover: hover) and (pointer: fine) { .table tr[data-link]:hover td { background: var(--hov); } }
.table [data-run="ok"] { color: var(--ok); }
.table [data-run="error"] { color: var(--err); }
.table [data-run="aborted"] { color: var(--dim); }
.table [data-run="running"] { color: var(--warn); }

/* ── log: newest first, scrolling inside its box ── */
.log { flex: 1; min-height: 0; overflow-y: auto; padding: var(--space-m) var(--space-xl); font-size: 0.92rem; line-height: 1.6;
  background: var(--term); overflow-wrap: break-word; scrollbar-width: thin; scrollbar-color: var(--line-ctl) transparent; }
.log::-webkit-scrollbar { width: 8px; }
.log::-webkit-scrollbar-thumb { background: var(--line-ctl); border-radius: 4px; }
.log .ts { color: var(--mut); }
.log .src { color: var(--acc); }
.log .line[data-level="warn"] { color: var(--warn); }
.log .line[data-level="error"] { color: var(--err); }
/* A line's request id: a chip at its end that scopes the pane to that
   request. Faint until hovered so the line still reads as prose. */
.log .req { font: inherit; color: var(--dim); background: none; border: 0; padding: 0; min-height: 0; cursor: pointer; }
.log .req:hover, .log .req:focus-visible { color: var(--acc); text-decoration: underline; }
.log[data-fixed] { flex: none; height: var(--log-height, 22rem); }

/* ── field: a labelled control with a hint ── */
.field label { display: block; margin-bottom: 6px; }
.field .controls { display: flex; gap: 8px; flex-wrap: wrap; }
.field .controls input { flex: 1; min-width: 220px; }
.field .hint { margin-top: 8px; font-size: 0.88rem; color: var(--dim); }
.field select { min-height: 2rem; padding: 0.15em 0.46em; font-size: 0.92rem; max-width: 16ch; }
@media (pointer: coarse) { .field select { font-size: 16px; min-height: var(--touch); } }

/* ── banner: an error the page leads with ── */
.banner { padding: 0.7rem 1rem; border: 1px solid #7d5c60; border-radius: var(--radius-m);
  background: var(--err-tint); color: var(--err); overflow-wrap: break-word; }
.banner .ph { margin-right: 0.46em; }

/* ── empty: what belongs in a list that has nothing yet ── */
.empty { display: flex; align-items: center; min-height: 5.4rem; padding: 0 var(--space-xl); color: var(--dim); line-height: 1.5; font-size: 0.88rem; }
.empty[data-tall] { min-height: 11rem; justify-content: center; text-align: center; }

/* ── danger: the console's irreversible actions. Prose left at a measure,
   the action right and centred against it. ── */
.danger { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: var(--space-xl) var(--space-4xl); padding: 0 var(--space-xl) var(--space-xl); }
.danger form { flex: none; margin: 0; }
.danger .text { --flow-space: var(--space-xs); max-width: 64ch; color: var(--mut); font-size: 0.92rem; line-height: 1.5; }
.danger .text b { color: var(--txt); font-weight: 400; }

/* ── group: a dashboard section's head — kicker, a line of context, a rule,
   the way into its page ── */
.group-head { display: flex; align-items: center; gap: var(--space-m); margin-bottom: 0.7rem; }
.group-head .context { font-size: var(--step--1); color: var(--mut); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.group-head .rule { flex: 1; height: 1px; background: var(--bd-soft); }
.group-head .link { font-size: 0.88rem; white-space: nowrap; }
@media (max-width: 600px) { .group-head .context { display: none; } }

/* ── strip: one column a day, height by count; a hairline mosaic, not a
   chart with axes ── */
.strip { display: grid; grid-template-columns: repeat(30, 1fr); gap: 3px; align-items: end; height: 4.6rem;
  padding: var(--space-xl) var(--space-xl) 0.4rem; }
.strip .bar { min-height: 2px; border-radius: 2px 2px 0 0; background: var(--acc); opacity: 0.85; }
.strip .bar[data-zero] { background: var(--bd); }
.strip .bar[data-today] { opacity: 1; }
.strip-axis { display: flex; justify-content: space-between; padding: 0 var(--space-xl) var(--space-l);
  font-size: var(--step--2); color: var(--mut); font-variant-numeric: tabular-nums; }

/* ── rows: label and note left, value and unit right, on hairlines ── */
.rows .row { display: flex; align-items: baseline; gap: var(--space-xl); padding: var(--space-m) var(--space-xl); border-bottom: 1px solid var(--bd-soft); }
.rows .row:last-child { border-bottom: 0; }
.rows .name { flex: 1; min-width: 0; }
.rows .name span { display: block; color: var(--bright); font-size: 0.96rem; }
.rows .name em { display: block; margin-top: 2px; color: var(--mut); font-size: var(--step--1); }
/* The value's note may be a path or a host with no break in it: it wraps
   anywhere rather than pushing the row wide, and the value keeps at most
   the right half of the row so the name is always readable. */
.rows .value { flex: 0 1 auto; min-width: 0; max-width: 55%; text-align: right; color: var(--bright); font-size: var(--step-1); font-variant-numeric: tabular-nums; }
.rows .value em { display: block; margin-top: 2px; color: var(--dim); font-size: var(--step--1); overflow-wrap: anywhere; }
.rows .row[data-tone="warn"] .value { color: var(--warn); }
.rows .row[data-tone="err"] .value { color: var(--err); }

/* ── accounts table extras ── */
.table .who { color: var(--bright); }
.table .who .led { width: 0.5rem; height: 0.5rem; margin-right: 0.55rem; vertical-align: middle; }
.table .mail { color: var(--dim); max-width: 22rem; overflow: hidden; text-overflow: ellipsis; }
.table .when { color: var(--dim); }
.table .actions form { display: inline-flex; gap: 0.35rem; align-items: center; margin: 0 0.5rem 0 0; }
/* The field is the same height as the small button beside it (2rem, the touch size on a coarse pointer): one control, not a field under a taller button. */
.table .actions input[type=number] { box-sizing: border-box; height: 2rem; width: 4.2rem; padding: 0 0.4rem; font-size: max(16px, 0.88rem); background: transparent; color: var(--txt); border: 1px solid var(--bd); border-radius: var(--radius-s); }
@media (pointer: coarse) { .table .actions input[type=number] { height: var(--touch); } }

/* ── kpi: a reading, the fortnight behind it, and how it compares ── */
.kpi { display: flex; flex-direction: column; padding: var(--space-l) var(--space-xl) 0;
  border: 1px solid var(--bd); border-radius: var(--radius-l); background: var(--pane); }
.kpi .top { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.kpi .value { display: flex; align-items: baseline; gap: 0.46em; margin: 0.85rem 0 1rem; line-height: 1.05;
  font-size: 1.85rem; font-weight: 600; color: var(--bright); font-variant-numeric: tabular-nums; }
.kpi .unit { font-size: 0.82rem; font-weight: 400; color: var(--dim); white-space: nowrap; }
.kpi .foot { display: flex; align-items: center; gap: 0.7rem; margin-top: auto; padding: var(--space-s) 0 0.7rem; border-top: 1px solid var(--bd); }
.kpi .delta { font-size: var(--step--1); color: var(--dim); font-variant-numeric: tabular-nums; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kpi .delta[data-dir="up"] b { color: var(--ok); }
.kpi .delta[data-dir="down"] b { color: var(--err); }
/* The sparkline: the last bar is today and carries the accent. */
.spark { flex: none; display: flex; align-items: flex-end; gap: 2px; height: 2.46rem; }
.spark i { display: block; width: 4px; min-height: 2px; border-radius: 2px; background: var(--bd); }
.spark i[data-today] { background: var(--acc); }

/* ── seg: the window switch, one control so there is one answer to "what
   period is this page showing" ── */
.seg { display: inline-flex; align-items: center; gap: 2px; padding: 3px; border: 1px solid var(--bd); border-radius: var(--radius-pill); background: var(--pane); }
.seg a, .seg button { display: inline-flex; align-items: center; justify-content: center; min-height: 2rem; padding: 0 0.85em;
  border: 0; border-radius: var(--radius-pill); background: transparent; color: var(--dim); font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.seg [aria-current] { background: var(--hov); color: var(--bright); }
@media (hover: hover) and (pointer: fine) {
  .seg a:hover, .seg button:hover { color: var(--bright); text-decoration: none; }
  .seg [aria-current]:hover { background: var(--hov); }
}
/* A read-only pill beside it: the range the window resolves to. Same
   height as the seg, so the two read as one row. */
.range { display: inline-flex; align-items: center; gap: 0.5em; min-height: calc(2rem + 6px); padding: 0 0.85em;
  border: 1px solid var(--bd); border-radius: var(--radius-m); background: var(--pane); color: var(--txt);
  font-size: 0.88rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.range .ph { color: var(--mut); }
/* The same-hour comparison on the subline: the sign carries the direction. */
.hour-delta { margin-left: 0.7em; font-size: 0.88rem; font-variant-numeric: tabular-nums; color: var(--dim); }
.hour-delta[data-dir="up"] { color: var(--ok); }
.hour-delta[data-dir="down"] { color: var(--err); }
.hour-delta em { color: var(--dim); margin-left: 0.4em; }
@media (pointer: coarse) {
  .seg a, .seg button { min-height: var(--touch); }
  .range { min-height: calc(var(--touch) + 6px); }
}
@media (max-width: 600px) {
  .hour-delta { display: block; margin-left: 0; margin-top: var(--space-3xs); }
  .seg { width: 100%; }
  .seg a, .seg button { flex: 1 1 0; font-size: 0.96rem; }
  .range { flex-basis: 100%; justify-content: center; font-size: var(--step--1); min-height: 0; padding: 0; border: 0; background: none; color: var(--dim); }
}

/* ── feed: the live requests table. A fixed height that scrolls inside
   itself, so the panels below never move as rows land; the head stays
   while the rows move under it. The heights are stated on the cells so the
   arithmetic is exact at any point of the type scale. ── */
.feed { position: relative; --rowh: 2.93rem; --headh: 2.1rem; --vis: 10; }
.feed .toolbar { display: flex; align-items: center; gap: var(--space-s); padding: var(--space-l) var(--space-xl) 0.85rem; flex-wrap: wrap; }
.feed .search { position: relative; display: flex; min-width: 9rem; }
.feed .search input { width: 100%; min-width: 0; }
.feed .search .clear { position: absolute; right: var(--space-2xs); top: 50%; transform: translateY(-50%); min-height: 1.85rem; padding: 0 0.62em; font-size: 0.92rem; }
.feed .scroller { height: calc(var(--vis) * (var(--rowh) + 1px) + var(--headh) + 1px); overflow-y: auto; overscroll-behavior: contain;
  overflow-anchor: none; border-top: 1px solid var(--bd); border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; scrollbar-color: auto; }
.feed .scroller::-webkit-scrollbar { width: 10px; height: 10px; }
.feed .scroller::-webkit-scrollbar-track { background: transparent; margin-top: calc(var(--headh) + 1px); margin-bottom: 6px; }
.feed .scroller::-webkit-scrollbar-thumb { background: var(--line-ctl); border-radius: 5px; border: 2px solid transparent; background-clip: padding-box; }
.feed .scroller::-webkit-scrollbar-corner { background: transparent; }
@supports not selector(::-webkit-scrollbar) { .feed .scroller { scrollbar-width: thin; scrollbar-color: var(--line-ctl) transparent; } }
.feed table { width: 100%; font-size: 0.88rem; }
.feed th { height: var(--headh); position: sticky; top: 0; z-index: 1; padding: 0.54rem 0.85rem; background: var(--pane);
  border-bottom: 1px solid transparent; text-align: left; font-size: var(--step--3); font-weight: 400; text-transform: uppercase;
  letter-spacing: var(--kicker-track); color: var(--mut); white-space: nowrap; }
/* The head's hairline is drawn once by the box, spanning the panel. */
.feed .scroller::after { content: ""; position: absolute; left: 0; right: 0; top: var(--headh); height: 1px; background: var(--bd); pointer-events: none; z-index: 2; }
.feed .scroller { position: relative; }
.feed td { height: var(--rowh); padding: 0.54rem 0.85rem; border-bottom: 1px solid var(--bd-soft); vertical-align: middle; white-space: nowrap; }
.feed th:first-child, .feed td:first-child { padding-left: var(--space-xl); }
.feed th:last-child, .feed td:last-child { padding-right: var(--space-xl); }
.feed tr:last-child td { border-bottom: 0; }
.feed .time { color: var(--dim); font-variant-numeric: tabular-nums; }
.feed .path { max-width: 34rem; overflow: hidden; text-overflow: ellipsis; color: var(--bright); }
.feed .path .method { color: var(--mut); margin-right: 0.46em; }
.feed .ip { font-variant-numeric: tabular-nums; }
.feed .ua { max-width: 22rem; overflow: hidden; text-overflow: ellipsis; color: var(--dim); }
.feed .ref { color: var(--dim); }
.feed .type { width: 2.8rem; text-align: center; }
.feed .mark { font-size: var(--step-1); line-height: 1; }
.feed .mark[data-kind="person"] { color: var(--ok); }
.feed .mark[data-kind="bot"] { color: var(--warn); }
.feed .status { font-variant-numeric: tabular-nums; color: var(--dim); }
.feed .status[data-class="3"] { color: var(--acc); }
.feed .status[data-class="4"] { color: var(--warn); }
.feed .status[data-class="5"] { color: var(--err); }
.feed .open { display: inline-grid; place-items: center; width: 1.85rem; height: 1.85rem; border-radius: 6px; color: var(--mut); }
.feed td:last-child { text-align: right; }
/* A crawler's row is dimmed as well as marked: during a sweep they are the
   majority, and a person still has to be findable among them. */
.feed tr[data-bot] { color: var(--mut); }
.feed tr[data-bot] .path { color: var(--txt); }
.feed .empty[data-tall] { min-height: calc(var(--vis) * (var(--rowh) + 1px)); }
@media (hover: hover) and (pointer: fine) { .feed .open:hover { color: var(--acc); background: var(--hov); text-decoration: none; } }
@media (pointer: coarse) { .feed { --rowh: calc(var(--touch) + 1.08rem); --vis: 6; } .feed .open { width: var(--touch); min-height: var(--touch); } }

/* ── rank: a ranked list with a share track — the same row for a page, a
   search and a referrer, because they are the same question ── */
.rank { padding: 0 var(--space-l) var(--space-l); }
.rank .row { display: grid; grid-template-columns: 1.4rem minmax(0, 1fr) auto; gap: var(--space-2xs) 0.7rem; align-items: baseline;
  padding: 0.42rem 0; border-top: 1px solid var(--bd-soft); }
.rank .row:first-child { border-top: 0; }
.rank .row[data-read] { grid-template-columns: 1.4rem minmax(0, 1fr) auto auto; }
.rank .n { font-size: var(--step--2); color: var(--mut); font-variant-numeric: tabular-nums; }
.rank .name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--bright); }
.rank .count { font-size: 0.88rem; color: var(--dim); font-variant-numeric: tabular-nums; }
.rank .read { font-size: var(--step--2); color: var(--mut); font-variant-numeric: tabular-nums; }
.rank .track { grid-column: 2 / -1; height: 3px; border-radius: 2px; background: var(--bd-soft); overflow: hidden; }
.rank .track i { display: block; height: 100%; background: var(--acc); border-radius: 2px; }
.rank .subgroup + .subgroup, .rank .row + .subgroup { margin-top: 0.85rem; padding-top: var(--space-s); border-top: 1px solid var(--bd); }
.rank .subhead { display: flex; align-items: baseline; justify-content: space-between; gap: 0.7rem; margin-bottom: var(--space-2xs);
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: var(--kicker-track); color: var(--mut); }
.rank .subhead em { font-variant-numeric: tabular-nums; }
/* A dimension is a column of a bounded width: with the panel spanning the page, 1fr columns
   stretched four dimensions to 27rem each and every name sat over a bar longer than the row. */
.rank .dimensions { display: grid; gap: 1.15rem 2.5rem; grid-template-columns: repeat(auto-fill, minmax(13rem, 19rem)); padding-top: var(--space-s); }
.rank .dimensions .subgroup { min-width: 0; margin: 0; padding: 0; border: 0; }

/* ── popover: the counting notes, anchored under their trigger ── */
.help-button { width: 1.85rem; height: 1.85rem; min-height: 0; padding: 0; border-radius: 50%; font-size: 0.96rem; }
.help-button[aria-expanded="true"] { background: var(--acc-tint); border-color: var(--line-acc); color: var(--acc); }
@media (pointer: coarse) {
  .help-button { width: 32px; height: 32px; position: relative; }
  .help-button::after { content: ""; position: absolute; inset: -6px; border-radius: 50%; }
}
.popover { position: fixed; top: 7.4rem; left: auto; right: auto; bottom: auto; margin: 0; padding: 0;
  width: min(48rem, calc(100vw - 3.4rem)); max-height: calc(100dvh - 6.4rem); overflow: hidden; flex-direction: column;
  background: var(--pane); border: 1px solid var(--bd); border-radius: var(--radius-l); color: var(--txt);
  box-shadow: 0 1.4rem 3.4rem rgba(0, 0, 0, 0.45); }
.popover:popover-open { display: flex; }
.popover::backdrop { background: rgba(0, 0, 0, 0.4); }
.popover[data-fallback][data-open] { display: flex; }
.popover .head { display: flex; align-items: center; gap: var(--space-l); flex: none; padding: 0.85rem var(--space-l) 0.85rem 1.15rem; border-bottom: 1px solid var(--bd); }
.popover .head .kicker-s { flex: 1; }
.popover .close { width: 2rem; height: 2rem; min-height: 0; padding: 0; border: 1px solid var(--bd); border-radius: 50%; background: transparent; color: var(--dim); font-size: var(--step-1); line-height: 1; }
.popover .body { --flow-space: var(--space-l); padding: var(--space-2xs) 1.15rem 1.15rem; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line-ctl) transparent; }
.popover .body p { color: var(--dim); font-size: 0.88rem; max-width: 72ch; line-height: 1.65; }
.popover .body b { color: var(--txt); }
@media (pointer: coarse) { .popover .close { width: var(--touch); height: var(--touch); } }
@media (max-width: 700px) { .popover { top: auto; bottom: 1rem; right: 1rem; left: 1rem; width: auto; max-height: 76dvh; } }

/* ── skeleton: a page's shape before its payload lands. A bone is the
   ground a value will occupy, pulsing softly, and it sits inside the
   element whose text it stands for: shorter than the line and centred on
   it, so the line box, and with it every height, is the real one. ── */
.skeleton { pointer-events: none; }
/* span.bone, not .bone: a block's rule for the spans it holds (.rows .name span) would
   otherwise take the bone with it and put it on a line of its own. */
.skeleton span.bone { display: inline-block; max-width: 100%; height: 0.72em; vertical-align: middle; border-radius: 4px;
  background: var(--bd-soft); animation: bone 1.4s ease-in-out infinite; }
.skeleton .tabs { border-bottom-color: var(--bd); }
.skeleton .tabs [role="tab"] { background: transparent; }
.skeleton .track { display: block; }
.skeleton .strip .bar { height: 0; }
@keyframes bone { 50% { opacity: 0.45; } }

/* ── signin: the only thing on its page ── */
.signin { min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 1.5rem; }
.signin .panel { width: min(24rem, 100%); padding: var(--space-2xl) 1.5rem 1.5rem; text-align: center; --flow-space: var(--space-xl); }
.signin h1 { font-size: 1.15rem; color: var(--bright); }
.signin p { font-size: 0.92rem; color: var(--dim); }
.signin .error { padding: 0.55rem 0.7rem; border-radius: 7px; background: var(--err-tint); color: var(--err); font-size: 0.9rem; }
.signin .go { display: inline-flex; align-items: center; gap: 0.46em; padding: 0.6rem 1.1rem; border-radius: var(--radius-m);
  background: var(--acc); color: var(--on-acc); font-weight: 600; }

/* ═══════════════════════════════════════════════════════════════════════
   Exception
   Most exceptions sit beside their block above, as data attributes. The
   one every block shares is the change flash, which script sets and
   re-arms.
   ═══════════════════════════════════════════════════════════════════════ */
/* A value that moved on the wire pulses once; a repaint that produced the
   same number never sets the attribute. The block form pulses ground and
   border together, for a card whose number barely moved any pixels. */
[data-flash="text"] { animation: flash-text 400ms ease-out; border-radius: 4px; }
[data-flash="box"] { animation: flash-box 700ms ease-out; }
@keyframes flash-text { from { background-color: var(--acc-tint); } }
@keyframes flash-box { from { background-color: var(--acc-tint); border-color: var(--line-acc); } }
