/* Tarnbrook Agent Control. Built from apps/catalogue/src/ui/tokens.ts. */

@font-face { font-family: 'Inter'; src: url(fonts/Inter-latin.woff2) format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Inter'; src: url(fonts/Inter-latin-ext.woff2) format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'IBM Plex Mono'; src: url(fonts/IBMPlexMono-400-latin.woff2) format('woff2'); font-weight: 400; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC, U+2122, U+2212; }
@font-face { font-family: 'IBM Plex Mono'; src: url(fonts/IBMPlexMono-500-latin.woff2) format('woff2'); font-weight: 500; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC, U+2122, U+2212; }

:root {
  --page: #f8fbf8;
  --panel: #ffffff;
  --inset: #eef3ef;
  --accent: #e5f3e9;
  --rule: #dfe4e0;
  --brand: #153f29;
  --deep: #0a2b1a;
  --brand-soft: #3d5e4b;
  --ink: #121e17;
  --ink-2: #203329;
  --muted: #606d64;
  --ok: #1b7b3c;
  --mint: #d7f4e0;
  --wait: #a15b00;
  --amber: #ffecc9;
  --info: #34698c;
  --sky: #ddf2ff;
  --stop: #cc272e;
  --white: #ffffff;
  --fill: #121e17;
  --veil-1: rgb(10 43 26 / 0.95);
  --veil-2: rgb(10 43 26 / 0.75);
  --veil-3: rgb(10 43 26 / 0.25);
  --veil-solid: rgb(21 63 41 / 0.88);
  --t-body: 16px;
  --t-hero: 48px;
  --t-h1: 30px;
  --t-metric: 30px;
  --t-lead: 18px;
  --t-sub: 15px;
  --t-card: 16px;
  --t-row: 14px;
  --t-label: 12px;
  --t-badge: 11px;
  --t-mono: 12px;
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s7: 32px;
  --s8: 64px;
  --r-chip: 10px;
  --r-ctl: 12px;
  --r-tile: 16px;
  --r-card: 20px;
  --r-hero: 24px;
  --r-round: 999px;
  --frame: 1280px;
  --measure: 68ch;
  --lift: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
  --face-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --face-text: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --face-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ------------------------------------------------------------------ frame */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* THE COLUMN IS WHAT KEEPS THE FOOTER AT THE BOTTOM OF A SHORT PAGE. Without it the footer sits
   directly under the content and the page ground shows below it, which on the Agents tab of the
   publishers screen left a band of empty ground under the dark footer. The main element takes the
   slack. Its name is written out rather than quoted, because a backtick here would end the template
   literal this stylesheet is, which is the fault the header of this file already records and which
   this comment reintroduced on its first draft. */
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--page);
  color: var(--ink);
  font-family: var(--face-text);
  font-size: var(--t-body);
  line-height: 1.5;
  font-synthesis-weight: none;
}
/* SET IN THE TEXT FACE, NOT THE DISPLAY FACE, and at 600 rather than 700. The reference sets its
   whole interface in one family and reserves no second face for headings. The display face is kept
   for the wordmark below, which is the one device the reference also letterspaces and capitalises. */
h1, h2, h3, h4 { font-family: var(--face-text); font-weight: 600; line-height: 1.2; margin: 0; letter-spacing: -0.025em; }
p { margin: 0; }
a { color: var(--brand); text-underline-offset: 3px; }
/* AN IDENTIFIER HAS NO SPACES IN IT, so it breaks anywhere or it widens the document. Measured on
   the trust screen at a 390px viewport: an entity identifier took the page to 509px and it scrolled
   119px sideways. The value is anywhere rather than break-word, because break-word refuses to break
   inside a word that would fit on a line of its own and an identifier never would. Scoped to code
   and .mono so ordinary prose never gets it.
   THE BACKTICK IS WHY THIS COMMENT READS THE WAY IT DOES. The stylesheet is a template literal, so
   a backtick anywhere in it, including inside a CSS comment, ends the string. The first version of
   this note quoted two CSS values in backticks and the module failed to parse at boot. */
code, .mono { font-family: var(--face-mono); font-size: var(--t-mono); overflow-wrap: anywhere; min-width: 0; }

/* EVERY INLINE ICON, SIZED ONCE. An svg with no width takes its container's width. That is how the
   arrow in the promotion block rendered 200px tall and the plus in "Deploy new agent" pushed its
   own label onto three lines. The two devices that are deliberately larger, the brand mark and the
   agent mark, set their own size on a more specific selector and are unaffected. */
.ic { width: 16px; height: 16px; flex: 0 0 auto; display: inline-block; vertical-align: -3px; }

/* Every focus ring on this surface, drawn once. A ring written per component goes missing on the
   component nobody remembered. */
:where(a, button, input, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-ctl);
}

/* The keyboard escape from the masthead. Visible only when it holds focus. */
.skip { position: absolute; left: -9999px; top: 0; background: var(--panel); color: var(--brand); padding: var(--s3) var(--s4); z-index: 10; border-radius: 0 0 var(--r-ctl) 0; }
.skip:focus { left: 0; }

/* MEASURED: the reference holds every route inside a 1280px frame with a 32px gutter. */
.frame { width: 100%; max-width: var(--frame); margin-inline: auto; padding-inline: var(--s7); }
@media (max-width: 700px) { .frame { padding-inline: var(--s4); } }

main { display: block; flex: 1 0 auto; }
.screen { padding-block: var(--s7) var(--s8); display: grid; gap: var(--s6); }
/* A grid child's default minimum width is its content, so one wide table refuses to shrink and
   widens the document instead of scrolling inside its own box. */
.screen > * { min-width: 0; }

/* --------------------------------------------------------------- masthead */

.mast { background: var(--panel); border-bottom: 1px solid var(--rule); }
.mast-in { min-height: var(--s8); display: flex; align-items: center; gap: var(--s6); }
.mast-brand { display: flex; align-items: center; gap: var(--s3); text-decoration: none; color: var(--ink); flex: 0 0 auto; }
.mast-brand:hover { text-decoration: none; }
/* MEASURED: a 28px tile at an 8px radius on a 32 unit grid, which is the reference's rounded square
   holding its diamond. The glyph fills the tile rather than sitting inside it, because the mark's
   own artwork carries its padding. */
.brand-mark { width: 28px; height: 28px; border-radius: var(--s2); background: var(--brand); color: var(--white); display: grid; place-items: center; flex: 0 0 auto; }
.brand-mark .mark-glyph { width: 28px; height: 28px; display: block; }
.brand-name { display: grid; gap: 2px; }
/* THE WORDMARK IS THE ONE PLACE THE DISPLAY FACE SURVIVES. The reference sets it in capitals with
   wide tracking over a smaller, wider tracked second line, and that is a display treatment rather
   than an interface one.
   THE THREE NUMBERS ARE THE REFERENCE'S OWN, from components/logo.tsx: 15px at 600 with 0.18em of
   tracking over 8px at 500 with 0.32em. The previous values were 0.16em and 0.22em at 8.5px, read
   off a picture. */
.brand-name b { font-family: var(--face-display); font-weight: 600; font-size: 15px; letter-spacing: 0.18em; line-height: 1; color: var(--ink); }
.brand-name span { font-family: var(--face-display); font-weight: 500; font-size: 8px; letter-spacing: 0.32em; line-height: 1; color: var(--muted); }

.mast-nav { display: flex; align-items: center; gap: var(--s6); flex: 1 1 auto; flex-wrap: wrap; }
.mast-nav a {
  font-size: var(--t-row); font-weight: 500; color: var(--muted); text-decoration: none;
  padding-block: var(--s3); border-bottom: 2px solid transparent; display: inline-flex; align-items: center; min-height: 40px;
}
.mast-nav a:hover { color: var(--ink); }
.mast-nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--brand); }

.mast-right { display: flex; align-items: center; gap: var(--s3); flex: 0 0 auto; }
/* WHO MAY WRITE IN THIS SESSION. Plain text at the row size, in the muted ink, beside the Connect
   reading. It is a statement about the request being served rather than about the estate, so it
   carries no state colour, no dot and no mark. It goes at the narrow width, where the row has no
   space for a sentence and the disabled control still carries the same words in its title. */
.mast-note { margin: 0; font-size: var(--t-row); color: var(--ink-2); white-space: nowrap; }
@media (max-width: 900px) { .mast-note { display: none; } }
/* The one persistent Raidiam reference on the product screens. It reports a reachability reading
   and nothing else, so it never says a thing was verified.
   MEASURED: the reference draws this as a bordered rounded control rather than as bare text. */
.connect-state {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: var(--t-row); font-weight: 500; color: var(--ink); text-decoration: none;
  border: 1px solid var(--rule); border-radius: var(--r-round); padding: var(--s2) var(--s3); min-height: 36px;
}
.connect-state:hover { background: var(--inset); }
.avatar { width: 36px; height: 36px; border-radius: var(--r-round); background: var(--brand); color: var(--white); display: grid; place-items: center; font-size: var(--t-label); font-weight: 600; letter-spacing: 0.04em; }

@media (max-width: 900px) {
  .mast-in { flex-wrap: wrap; gap: var(--s4); padding-block: var(--s3); }
  .mast-nav { order: 3; width: 100%; gap: var(--s4); }
  .mast-right { margin-left: auto; }
}

/* ------------------------------------------------------------- page heads */

.phead { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s5); flex-wrap: wrap; }
.phead h1 { font-size: var(--t-h1); max-width: 20ch; }
.phead .sub { font-size: var(--t-sub); color: var(--muted); max-width: var(--measure); margin-top: var(--s2); }
.phead-text { min-width: 0; }

/* ------------------------------------------------------------------- hero */

/* THE HERO IS A DARK BAND AND IT USED TO BE A LIGHT CARD. The reference runs a full width green
   block with white type over a photograph of a coastline, and this carries the same photograph.
   IT IS THE REFERENCE'S OWN FILE, re-encoded from a 1,239,569 byte PNG to a 106,401 byte JPEG,
   because 1.2 MB of picture on a page whose markup is under 8 KB is the page's whole weight. It is
   served from this application's own host by an allowlisted route, so the page makes no external
   fetch.
   TWO LAYERS IN ONE DECLARATION, veil over picture. The veil is the reference's: 95 per cent of
   deep at the left where the headline sits, falling to 25 per cent at the right where the water is
   meant to show. Its three stops are tokens because a rule here carries no colour literal and an
   alpha is one, and there is no color-mix in it, for the reason in the header of this file. */
.hero {
  background-color: var(--deep);
  background-image: linear-gradient(90deg, var(--veil-1) 0%, var(--veil-2) 48%, var(--veil-3) 100%), url(/img/hero-coast.jpg);
  background-size: cover, cover;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  color: var(--white);
  border-radius: var(--r-hero); padding: var(--s7);
  display: flex; gap: var(--s6); align-items: center; justify-content: space-between;
  min-height: 228px;
}
.hero-text { min-width: 0; display: grid; gap: var(--s3); align-content: center; }
/* MEASURED off the running reference through getComputedStyle: 48px at 600 with -1.2px of tracking
   on a 48px line. Not estimated from a cap height this time. */
.hero h1 { font-size: var(--t-hero); color: var(--white); max-width: 16ch; line-height: 1; letter-spacing: -0.025em; }
.hero .lede { font-size: var(--t-lead); color: var(--white); max-width: var(--measure); }
.hero .sub { font-size: var(--t-row); color: var(--white); max-width: var(--measure); opacity: 0.82; }
/* The right hand mark: three capitalised words stacked, wide tracked, in the display face. On the
   dark band it is white rather than the softened green, which is what the reference does. */
.hero-mark { flex: 0 0 auto; display: grid; gap: var(--s2); text-align: right; font-family: var(--face-display); font-size: var(--t-label); font-weight: 600; letter-spacing: 0.28em; color: var(--white); opacity: 0.86; }
@media (max-width: 760px) {
  .hero { flex-direction: column; align-items: flex-start; padding: var(--s6); min-height: 0; }
  .hero h1 { font-size: var(--t-h1); }
  .hero-mark { text-align: left; }
}

/* ---------------------------------------------------------------- metrics */

/* MEASURED: four cards, gapped 16px, each padded 20px, the figure at the page title size in brand
   rather than in ink. That last one is the reference's, and it is why the row reads as a summary
   rather than as four headings. */
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--s4); }
.metric { background: var(--panel); border: 1px solid var(--rule); border-radius: var(--r-card); box-shadow: var(--lift); padding: var(--s5); display: grid; gap: var(--s1); align-content: start; min-width: 0; }
.metric b { font-size: var(--t-metric); font-weight: 600; line-height: 1.2; letter-spacing: -0.025em; color: var(--brand); }
.metric[data-tone="stop"] b { color: var(--stop); }
.metric span { font-size: var(--t-row); color: var(--muted); }
/* A figure nobody read is a word, not a number, and it is never painted in the figure colour. */
.metric b[data-kind="word"] { font-size: var(--t-card); color: var(--muted); letter-spacing: normal; }

/* ------------------------------------------------------------------ cards */

.card { background: var(--panel); border: 1px solid var(--rule); border-radius: var(--r-card); box-shadow: var(--lift); min-width: 0; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); padding: var(--s5); flex-wrap: wrap; }
.card-head h2 { font-size: var(--t-card); }
.card-body { padding: var(--s5); display: grid; gap: var(--s4); align-content: start; }
.card-head + .card-body { padding-top: 0; }
.card-head + .tbl-wrap { border-top: 1px solid var(--rule); }

/* MEASURED: the reference holds two entry cards across a 1280px frame with a 24px gutter. 420px is
   the smallest track that gives two rather than three at that width. */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr)); gap: var(--s6); }
.cards > * { min-width: 0; }

/* The two column split the overview and the agent detail both use. */
.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 400px); gap: var(--s6); align-items: start; }
@media (max-width: 980px) { .split { grid-template-columns: minmax(0, 1fr); } }

/* ---------------------------------------------------------- the agent mark */

/* The rounded square every agent is drawn with. It is a mark, not a logo: it identifies a row and
   carries no claim.
   IT IS A SOFT TILE AND IT USED TO BE A FILLED GREEN SQUARE. The reference draws a pale tile with a
   dark glyph, which lets four of them sit in a list without four green blocks competing with the
   status badges beside them. The own and external distinction survives the change, because this
   application needs it and the reference has no such distinction to copy. */
.mark { width: 40px; height: 40px; border-radius: var(--r-tile); background: var(--accent); color: var(--brand); display: grid; place-items: center; flex: 0 0 auto; }
.mark svg { width: 20px; height: 20px; display: block; }
.mark[data-scale="sm"] { width: 32px; height: 32px; border-radius: var(--r-ctl); }
.mark[data-scale="sm"] svg { width: 16px; height: 16px; }
.mark[data-scale="lg"] { width: 56px; height: 56px; }
.mark[data-scale="lg"] svg { width: 28px; height: 28px; }
/* An external publisher's agent is not Tarnbrook's, and the mark says so before any word does. The
   neutral tile carries no green at all. */
.mark[data-own="external"] { background: var(--inset); color: var(--muted); }

/* ---------------------------------------------------------------- buttons */

/* MEASURED: 14px at 500, a 12px radius, 40px tall. The label weight is the one number that moved
   furthest from the previous build, which set every button at 700. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 40px; padding: 0 var(--s4);
  font-family: var(--face-text); font-size: var(--t-row); font-weight: 500;
  border-radius: var(--r-ctl); border: 1px solid var(--rule);
  background: var(--panel); color: var(--ink); text-decoration: none; cursor: pointer;
  white-space: nowrap;
}
.btn:hover { background: var(--inset); }
.btn[data-kind="primary"] { background: var(--brand); border-color: var(--brand); color: var(--white); }
.btn[data-kind="primary"]:hover { background: var(--deep); border-color: var(--deep); }
.btn[data-kind="quiet"] { background: transparent; border-color: transparent; color: var(--brand); padding-inline: var(--s2); }
.btn[data-kind="quiet"]:hover { background: var(--inset); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
.btn-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s3); }
form.inline-form { display: contents; }

/* ------------------------------------------------------- chips and status */

/* A capability tag. Inert by construction: it names what software offers and asserts nothing about
   whether it was checked.
   MEASURED: 12px at 500 on the inset ground, 10px radius, in ink-2 rather than ink so a row of them
   does not read as loud as the card title above. NOT A PILL, which is the change. */
.chip { display: inline-flex; align-items: center; padding: var(--s1) var(--s3); border-radius: var(--r-chip); background: var(--inset); color: var(--ink-2); font-size: var(--t-label); font-weight: 500; }
.chips { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* A state: a dot and a word.
   THE WORD AND THE DOT NOW SHARE ONE TOKEN, and in the previous build they did not. That split
   existed because the old reference's status green was 3.02 against the page ground and unreadable
   as a word, so the palette carried a darker ink beside each dot colour. This reference's status
   colours are readable as words, and tokens.ts corrects the two that miss inside a badge instead.
   Nothing here needs a second colour any more. */
.state { display: inline-flex; align-items: center; gap: var(--s2); font-size: var(--t-row); white-space: nowrap; }
.state::before { content: ""; width: 8px; height: 8px; border-radius: var(--r-round); flex: 0 0 auto; background: var(--muted); }
.state[data-tone="ok"]::before { background: var(--ok); }
.state[data-tone="wait"]::before { background: var(--wait); }
.state[data-tone="info"]::before { background: var(--info); }
.state[data-tone="stop"]::before { background: var(--stop); }
.state[data-tone="ok"] { color: var(--ok); }
.state[data-tone="wait"] { color: var(--wait); }
.state[data-tone="info"] { color: var(--info); }
.state[data-tone="stop"] { color: var(--stop); }
.state[data-tone="muted"] { color: var(--muted); }

/* A badge: the one state that titles a card.
   MEASURED: 11px at 600, capitalised, 0.275px of tracking, 2px by 8px of padding, a 10px radius,
   and a soft tint of its own colour as the ground. Each pair is measured in
   tests/tarnbrook-design.test.ts, and two of them carry a corrected foreground because the
   reference's own values land at 4.42 and 4.33. */
.badge {
  white-space: nowrap; flex: 0 0 auto; display: inline-flex; align-items: center;
  padding: 2px var(--s2); border-radius: var(--r-chip);
  font-size: var(--t-badge); font-weight: 600; letter-spacing: 0.025em; text-transform: uppercase;
  background: var(--inset); color: var(--muted);
}
.badge[data-tone="ok"] { background: var(--mint); color: var(--ok); }
.badge[data-tone="wait"] { background: var(--amber); color: var(--wait); }
.badge[data-tone="info"] { background: var(--sky); color: var(--info); }
.badge[data-tone="stop"] { background: var(--inset); color: var(--stop); }

/* ----------------------------------------------------------------- tables */

.tbl-wrap { overflow-x: auto; max-width: 100%; min-width: 0; }
.tbl { width: 100%; border-collapse: collapse; font-size: var(--t-row); }
/* MEASURED: the head sits on the card ground rather than on an inset band, at 12px, 500, capitalised
   with 0.3px of tracking, and it is separated by a rule rather than by a fill. */
.tbl th {
  text-align: left; font-weight: 500; font-size: var(--t-label); letter-spacing: 0.025em; text-transform: uppercase;
  color: var(--muted); background: var(--panel); padding: var(--s3) var(--s5); white-space: nowrap;
  border-bottom: 1px solid var(--rule);
}
.tbl td { padding: var(--s4) var(--s5); border-bottom: 1px solid var(--rule); color: var(--muted); vertical-align: middle; }
.tbl tbody tr:last-child td { border-bottom: 0; }
/* The row subject: the one cell that says which thing this row is about. */
.tbl td[data-cell="subject"] { color: var(--ink); font-weight: 500; }
.tbl td[data-cell="id"] { font-family: var(--face-mono); font-size: var(--t-mono); color: var(--muted); }
.tbl td[data-cell="go"] { width: 1%; text-align: right; }
.tbl .row-lead { display: flex; align-items: center; gap: var(--s3); }
.go { color: var(--muted); text-decoration: none; display: inline-flex; align-items: center; justify-content: center; min-width: 32px; min-height: 32px; border-radius: var(--r-ctl); }
.go:hover { background: var(--inset); color: var(--brand); }

/* A row that opens onto the identifiers a machine needs. It ships CLOSED, so a sweep of this
   screen taken as served reads a state nobody stays in; anything measuring this page opens every
   one of them first. */
/* NOT A POPOVER. See the note in views/identities.ts: an absolutely positioned panel inside the
   last cell measured 285px wide and 602px tall and its bottom was clipped by the box that scrolls
   sideways. This is a full width row: the width of the table, clipped by nothing, no script. */
.tbl tr.row-extra > td { padding: 0; border-bottom: 1px solid var(--rule); }
.tbl tr:not(.row-extra) > td { border-bottom: 0; }
.row-open > summary { display: flex; align-items: center; gap: var(--s2); padding: var(--s3) var(--s5); font-size: var(--t-row); color: var(--brand); cursor: pointer; list-style: none; min-height: 34px; }
.row-open > summary::-webkit-details-marker { display: none; }
.row-open > summary:hover { background: var(--inset); }
.row-open[open] > summary .ic { transform: rotate(180deg); }
.row-panel { padding: 0 var(--s5) var(--s4); display: grid; gap: var(--s3); }
/* One identifier: its name, then the string, which wraps anywhere because it has no spaces. */
.ident { display: grid; gap: 2px; }
.ident-k { font-size: var(--t-label); letter-spacing: 0.025em; text-transform: uppercase; color: var(--muted); }
.ident code { overflow-wrap: anywhere; color: var(--ink); }

/* Two states in one cell: what the instance is doing, and what its identity is.
   THE FLEX IS ON A DIV INSIDE THE CELL AND NEVER ON THE CELL. display:flex on a td takes it out of
   the table's cell layout: its height came back one pixel short of its neighbours and the engine
   drew a second, offset hairline under that one column, which read as a stray box around three
   rows. Measured: seven cells at height 76 and the flex one at 75, same row, same border. */
.tbl td > .pair { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }

/* The trust table. The question is the row subject and must stay readable; the address asked is a
   long URL that wraps anywhere, so without a floor on the first column the question wrapped to five
   lines while the address took half the table. */
.tbl td[data-cell="subject"] { min-width: 22ch; }
.tbl td code { display: inline-block; max-width: 46ch; }

/* ------------------------------------------------------- tabs and filters */

.tabs { display: flex; gap: var(--s1); flex-wrap: wrap; border-bottom: 1px solid var(--rule); }
.tabs a, .tabs button {
  font-family: var(--face-text); font-size: var(--t-row); font-weight: 500; color: var(--muted);
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  padding: var(--s3) var(--s4); min-height: 40px; text-decoration: none; cursor: pointer;
}
.tabs a:hover, .tabs button:hover { color: var(--ink); }
.tabs [aria-current="page"], .tabs [aria-selected="true"] { color: var(--ink); border-bottom-color: var(--brand); }

/* THE FILTER SWITCH ABOVE THE CATALOGUE, and it changed shape. It was three separate pills; the
   reference draws one rounded container in the inset ground with the chosen segment filled inside
   it, which is what says the three are one choice rather than three buttons. */
.pills { display: inline-flex; gap: var(--s1); flex-wrap: wrap; background: var(--inset); border: 1px solid var(--rule); border-radius: var(--r-tile); padding: var(--s1); }
.pills a {
  font-size: var(--t-row); font-weight: 500; text-decoration: none;
  padding: var(--s2) var(--s3); min-height: 32px; display: inline-flex; align-items: center;
  border-radius: var(--r-ctl); background: transparent; color: var(--muted); border: 1px solid transparent;
}
.pills a:hover { color: var(--ink); }
.pills a[aria-current="page"] { background: var(--brand); border-color: var(--brand); color: var(--white); }

.toolbar { display: flex; gap: var(--s3); align-items: center; flex-wrap: wrap; }
.toolbar > form { flex: 1 1 260px; min-width: 0; display: flex; }
/* MEASURED: white ground, a 16px radius, 40px tall. The input is rounder than the button beside it,
   which is the reference's, and it is what stops the row reading as four identical rectangles. */
.search { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: var(--s3); background: var(--panel); border: 1px solid var(--rule); border-radius: var(--r-tile); padding-inline: var(--s4); min-height: 40px; }
.search input { flex: 1 1 auto; min-width: 0; border: 0; background: transparent; font: inherit; font-size: var(--t-row); color: var(--ink); min-height: 38px; }
.search input:focus { outline: 0; }
.search:focus-within { outline: 2px solid var(--brand); outline-offset: 2px; }
.search svg { width: 16px; height: 16px; color: var(--muted); flex: 0 0 auto; }

/* -------------------------------------------------------- entry card body */

.entry { display: grid; gap: var(--s4); align-content: start; padding: var(--s5); }
.entry-top { display: flex; gap: var(--s4); align-items: flex-start; justify-content: space-between; }
.entry-id { display: flex; gap: var(--s4); align-items: flex-start; min-width: 0; flex: 1 1 auto; }
.entry-id h2 { font-size: var(--t-card); }
.entry-id p { font-size: var(--t-row); color: var(--muted); margin-top: 2px; }
.entry .purpose { font-size: var(--t-row); color: var(--muted); }
.entry-meta { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s5); align-items: center; font-size: var(--t-row); color: var(--muted); padding-top: var(--s4); border-top: 1px solid var(--rule); }
.entry-meta .ver { margin-left: auto; font-family: var(--face-mono); font-size: var(--t-mono); letter-spacing: -0.01em; }
.fact { display: inline-flex; align-items: center; gap: var(--s2); }
.fact svg { width: 14px; height: 14px; color: var(--muted); flex: 0 0 auto; }

/* --------------------------------------------------- the detail screen */

.crumbs { display: flex; align-items: center; gap: var(--s3); font-size: var(--t-row); color: var(--muted); flex-wrap: wrap; }
.crumbs a { display: inline-flex; align-items: center; gap: var(--s2); color: var(--brand); text-decoration: none; min-height: 24px; }
.crumbs a:hover { text-decoration: underline; }
/* The arrow points back, and it is the only place in this application where it does. */
.crumbs a .ic { transform: rotate(180deg); }

.detail-id { display: flex; gap: var(--s5); align-items: flex-start; }
.detail-id h1 { font-size: var(--t-h1); }

/* The numbered steps of the deploy workflow. An ordered list, because the order is the meaning. */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4); }
.step { display: flex; gap: var(--s4); align-items: flex-start; position: relative; }
.step-n {
  width: 28px; height: 28px; border-radius: var(--r-round); background: var(--brand); color: var(--white);
  display: grid; place-items: center; font-size: var(--t-label); font-weight: 600; flex: 0 0 auto;
}
/* The thread between one step and the next, drawn on the step rather than between them so the last
   step cannot carry a line to nothing. */
.step:not(:last-child)::before { content: ""; position: absolute; left: 13px; top: 30px; bottom: -18px; width: 2px; background: var(--rule); }

/* The drawer the HTTP calls and the federation statements go behind. Closed on the page it is
   served on, so every sweep of this screen opens it before reading anything. */
.tech { border-top: 1px solid var(--rule); }
.tech > summary { padding: var(--s4) var(--s5); font-size: var(--t-row); font-weight: 500; color: var(--brand); cursor: pointer; list-style-position: inside; }
.tech > summary:hover { background: var(--inset); }

/* ----------------------------------------------------- name and value list */

/*
 * THE COLUMN OF EVERY CELL IS STATED, BECAUSE A THREE COLUMN GRID SCRAMBLES A TWO COLUMN LIST.
 *
 * The third column exists for a state cell, and only some lists carry one. Without an explicit
 * column, auto placement fills three cells per row from a stream of name and value pairs: the
 * second pair's name lands in the third column, which is max-content and therefore squeezed to
 * about one character, and the value after it wraps onto the next row under its neighbour.
 *
 * Measured on 27 September 2026 by reading frame 56s of the story film: the identity panel drew
 * the slug records-assistant one letter per line down a column a character wide, printed
 * "Accountable owner" to the right of its own value, and overlapped "Environment" with "Connect
 * hosted". The list had six pairs and no state cell, which is the case this grid was never given.
 *
 * Proved by consequence in a browser at 380px: under the old rule the six values landed at three
 * different left edges, two of them under 40px wide and two over 100px tall. Under this one every
 * value sits at one left edge and none is narrow or tall.
 */
.facts { display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content; gap: var(--s3) var(--s5); align-items: baseline; margin: 0; }
.facts dt { grid-column: 1; font-size: var(--t-row); color: var(--muted); }
.facts dd { grid-column: 2; margin: 0; min-width: 0; overflow-wrap: break-word; color: var(--ink); font-size: var(--t-row); }
.facts dd[data-cell="state"] { grid-column: 3; }
@media (max-width: 560px) { .facts { grid-template-columns: minmax(0, 1fr); gap: var(--s1); } .facts dd[data-cell="state"] { grid-column: 1; margin-bottom: var(--s3); } }

/* ------------------------------------------------------------ the feed */

.feed { display: grid; }
.feed-row { display: flex; align-items: center; gap: var(--s4); padding: var(--s3) var(--s5); border-bottom: 1px solid var(--rule); font-size: var(--t-row); }
.feed-row:last-child { border-bottom: 0; }
.feed-row time { color: var(--muted); flex: 0 0 auto; }
.feed-row .what { color: var(--ink); min-width: 0; }
.feed-row .ref { margin-left: auto; font-family: var(--face-mono); font-size: var(--t-mono); color: var(--muted); }

/* ------------------------------------------------- the publishers screen */

.pub-split { display: grid; grid-template-columns: minmax(0, 280px) minmax(0, 1fr); gap: var(--s6); align-items: start; }
@media (max-width: 900px) { .pub-split { grid-template-columns: minmax(0, 1fr); } }
.pub-list { display: grid; gap: var(--s2); min-width: 0; align-content: start; }
/* A party in the list: a mark, then the name and what it is. The mark is the reference's and it is
   what makes three rows of text read as three parties rather than as a paragraph. */
.pub-item { display: flex; gap: var(--s3); align-items: flex-start; padding: var(--s3) var(--s4); border-radius: var(--r-tile); border: 1px solid var(--rule); background: var(--panel); text-decoration: none; color: var(--ink); min-width: 0; }
.pub-item:hover { background: var(--inset); }
/* SELECTED IS A FILL AND IT WAS A LEFT EDGE. The reference marks the open party by tinting the whole
   row, which reads at a glance; an inset 3px rule on the left did not, at the size these rows are. */
.pub-item[aria-current="page"] { background: var(--inset); border-color: var(--rule); }
.pub-text { display: grid; gap: 2px; min-width: 0; }
.pub-name { font-weight: 500; }

.sub-h { font-size: var(--t-card); margin-bottom: var(--s3); }
.sub-h + .sub-h, .path + .sub-h, .ceiling + .sub-h, p + .sub-h { margin-top: var(--s5); }

/* The trust path: the hops a resolver walks, in the order it walks them.
   EACH HOP IS ITS OWN CARD, which is the reference's shape. It was a row of names on one inset band,
   where two parties and an arrow read as one sentence rather than as two things and a walk. */
.path { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.path-step { display: flex; align-items: center; gap: var(--s3); min-width: 0; background: var(--panel); border: 1px solid var(--rule); border-radius: var(--r-tile); padding: var(--s3) var(--s4); }
.path-step-text { display: grid; gap: 2px; min-width: 0; }
.path-arrow { color: var(--muted); display: inline-flex; }
.path-end { margin-left: var(--s2); }
@media (max-width: 620px) { .path { align-items: stretch; flex-direction: column; } .path-end { margin-left: 0; } }

/* The ceiling role, framed as one governed thing rather than left as a stray identifier. The glyph
   is the reference's; the identifier inside is this estate's, because no label exists to translate
   it with. See the note above ceilingPanel in views/publishers.ts. */
.ceiling { display: flex; gap: var(--s3); align-items: flex-start; background: var(--inset); border: 1px solid var(--rule); border-radius: var(--r-tile); padding: var(--s4); }
.ceiling-mark { width: 32px; height: 32px; border-radius: var(--r-ctl); background: var(--panel); border: 1px solid var(--rule); color: var(--brand); display: grid; place-items: center; flex: 0 0 auto; }
.ceiling-text { display: grid; gap: var(--s2); min-width: 0; }

/* The agents a publisher lists. One row each, because two of them can share a name. */
.agent-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.agent-list li { display: flex; gap: var(--s3); align-items: flex-start; padding: var(--s3) var(--s4); border: 1px solid var(--rule); border-radius: var(--r-tile); background: var(--panel); min-width: 0; }
.agent-text { display: grid; gap: 2px; min-width: 0; }

/* ------------------------------------------------------- promotion block */

/* The topographic texture, the reference's second photograph, under the same flat veil the footer
   uses. One veil rather than the reference's two stacked layers: the result is the same and there
   is one layer fewer to go wrong. */
.promo {
  background-color: var(--brand);
  background-image: linear-gradient(0deg, var(--veil-solid), var(--veil-solid)), url(/img/green-topo-waves.jpg);
  background-size: cover, cover;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  color: var(--white); border-radius: var(--r-card); padding: var(--s6);
  display: grid; gap: var(--s4); align-content: space-between; min-height: 200px;
}
.promo h2 { color: var(--white); font-size: var(--t-lead); max-width: 14ch; line-height: 1.25; }
.promo p { color: var(--white); font-size: var(--t-row); max-width: 36ch; opacity: 0.86; }
.promo a { color: var(--white); }

/* --------------------------------------------------------------- notices */

/* Where a value is declared rather than read, the interface says so here and nowhere else, so the
   sentence cannot drift into five spellings. It is deliberately not green. */
.declared { display: inline-flex; align-items: center; gap: var(--s2); font-size: var(--t-row); color: var(--muted); }
.note { background: var(--inset); border: 1px solid var(--rule); border-radius: var(--r-tile); padding: var(--s4); font-size: var(--t-row); color: var(--muted); }
.note strong { color: var(--ink); }

/* ----------------------------------------------------------------- footer */

/* THE FOOTER IS DARK AND IT USED TO BE WHITE. The reference closes every route with a green band
   carrying the wordmark, a tagline, the navigation a second time and a status line, over the same
   topographic texture the promotion block uses. */
.foot {
  background-color: var(--brand);
  background-image: linear-gradient(0deg, var(--veil-solid), var(--veil-solid)), url(/img/green-topo-waves.jpg);
  background-size: cover, cover;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  color: var(--white); margin-top: var(--s8);
}
.foot-in { padding-block: var(--s6); display: flex; gap: var(--s5); align-items: center; justify-content: space-between; flex-wrap: wrap; font-size: var(--t-row); color: var(--white); }
.foot-in a { color: var(--white); text-decoration: none; }
.foot-in a:hover { text-decoration: underline; }
.foot-in nav { display: flex; gap: var(--s6); flex-wrap: wrap; }
.foot-in nav a { display: inline-flex; align-items: center; min-height: 24px; }
.foot .brand-name b, .foot .brand-name span { color: var(--white); }
.foot .brand-mark { background: transparent; border: 1px solid var(--white); }

/* THE FIVE TREATMENT LABELS, drawn by this stylesheet and by no other.
   Exactly one of the five is FILLED, which is the distinction the vocabulary requires, and it is
   filled in a neutral near black rather than in a brand accent: Tarnbrook green would say the
   Tarnbrook colour means Raidiam product, and the showcase teal is what this palette exists to
   avoid. The other four differ by their edge, which reads at any size and needs no second colour. */
.treat-legend { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4); }
.treat { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s3) var(--s5); align-items: baseline; }
@media (max-width: 620px) { .treat { grid-template-columns: minmax(0, 1fr); gap: var(--s1); } }
.tl-chip { display: inline-flex; align-items: center; gap: var(--s2); padding: var(--s1) var(--s3); border-radius: var(--r-chip); font-size: var(--t-label); font-weight: 600; white-space: nowrap; border: 1px solid var(--rule); background: var(--panel); color: var(--ink); }
.tl-mark { width: 8px; height: 8px; border-radius: var(--r-round); background: currentColor; flex: 0 0 auto; }
.tl-note { color: var(--muted); font-size: var(--t-row); min-width: 0; }
.treat[data-treat="product"] .tl-chip { background: var(--fill); border-color: var(--fill); color: var(--white); }
.treat[data-treat="customer"] .tl-chip { border-color: var(--ink); }
.treat[data-treat="reference"] .tl-chip { border-style: dashed; border-color: var(--muted); color: var(--muted); }
.treat[data-treat="standard"] .tl-chip { border-style: dotted; border-color: var(--muted); color: var(--muted); }
.treat[data-treat="third"] .tl-chip { background: var(--inset); border-color: var(--inset); color: var(--muted); }

/* The name and value list the About page explains the labels with. */
.legend-list { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s3) var(--s5); margin: 0; align-items: baseline; }
.legend-list dt { font-weight: 600; }
.legend-list dd { margin: 0; color: var(--muted); min-width: 0; }
@media (max-width: 620px) { .legend-list { grid-template-columns: minmax(0, 1fr); gap: var(--s1); } .legend-list dd { margin-bottom: var(--s3); } }

/* ------------------------------- the pages the rebuild has not restyled */

/* THESE FOUR CLASSES EXIST SO FOUR PAGES CAN WEAR THIS BRAND WITHOUT BEING REWRITTEN.
   /register, /register/release, /vocabulary and /inspect are served by this host and reached from
   Tarnbrook screens, so on 14 September 2026 they moved onto this stylesheet: a reader inside
   Tarnbrook was clicking a link and landing on a page wearing Raidiam's brand, and the primary
   "Deploy new agent" button on the catalogue was one of those links.
   Their markup is src/pages.ts and it uses the showcase's class names. Rather than restyle four
   pages, the four names it needs are defined here in this palette. When those pages are rebuilt as
   Tarnbrook screens these go with them. */
.panel { background: var(--panel); border: 1px solid var(--rule); border-radius: var(--r-card); box-shadow: var(--lift); padding: var(--s5); display: grid; gap: var(--s3); align-content: start; min-width: 0; }
.panel > h2 { font-size: var(--t-card); }
.two, .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: var(--s6); align-items: start; }
.two > *, .grid > * { min-width: 0; }
.actions { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center; }
/* The showcase's small button, so a write control keeps its size on these pages. */
.btn-small { min-height: 34px; padding: 0 var(--s3); font-size: var(--t-label); }

/* ------------------------------------------- the resolved evidence panel */

/* Six sections about one resolved identity, drawn to be filmed at 1920 by 1080 and read at video
   bitrate. Two rules govern this block and neither applies to the rest of the application.

   THE TYPE FLOOR IS 14px HERE. Everything else on these screens may use --t-label at 12px and
   --t-mono at 12px, because a person reads them on a screen. A frame that survives a video codec
   does not, so every size in this block is --t-row or larger and the identifiers are set at
   --t-row rather than --t-mono.

   THE COLOURS SAY WHICH, NOT HOW HEALTHY. --ok appears in one place, on a trust path hop whose
   signature this request checked, and in the verdict that follows from those hops. The difference
   between what an agent asked for and what its authority granted is not a health state, so it is
   drawn with a coloured left edge: --stop on an entry the authority did not grant, --info on one
   the authority added, and the plain rule on the entries both records carry. */
/* THE CHROME IS TRIMMED FOR THIS SCREEN AND FOR NO OTHER. The screen's own padding is 32 over 64
   and the footer carries a 64px gap above it, which is right for a page a person scrolls and is
   160px of a frame that has 1080 of them. Both are scoped to the page that carries .ev-screen, so
   every other Tarnbrook route keeps the reference's spacing. */
.screen:has(> .ev-screen) { padding-block: var(--s5); }
body:has(.ev-screen) .foot { margin-top: var(--s6); }
.ev-screen { display: grid; gap: var(--s2); }
.ev-screen code { font-family: var(--face-mono); font-size: var(--t-row); color: var(--ink); overflow-wrap: anywhere; }
/* ONE SHEET, FOUR SECTIONS AND A DISCLOSURE, divided by a hairline. See the note above band() in
   src/views/resolved.ts: as five cards this screen was 1826px tall at 1920 by 1080, so the frame it
   exists to make could not be taken. */
.ev-sheet { display: grid; background: var(--panel); border: 1px solid var(--rule); border-radius: var(--r-card); box-shadow: var(--lift); min-width: 0; }
.ev-sheet > * + * { border-top: 1px solid var(--rule); }
.ev-k { font-size: var(--t-row); font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.ev-v { font-size: var(--t-row); color: var(--ink); }
.ev-quiet { color: var(--muted); }
.ev-note { margin: 0; font-size: var(--t-row); color: var(--muted); }
.ev-unread { margin: 0; display: flex; align-items: flex-start; gap: var(--s2); font-size: var(--t-row); color: var(--muted); }
.ev-unread svg { flex: 0 0 auto; margin-top: 3px; }

.ev-band { padding: var(--s3) var(--s5); display: grid; gap: var(--s2); align-content: start; min-width: 0; }
.ev-band-head { display: flex; align-items: baseline; gap: var(--s2) var(--s5); flex-wrap: wrap; }
.ev-band-head h2 { font-size: var(--t-row); font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; color: var(--brand); }
.ev-band-head p { margin: 0; font-size: var(--t-row); color: var(--muted); }

/* The entity identifier is twice as long as the other three values, so it gets twice the column
   rather than wrapping to three lines while its neighbours use half of theirs. */
.ev-facts { display: grid; grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)); gap: var(--s3) var(--s6); }
@media (max-width: 900px) { .ev-facts { grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); } }
.ev-fact { display: grid; gap: var(--s1); align-content: start; min-width: 0; }

.ev-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); gap: var(--s6); align-items: start; }
.ev-col { display: grid; gap: var(--s2); min-width: 0; align-content: start; }
.ev-col h3 { font-size: var(--t-card); display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap; }
.ev-src { font-size: var(--t-row); font-weight: 400; color: var(--muted); }
.ev-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
/* The left edge is 3px because a 1px tint does not survive a video codec, and it is the only thing
   that differs between the three kinds of row, so the eye lands on it. */
/* No 44px minimum: nothing in this list is a target, so the height is the text plus its padding. */
.ev-list li { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; padding: var(--s1) var(--s4); background: var(--inset); border: 1px solid var(--rule); border-left: 3px solid var(--rule); border-radius: var(--r-chip); min-width: 0; }
.ev-list li[data-mark="dropped"] { border-left-color: var(--stop); }
.ev-list li[data-mark="dropped"] code { color: var(--muted); text-decoration: line-through; }
.ev-list li[data-mark="added"] { border-left-color: var(--info); }
.ev-added { font-size: var(--t-row); font-weight: 500; color: var(--info); }

/* THE CHAIN READS LEFT TO RIGHT, one tile per party, because that is the direction it is walked
   and because three stacked rows carrying a ninety character identifier each were 406px of the
   frame. */
.ev-path { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: var(--s4); align-items: stretch; }
.ev-hop { display: grid; gap: 2px; align-content: start; padding: var(--s4); background: var(--inset); border: 1px solid var(--rule); border-radius: var(--r-tile); min-width: 0; }
.ev-hop .ev-v { font-weight: 500; }
.ev-hop .state { margin-top: var(--s1); }
.ev-hop-why { font-size: var(--t-row); color: var(--muted); }
/* The chain identifiers, inside the disclosure, where the full length costs nothing. */
.ev-chain { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.ev-chain li { display: grid; grid-template-columns: minmax(0, 14ch) minmax(0, 1fr); gap: var(--s3); align-items: baseline; padding: var(--s2) var(--s4); background: var(--inset); border: 1px solid var(--rule); border-radius: var(--r-chip); }
.ev-chain-text { display: grid; gap: 2px; min-width: 0; }

.ev-verdict { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s2) var(--s5); align-items: baseline; }
.ev-verdict-text { display: grid; gap: 2px; min-width: 0; }
.ev-verdict-word { margin: 0; }
.ev-verdict-word .state { font-size: var(--t-card); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; }
.ev-verdict-word .state::before { width: 12px; height: 12px; }
/* Wider than --measure, which is 68ch and would take the key source address onto a third line. A
   two line note beside a verdict is not body prose and 96ch reads cleanly at this size. */
/* overflow-wrap, because the sentence carries the key source address and a URL in prose has no
   break opportunity in it. Measured at 390: it took the document to 615px on its own. */
.ev-verdict-why { margin: 0; font-size: var(--t-row); color: var(--ink); max-width: 96ch; overflow-wrap: anywhere; }
.ev-verdict-when { overflow-wrap: anywhere; }
@media (max-width: 700px) { .ev-verdict { grid-template-columns: minmax(0, 1fr); } }
.ev-verdict-when { margin: 0; font-size: var(--t-row); color: var(--muted); }

.ev-open > summary { display: flex; align-items: center; gap: var(--s2); min-height: 44px; padding: var(--s2) var(--s5); font-size: var(--t-row); font-weight: 500; color: var(--brand); cursor: pointer; }
.ev-open > summary:hover { background: var(--inset); }
.ev-open-body { padding: 0 var(--s5) var(--s5); display: grid; gap: var(--s3); }
.ev-doc { margin: 0; padding: var(--s4); background: var(--inset); border: 1px solid var(--rule); border-radius: var(--r-tile); max-height: 300px; overflow: auto; }
.ev-doc[data-kind="signature"] { max-height: 110px; }
.ev-doc code { display: block; font-size: var(--t-row); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
/* The plain view (?view=plain). A permission prints as its label, and a label the authority did not
   grant is struck the same way its identifier is on the technical view. The signed record prints as
   rows of a plain label beside the values read from it. */
.ev-list li[data-mark="dropped"] .ev-perm { color: var(--muted); text-decoration: line-through; }
.ev-read { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.ev-read > li { display: grid; grid-template-columns: minmax(0, 32ch) minmax(0, 1fr); gap: var(--s3); align-items: baseline; padding: var(--s2) var(--s4); background: var(--inset); border: 1px solid var(--rule); border-radius: var(--r-chip); min-width: 0; }
.ev-read-values { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; min-width: 0; }
.ev-read-values .ev-v, .ev-read-values code { overflow-wrap: anywhere; }
@media (max-width: 700px) { .ev-read > li { grid-template-columns: minmax(0, 1fr); } }

/* -------------------------------------------------------------- utilities */

.u-quiet { color: var(--muted); }
.u-small { font-size: var(--t-row); }
.u-measure { max-width: var(--measure); }
/* VISUALLY HIDDEN, AND NOT POSITIONED, AND THAT SECOND HALF IS THE WHOLE POINT.
   The usual recipe adds position:absolute. An absolutely positioned element inside a box that
   scrolls sideways is NOT clipped by that box when its containing block is an ancestor of the
   scroller, so the four hidden labels inside the estate table's row links sat at left=814 and took
   the DOCUMENT to 815px at a 390px viewport. Measured by consequence: window.scrollTo(9999,0) left
   the overview at scrollX 425, then at 0 with this rule. A one pixel box with a negative margin,
   clipped, stays in flow and can widen nothing. */
.u-hidden { display: inline-block; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
/* min-width: 0 on both, because a grid child's default minimum is its content, so one unbreakable
   string inside refuses to shrink and widens everything that contains it. */
.stack { display: grid; gap: var(--s4); align-content: start; min-width: 0; }
.stack-sm { display: grid; gap: var(--s2); align-content: start; min-width: 0; }
.row { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
