/* Luce · Veliu Research Lab · console (dark ground + warm-paper light)
   ONE stylesheet, ONE shell, every page. The dashboard used to ship its own chrome and its own
   palette inline, so the product looked like two products. The ground is now near-monochrome and the
   colour names provenance; the gold emphasis is spent in exactly one place: the brand that leads a cell.
   Every other mark uses neutral ink, including intervals, chrome and focus. */
:root {
  --bg: #0a0b0d;
  --bg2: #0e1013;
  --panel: #101317;
  --panel2: #14181d;
  --line: #1d2126;
  --line2: #2b3138;
  --link-line: #656d75;
  --ink: #e7eaed;
  --mut: #9aa3ac;
  --dim: #79838d; /* 4.83:1 on the panel */
  --ci: #969ca2;
  --focus: #ffffff;
  --acc: #ffd23f;
  --acc-dim: #8a7524;
  --cyan: #6fd3f2;
  --up: #59d68c;
  --down: #ff7b6b;
  --watch: #e6b84c;
  --railbg: #0c0e11;
  --headbg: rgba(10, 11, 13, 0.92);
  --bannerbg: #101317;
  --bannerbd: #2b3138;
  --bannerstripe1: rgba(231, 234, 237, 0.05);
  --bannerstripe2: rgba(231, 234, 237, 0.01);
  --glow1: transparent;
  --glow2: transparent;
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;
  --sans: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --s0: 2px;
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;
  --s8: 64px;
  --t-micro: 10px;
  --t-data: 12px;
  --t-num: 14px;
  --t-num-lg: 22px;
  --t-fine: 13px;
  --t-body: 15px;
  --t-lede: 18px;
  --t-h: 20px;
  --railw: 232px;
  /* Ordered land tiers use two 3:1 steps. A third 3:1 step to a darker ocean needs
     27:1, beyond the 21:1 luminance range. White maximizes the remaining land/ocean step. */
  --cov-land: #484848;
  --cov-queued: #949494;
  --cov-measured: #ffffff;
}

/* ---- LIGHT THEME: the SAME warm paper the dashboard uses, so a reader who toggles to light on the
   dashboard and clicks through to the board does not fall into a black hole. Dark is the default; a
   saved choice and the host theme both stamp data-theme, which wins over the OS preference. ---- */
:root[data-theme="light"] {
  --bg: #f5f2ea;
  --bg2: #efebe1;
  --panel: #fbf9f3;
  --panel2: #f3efe5;
  --line: #e0dad0;
  --line2: #cdc5b7;
  --link-line: #858077;
  --ink: #1e1c18;
  --mut: #6d675c;
  --dim: #70695f; /* at least 4.55:1 on every theme surface */
  --ci: #66635e;
  --focus: #000000;
  --acc: #865a00;
  --acc-dim: #c19a3a;
  --cyan: #0d7f9c;
  --up: #1f9a55;
  --down: #c34a39;
  --watch: #a97c0a;
  --railbg: #efebe1;
  --cov-land: #484848;
  --cov-queued: #949494;
  --cov-measured: #ffffff;
  --headbg: rgba(245, 242, 234, 0.9);
  --bannerbg: #efebe1;
  --bannerbd: #cdc5b7;
  --bannerstripe1: rgba(30, 28, 24, 0.06);
  --bannerstripe2: rgba(30, 28, 24, 0.01);
  --glow1: transparent;
  --glow2: transparent;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #f5f2ea;
    --bg2: #efebe1;
    --panel: #fbf9f3;
    --panel2: #f3efe5;
    --line: #e0dad0;
    --line2: #cdc5b7;
    --link-line: #858077;
    --ink: #1e1c18;
    --mut: #6d675c;
    --dim: #70695f; /* at least 4.55:1 on every theme surface */
    --ci: #66635e;
    --focus: #000000;
    --acc: #865a00;
    --acc-dim: #c19a3a;
    --cyan: #0d7f9c;
    --up: #1f9a55;
    --down: #c34a39;
    --watch: #a97c0a;
    --railbg: #efebe1;
    --cov-land: #484848;
    --cov-queued: #949494;
    --cov-measured: #ffffff;
    --headbg: rgba(245, 242, 234, 0.9);
    --bannerbg: #efebe1;
    --bannerbd: #cdc5b7;
    --bannerstripe1: rgba(30, 28, 24, 0.06);
    --bannerstripe2: rgba(30, 28, 24, 0.01);
    --glow1: transparent;
    --glow2: transparent;
  }
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scrollbar-gutter: stable; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
a:hover, a:focus-visible { color: var(--focus); text-decoration-thickness: 2px; }

/* R53: the caption belongs to the measurement, including on a clean screenshot ground. */
.module-frame { min-width: 0; margin: 14px 0; padding: 14px; border: 1px solid var(--line); background: var(--bg); }
.module-identity { display: none; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin-bottom: 14px; }
html[data-card] [data-card-active] > .module-identity { display: flex; }
.module-identity .wordmark { padding: 0; }
.module-identity .sample-banner { border: 1px solid var(--ink); color: var(--ink); padding: 1px 5px; font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; }
.module-meta { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--line); color: var(--dim); font-family: var(--mono); font-size: 11px; overflow-wrap: anywhere; }
.module-meta-line { flex-basis: 100%; }
.module-key { flex-basis: 100%; }
.module-meta [data-meta="estimand"], .module-meta [data-meta="disclosure"] { flex-basis: 100%; }
.module-meta .chip { white-space: normal; }
.module-url { color: inherit; }
.module-control { display: inline-flex; align-items: center; min-height: 44px; margin-top: 4px; color: var(--dim); font-size: 11px; }
html[data-card] body *:not([data-card-path]):not([data-card-active]):not([data-card-active] *):not([data-card-control]):not(#themebtn):not(#themebtn *):not(.wavebar):not(.wavebar *) { display: none !important; }
html[data-card] [data-card-path]:not(body) { display: contents !important; }
html[data-card] .wavebar { position: static; margin: 16px 16px 0; padding: 9px 16px; height: auto; overflow: visible; }
html[data-card] .wavebar .sample-banner { display: inline-block; white-space: normal; }
html[data-card] [data-card-active] { width: calc(100% - 32px); max-width: 1056px; margin: 16px auto 24px; scroll-margin-top: 100vh; }
html[data-card] #themebtn { position: static; display: inline-flex; width: auto; margin: 0 16px 24px; vertical-align: middle; background: var(--bg); }
html[data-card] .module-control { position: static; margin: 0 0 24px max(16px, calc((100% - 1056px) / 2)); padding: 0 8px; vertical-align: middle; background: var(--bg); }
html[data-card] [data-card-active] > section { margin: 0; padding: 0; }

/* ---- the console: a permanent left rail, one content column ---------------------------------- */
.app { display: grid; grid-template-columns: var(--railw) minmax(0, 1fr); min-height: 100vh; }
.col { display: flex; flex-direction: column; min-width: 0; }
.wrap { max-width: 1120px; margin: 0 auto; padding: 0 32px; width: 100%; }
main.wrap { flex: 1 0 auto; padding-bottom: 40px; }

.rail {
  position: sticky; top: 0; align-self: start; height: 100vh; overflow-y: auto;
  display: flex; flex-direction: column; gap: 4px;
  padding: 22px 0 16px;
  background: var(--railbg); border-right: 1px solid var(--line);
}
/* The rail in two parts (R111). The rail-top block is the identity block (wordmark, subtitle, wave
   chip, search); railfold is a native details element holding every destination plus the rail foot. On every
   viewport wider than a phone the details is OPEN and its summary is not rendered, so the rail looks
   and behaves exactly as it did; at 430px and below the summary becomes the "Board" button and the
   panel drops out of a one-row sticky header. No JavaScript is required for any of it: RAILFOLD_JS
   only chooses the initial state, so with JS off a phone reader gets the full list rather than a
   dead button. */
.rail-top { display: flex; flex-direction: column; gap: 4px; }
.railfold { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.rail-panel { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
/* Above the phone breakpoint there is no button, because there is no fold. */
.rail-more { display: none; }
/* The wave chip is the phone-only home of the banner tag. Above the breakpoint the wavebar shows it,
   and this copy is display:none, so it is invisible to assistive technology too: exactly one visible
   wave tag at every width. */
.rail-wave { display: none; }
.wordmark {
  color: var(--ink); font-size: 14px; font-weight: 800; letter-spacing: 0.16em; white-space: nowrap;
  padding: 0 20px;
}
.wordmark:hover { color: var(--focus); }
.wordmark .wm-dot { color: var(--ink); margin: 0 2px; }
.rail-sub {
  padding: 2px 20px 0; color: var(--dim); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6;
}

/* ---- rail search box + ⌘K/"/" palette -------------------------------------------------------- */
.rail-search {
  margin: 16px 16px 0; display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; width: calc(100% - 32px);
  background: var(--panel); border: 1px solid var(--line2); border-radius: 7px;
  color: var(--dim); font-family: var(--mono); font-size: 12px; cursor: text; text-align: left;
}
.rail-search:hover { border-color: var(--dim); color: var(--mut); }
.rail-search .rs-txt { flex: 1; }
.rail-search .rs-kbd {
  border: 1px solid var(--line2); border-radius: 4px; padding: 0 6px; font-size: 11px; color: var(--dim);
}
.pal {
  position: fixed; inset: 0; z-index: 200; display: flex; justify-content: center; align-items: flex-start;
  padding-top: 12vh; background: rgba(6, 7, 9, 0.6); backdrop-filter: blur(3px);
}
.pal[hidden] { display: none; }
.pal-box {
  width: min(560px, 92vw); background: var(--panel); border: 1px solid var(--line2); border-radius: 12px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5); overflow: hidden;
}
.pal-input {
  width: 100%; border: 0; border-bottom: 1px solid var(--line); background: transparent; color: var(--ink);
  font-family: var(--mono); font-size: 15px; padding: 16px 18px;
}
.pal-list { list-style: none; max-height: 52vh; overflow-y: auto; }
.pal-item {
  display: flex; align-items: baseline; gap: 12px; padding: 10px 18px; cursor: pointer;
  border-bottom: 1px solid var(--line);
}
.pal-item:last-child { border-bottom: 0; }
.pal-item.on, .pal-item:hover { background: var(--panel2); }
.pal-kind {
  flex: 0 0 auto; font-size: 8.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
  border: 1px solid var(--line2); border-radius: 4px; padding: 1px 6px; min-width: 62px; text-align: center;
}
.pal-brand { color: var(--mut); border-color: var(--line2); }
/* R104: the widened index. Answers carry the accent (they are the product's proof); the reference
   kinds (source, term, claim) stay quiet. */
.pal-answer { color: var(--acc); border-color: var(--line2); }
.pal-claim { color: var(--ink); }
.pal-lab { color: var(--ink); font-size: 13px; font-weight: 700; }
.pal-sub { color: var(--dim); font-size: 11px; margin-left: auto; }
.pal-empty { padding: 18px; color: var(--dim); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }

.rail-nav { margin-top: 22px; display: flex; flex-direction: column; gap: 20px; }
.rail-grp { display: flex; flex-direction: column; }
.rail-lab {
  padding: 0 20px 7px; color: var(--dim);
  font-size: 9px; letter-spacing: 0.2em; text-transform: uppercase;
}
.rail-nav a {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 6px 20px; color: var(--mut); font-size: 12px;
  border-left: 2px solid transparent;
}
.rail-state { color: var(--dim); font-size: 8px; letter-spacing: 0.1em; text-transform: uppercase; font-weight: 400; }
.rail-category { display: flex; align-items: baseline; padding-right: 20px; }
.rail-category > a { flex: 1; min-width: 0; padding-right: 8px; }
.rail-category .m-gloss { display: inline; padding: 0; border: 0; font: inherit; text-decoration: underline; text-underline-offset: 2px; }
.rail-nav a.measuring { color: var(--dim); }
.rail-nav a:hover { color: var(--focus); background: var(--panel); }
/* The reader always knows which surface they are on. */
.rail-nav a.on { color: var(--ink); background: var(--panel); border-left-color: var(--ink); font-weight: 700; }

.rail-foot {
  margin-top: auto; padding: 14px 20px 0; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 10px; align-items: flex-start;
}
.rf-line { color: var(--dim); font-size: 10px; letter-spacing: 0.06em; }
.themebtn {
  background: none; border: 1px solid var(--line2); color: var(--mut);
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 5px 10px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
}
.themebtn:hover { color: var(--ink); border-color: var(--dim); }
.themebtn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.theme-icon { width: 12px; height: 12px; flex: 0 0 auto; }

/* ---- the ONE honesty band ---------------------------------------------------------------------
   The class is wavebar, NOT band. That name was already taken by the probe log's own mandatory band,
   which pins itself with position sticky, top 33px, under a header that no longer exists. Two
   components sharing one class name is how the shell band ended up rendered 33px below its own flow
   position, overlapping the first line of every page. Unique names, scoped rules. (This stylesheet is
   a JS template literal: never put a backtick in a comment here.) */
.wavebar {
  /* Not sticky. The band sits at the top of every page and the rail is permanent; nothing in the
     doctrine requires it to follow the scroll, and a bar that overlaps the content it is meant to
     qualify is worse than one that does not.
     The INK is --ink, not gold. Gold on the banner ground measured 3.09:1, and the wave id measured
     2.17:1: a disclosure nobody can read is a doctrine violation, not a nit. The wave disclosure uses neutral ink, including its striped tag. */
  display: flex; gap: 6px 16px; align-items: center; flex-wrap: wrap;
  padding: 9px 32px;
  background: var(--bannerbg);
  border-bottom: 1px solid var(--bannerbd);
  color: var(--ink);
  font-family: var(--sans); font-size: var(--t-body); line-height: 1.6;
}
.wavebar .sample-banner {
  border: 1px solid var(--ink); color: var(--ink); padding: 1px 8px; font-weight: 700;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap;
  background:
    repeating-linear-gradient(-45deg, var(--bannerstripe1) 0 6px, var(--bannerstripe2) 6px 12px);
}
.wavebar .wb-text, .wavebar .wb-prov { color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
/* The provenance sentence is the one the doctrine mandates; it may wrap, it may not be dropped. */
.wavebar .wb-prov { flex: 1 1 420px; min-width: 0; }
/* The band is paper voice now, so its tier tokens keep the instrument voice explicitly: they are
   identifiers, not prose. Dotted underline, because a colour shift alone does not read as a
   destination and a solid rule would cut the sentence up. */
.wavebar .wb-gloss { font-family: var(--mono); color: inherit; text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 2px; }
.wavebar .wb-gloss:hover, .wavebar .wb-gloss:focus-visible { color: var(--focus); text-decoration-style: solid; }
.wavebar .wb-sep { color: var(--line2); }

/* The matrix legend: what the ink means. Stated once per page, above the tables. */
.legend { color: var(--dim); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; max-width: 78ch; margin: 0 0 20px; }

/* ---- the stat strip: the ONLY place a fact about the wave is stated -------------------------- */
.strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
  border: 1px solid var(--line); background: var(--panel);
  margin: 26px 0 30px;
}
.strip .stat {
  min-width: 0; padding: 13px 18px; border-right: 1px solid var(--line);
  /* Each visual row shares label, numeral and qualifier tracks, even when a label wraps again. */
  display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 3px;
}
.strip .stat:last-child { border-right: 0; }
.strip .st-lab {
  color: var(--dim); font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase;
  white-space: normal; overflow-wrap: break-word;
  min-height: 26px; line-height: 1.45;
}
.strip .locale-token { white-space: nowrap; }
.strip .st-val {
  color: var(--ink); font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums;
  line-height: 1.25;
  /* Bottom-aligned inside its own reserved row, so a one-line and a two-line label still set their
     values on the same line. */
  align-self: end; grid-row: 2;
}
/* The qualifier that used to ride the label ("AI surfaces · 3 APIs + web app"). It carries digits, so
   it cannot be part of a word-only label; it sits under the value, quiet, and the same text is also on
   the tile's title attribute for a reader who hovers. */
.strip .st-sub {
  grid-row: 3; min-height: 14px;
  color: var(--dim); font-size: 9.5px; letter-spacing: 0.04em; line-height: 1.4;
  white-space: normal; overflow-wrap: break-word;
}

/* The column header row, once, above the standings. The bar is a RANK axis and it must say so. */
.standing.st-hd { border-bottom: 1px solid var(--line2); }
.standing.st-hd .st-body {
  padding-top: 0; padding-bottom: 8px;
  color: var(--dim); font-size: 9px; letter-spacing: 0.11em; text-transform: uppercase;
}
@media (max-width: 900px) {
  .standing.st-hd { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* The brand page's takeaway: ONE ROW PER SURFACE (R110), never a fused cross-engine range. Each row is
   its own cell: engine, rate with its own interval, its own sample and tier, and a door to its own
   evidence. The rows share a grid so the rates line up down the column and the reader can compare
   surfaces by eye without any number pretending to be a combination of them. */
.brand-deck {
  margin-top: 14px; border-left: 2px solid var(--ink); padding-left: 12px;
  display: flex; flex-direction: column; gap: 2px; max-width: 640px;
}
.bd-row {
  display: grid; grid-template-columns: 120px minmax(0, 1fr) auto auto;
  align-items: baseline; gap: 4px 14px; padding: 5px 0;
  border-bottom: 1px solid var(--line);
}
.bd-row:last-child { border-bottom: 0; }
.bd-eng { color: var(--ink); font-size: 12px; font-weight: 700; }
.bd-rate { color: var(--ink); font-size: 14px; font-variant-numeric: tabular-nums; }
.bd-rate b { font-weight: 700; }
.bd-ci { color: var(--mut); font-size: 11px; margin-left: 8px; white-space: normal; }
.bd-meta { color: var(--dim); font-size: 10.5px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.bd-row.lp .bd-rate b { color: var(--mut); }
.bd-door { font-size: 11px; color: var(--ink); white-space: nowrap; }
.bd-door:hover, .bd-door:focus-visible { color: var(--focus); }
@media (max-width: 700px) {
  .bd-row { grid-template-columns: minmax(0, 1fr) auto; }
  .bd-eng { grid-column: 1 / -1; }
  .bd-meta { grid-column: 1; white-space: normal; }
}

/* The absence view (R110): what the shopper saw in the answers this brand is NOT in. Observation, no
   call to action; the list is alphabetical and says so. */
.absence {
  margin: 14px 0 4px; max-width: 78ch; color: var(--mut);
  font-family: var(--sans); font-size: var(--t-body); line-height: 1.6;
}
.absence b { font-family: var(--mono); color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }
.absence .abs-note { color: var(--dim); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.absence .abs-door { color: var(--ink); }

/* ---- breadcrumbs ---------------------------------------------------------------------------- */
.crumbs {
  margin-top: 22px; font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--dim);
}
.crumbs a { color: var(--mut); }
.crumbs a:hover { color: var(--ink); }
.crumbs .sep { margin: 0 8px; color: var(--line2); }

/* ---- chips ---------------------------------------------------------------------------------- */
.chip {
  font-family: var(--mono);
  display: inline-block; padding: 0 7px; border: 1px solid var(--line2);
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; line-height: 1.7;
  color: var(--mut); white-space: nowrap;
}
.chip-synth { border-color: var(--line2); color: var(--mut); background: transparent; }
.chip-real { border-color: #1f5233; color: var(--up); background: rgba(89, 214, 140, 0.07); }
.chip-eng { color: var(--cyan); border-color: #274c5c; }
.chip-warn { border-color: #5c2e28; color: var(--down); background: rgba(255, 123, 107, 0.06); }
/* A deliberately small wave is not a fault. The under-powered flag used to render in the RED error
   colour on EVERY cell, which argued the system had broken; the guide says 0% coverage is honest.
   Amber = a state you should know about, not an alarm. */
.chip-watch { border-color: #5a4a16; color: var(--watch); background: rgba(230, 184, 76, 0.07); }

/* ---- page head: ONE title, ONE sentence -------------------------------------------------------
   The lede is the copy system for the whole site. It is a plain English sentence with the numbers
   set in bold inside it, not a rack of chips and fragments. A reader gets the finding before the
   table, in words, once. */
.page-title { padding: 30px 0 0; }
.page-title .kicker {
  color: var(--dim); font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase;
  margin-bottom: 12px;
}
.page-title h1 {
  font-size: clamp(24px, 3.4vw, 34px); line-height: 1.15; letter-spacing: -0.01em;
  font-weight: 800; max-width: 26ch;
}
.page-title h1 em { font-style: normal; color: var(--ink); }
.brand-h1 { display: flex; align-items: center; gap: 14px; }
.lede {
  margin-top: 14px; max-width: 68ch; color: var(--mut);
  font-family: var(--sans); font-size: var(--t-lede); line-height: 1.55;
}
.lede b { font-family: var(--mono); font-size: var(--t-num); color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }
.page-title .sub { margin-top: 10px; max-width: 68ch; color: var(--dim); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }

/* ---- sections ------------------------------------------------------------------------------- */
section { padding: 8px 0 22px; }
.sec-head {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  padding-bottom: 12px; margin-bottom: 4px;
}
.sec-no { color: var(--dim); font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase; }
.sec-head h2 {
  font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 700;
}
/* --mut, not --dim: at --dim these were 2.86:1 in the light theme, and the estimand is a
   doctrine-REQUIRED disclosure. --mut is 4.9:1 light / 6.5:1 dark. */
.sec-note { color: var(--mut); font-family: var(--sans); font-size: var(--t-body); margin-left: auto; text-align: right; line-height: 1.6; }
/* The rule is NEUTRAL. Gold has exactly one job on this site, and the legend states it: the top rate on
   an engine. An estimand line wearing the same gold quietly breaks that promise. */
.estimand {
  color: var(--mut); font-family: var(--sans); font-size: var(--t-body); margin: 4px 0 18px;
  border-left: 2px solid var(--line2); padding-left: 10px; line-height: 1.6;
}

/* ---- board cards ---------------------------------------------------------------------------- */
.board { display: grid; grid-template-columns: 1fr; gap: 18px; }
.cell-card { border: 1px solid var(--line); background: var(--panel); }
.cell-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 16px; border-bottom: 1px solid var(--line); background: var(--panel2);
}
.cell-head h3 { font-size: 14px; font-weight: 700; letter-spacing: 0.04em; }
.cell-head h3 a { color: var(--ink); }
.cell-head h3 a:hover { color: var(--focus); }
.cell-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-left: auto; }
.cell-meta .m { color: var(--dim); font-size: 11px; }

.league { border-bottom: 1px solid var(--line); display: flex; }
.league:last-of-type { border-bottom: none; }
.league-rail {
  flex: 0 0 108px; padding: 10px 0 10px 16px;
  border-right: 1px dashed var(--line2);
  display: flex; flex-direction: column; gap: 4px;
}
.league-rail .league-tag {
  color: var(--mut); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  writing-mode: initial; line-height: 1.5;
}
.league-rail .league-sub { color: var(--dim); font-size: 10px; }
.league-gloss { color: var(--mut); font-size: 11px; line-height: 1.5; letter-spacing: normal; text-transform: none; }
.league-rail .league-gloss { padding-right: 8px; }
.league-standing { display: flex; flex-direction: column; min-width: 0; }
.league.lp .league-tag { color: var(--dim); }
/* Shared board heading. Its host supplies the existing quadrant bottom padding. */
.league-heading { padding: 10px 16px var(--league-heading-bottom, 0px); color: var(--dim); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; }
.league-heading .league-sub { letter-spacing: .06em; text-transform: none; color: var(--dim); }
.wgx-qhead { --league-heading-bottom: 10px; display: flex; align-items: baseline; gap: 8px; }
.members { list-style: none; flex: 1; min-width: 0; }
.member, .member-head, .standing .st-body {
  display: grid;
  grid-template-columns: minmax(120px, 180px) minmax(110px, 1fr) minmax(150px, 200px) minmax(100px, 178px);
  gap: 14px; align-items: center;
}
.member {
  padding: 8px 16px; border-bottom: 1px solid var(--line);
}
.member:last-child { border-bottom: none; }

/* An unranked brand says so in words where its rank bar would have been. */
.rr-none { color: var(--mut); font-size: 10.5px; letter-spacing: 0.04em; }

/* Both list surfaces use one rank cell, one subject, one CI-bearing rate, and optional history. */
.cell-card.no-trend .member,
.cell-card.no-trend .member-head,
.standing .st-body.no-trend { grid-template-columns: minmax(120px, 180px) minmax(110px, 1fr) minmax(150px, 200px); }
.cell-card.no-rank .member, .cell-card.no-rank .member-head,
.standing .st-body.no-rank { grid-template-columns: minmax(110px, 1fr) minmax(150px, 200px) minmax(100px, 178px); }
.cell-card.no-rank.no-trend .member, .cell-card.no-rank.no-trend .member-head,
.standing .st-body.no-rank.no-trend { grid-template-columns: minmax(110px, 1fr) minmax(150px, 200px); }
.rank-cell { min-width: 0; display: grid; gap: 5px; }

/* The column header. The rank bar sits next to the rate and was being read AS the rate's bar, which
   inverts it: the bar is a RANK axis, so the worst-rate brand draws the longest reach. Name the
   columns and the misread is impossible. */
.league.cols { border-bottom: 0; }
.member-head {
  align-items: end;
  padding: 2px 16px 6px; border-bottom: 1px solid var(--line2);
  color: var(--dim); font-size: 9px; letter-spacing: 0.11em; text-transform: uppercase;
  line-height: 1.35;
}
:is(.member, .standing) .rk { color: var(--mut); font-size: 11px; }
:is(.member, .standing) .bn { min-width: 0; font-weight: 700; letter-spacing: 0.04em; overflow-wrap: anywhere; }
:is(.member, .standing) .bn a { color: var(--ink); }
:is(.member, .standing) .bn a:hover { color: var(--focus); }
:is(.member, .standing).lp :is(.bn, .bn a, .rk, .rate b, .rate .ci) { color: var(--dim); }

/* League-A leader: the top member of the top league reads instantly at a glance -- brighter name and
   an accent-toned rank-range bar. This is scan emphasis on the observed leader (never a rank claim): the
   label stays a range and the photo-finish card still says when the top is contested. */
.member.leader .bn, .member.leader .bn a { color: var(--acc); }
.standing.leader .bn, .standing.leader .bn a { color: var(--acc); }
.member.leader .bn { font-weight: 800; }


.rr { position: relative; height: 16px; }
.rr-ticks {
  position: absolute; inset: 2px 0;
  background-image: repeating-linear-gradient(to right, var(--ci) 0 1px, transparent 1px calc(100% / var(--field, 8)));
}
.rr-track { position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--line2); }
.rr-span {
  position: absolute; top: 3px; bottom: 3px;
  border-left: 2px solid var(--ci); border-right: 2px solid var(--ci);
}
.rr-span::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--ci);
}
.rr-med {
  position: absolute; top: 50%; width: 5px; height: 5px; margin-left: -2.5px;
  background: var(--ci); transform: translateY(-50%) rotate(45deg);
}
.member.leader .rr-span { background: rgba(255, 210, 63, 0.26); border-color: var(--acc); }
.member.leader .rr-span::after, .member.leader .rr-med { background: var(--acc); }
.rr-rate, .rr-div { background: var(--bg2); border: 1px solid var(--line); }
.rr-rate { height: 10px; }
.rr-rate .rr-ticks { inset: 0; background: none; }
.rr-rate .rr-ticks i { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--ci); }
.rr-rate .rr-span { top: 1px; bottom: 1px; background: var(--ci); border: 1px solid var(--ci); }
.rr-rate .rr-span::after, .rr-div .rr-span::after { content: none; }
.rr-rate .rr-med { top: -2px; width: 3px; height: 12px; margin-left: 0; transform: none; }
.rr-rate .rr-span + .rr-med { box-shadow: 0 0 0 1px var(--bg2); }
.rr-div { height: 12px; }
.rr-fill { position: absolute; inset: 2px auto 2px 2px; background: var(--ci); }
.rr-div .rr-span { top: 50%; bottom: auto; height: 1px; border: 0; background: var(--ci); box-shadow: 0 0 0 1px var(--bg2); }


.rate { white-space: nowrap; font-size: 12px; }
/* Fixed right-aligned width so a single-digit rate ("4%") and a two-digit one ("44%") both occupy
   the same box; the "95% CI ..." text that follows always starts at a constant x, no column jitter. */
.rate b { font-size: 15px; font-weight: 700; display: inline-block; min-width: 3.2ch; text-align: right; }
/* ciTextOf prints ONE interval as words instead of bounds ("interval unresolved at this n", a
   boundary-degenerate zero). At ~155px it is three times a "39-52" and it does not fit the 178px rate
   track, so the parent's nowrap pushed it past the card border on /e/chatgpt-web and past the diptych
   panel on the flagship. The words wrap; the rate and its interval still never split, because the space
   BETWEEN them lives in .rate and .rate is still nowrap. The text itself is untouched. */
.rate .ci { display: inline-block; min-width: 7ch; color: var(--mut); margin-left: 7px; font-size: 11px; white-space: normal; overflow-wrap: anywhere; }
.rate .ci-unresolved { display: inline; min-width: 0; }
.member.lp .rate b, .member.lp .rate .ci { color: var(--dim); }

.spark { color: var(--ci); display: inline-flex; }
.spark svg { display: block; max-width: 100%; }
.member.lp .spark { color: var(--ci); }
/* The translucent ribbon has a solid contour. Low-n segments keep a dashed line and hollow dot,
   so lowering opacity cannot hide a measurement or become its only precision cue. */
:is(.spark, .mx-tr-series) [data-ci-ribbon] { stroke: var(--ci); stroke-width: 1px; }
:is(.spark, .mx-tr-series) :is(line, text) { stroke-opacity: 1; fill-opacity: 1; }
:is(.spark, .mx-tr-series) circle { fill-opacity: 1; }
:is(.spark, .mx-tr-series) line[stroke-opacity="0.5"] { stroke-dasharray: 2 2; }
:is(.spark, .mx-tr-series) circle[fill-opacity="0.5"] { fill: var(--panel); stroke: var(--ci); stroke-width: 1px; }


.league-foot {
  padding: 6px 16px 10px; color: var(--dim); font-size: 10.5px;
  border-top: 1px dashed var(--line);
}

/* movement chips */
.mv { display: inline-block; padding: 0 8px; font-size: 11px; line-height: 1.8; border: 1px solid; white-space: nowrap; }
.mv-up { color: var(--mut); border-color: var(--line2); background: var(--panel2); }
.mv-down { color: var(--mut); border-color: var(--line2); background: var(--panel2); }
.mv-stable { color: var(--mut); border-color: var(--line2); }
.mv-watch { color: var(--mut); border-color: var(--line2); background: var(--panel2); }
.mv-insufficient { color: var(--dim); border-color: var(--line); }

/* ---- probe log ------------------------------------------------------------------------------ */
.ticker { border: 1px solid var(--line); background: var(--panel); }
/* The probe log's own band. Scoped: it used to be an unscoped .band, colliding with the shell's, and
   it pinned itself 33px down under a header that no longer exists. */
.ticker .band {
  padding: 8px 16px; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink); background: var(--panel2);
  border-bottom: 1px solid var(--bannerbd);
}
.probes { list-style: none; }
/* Seven tracks summed to 1016px of min-content and the log lived inside the methodology prose column,
   which is ~594px once the rail takes its 232px. The row sliced "en-US" mid-glyph and painted the brand
   list OUTSIDE the card, on the bare page background. The 360/390 sweep could not see it: the spill lands
   in the empty right gutter of the main region, so scrollWidth never exceeds clientWidth. The surface id
   (openai_native) is implied by the engine column beside it, and the locale is stated in the band and in
   the rail foot; both tracks are deleted here and hidden in the markup. */
/* Seven fixed tracks summed to 1016px of min-content, inside a methodology prose column that is ~594px
   once the rail takes its 232px: the row sliced "en-US" mid-glyph and painted the brand list OUTSIDE the
   card, on the bare page background. The viewport sweep at 360/390 could not see it, because the spill
   lands in the empty right gutter of the main region and scrollWidth never exceeds clientWidth. It takes
   an ELEMENT-level check (el.scrollWidth > el.clientWidth) to catch it, and that check is now in the
   verification pass.

   The surface id (openai_native) is implied by the engine column beside it, and the locale is in the band
   and the rail foot; both tracks are gone. What remains is fluid: no track has a fixed minimum that can
   outgrow its container. */
.probe {
  display: grid;
  grid-template-columns: 88px minmax(0, 1.1fr) 76px minmax(0, 1.5fr) minmax(0, 1.2fr);
  gap: 10px; align-items: baseline;
  padding: 7px 14px; border-bottom: 1px solid var(--line); font-size: 11px;
  min-width: 0;
}
.probe > * { min-width: 0; overflow-wrap: anywhere; }
.probe .srf, .probe .loc { display: none; }
.ticker, .probes { min-width: 0; }
.probe:last-child { border-bottom: none; }
.probe .t { color: var(--dim); }
.probe .eng { color: var(--cyan); }
.probe .srf { color: var(--mut); }
.probe .loc { color: var(--dim); }
.prompt-muted { color: var(--dim); }
.probe .pb { color: var(--ink); }
.probe .pb i { color: var(--dim); font-style: normal; font-size: 10px; margin-left: 6px; }

/* ---- contest -------------------------------------------------------------------------------- */
.contest-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.contest-card { border: 1px solid var(--line); background: var(--panel); padding: 14px 16px; }
.contest-card h3 { font-size: 12px; letter-spacing: 0.08em; margin-bottom: 2px; }
.contest-card h3 a { color: var(--ink); }
.contest-card .cc-foot { margin-top: 10px; color: var(--dim); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.contest-card .cc-srf { color: var(--dim); font-size: 10.5px; margin-bottom: 10px; }
/* The verdict is a WORD, and the word carries the meaning. It was amber-for-contested and green-for-
   resolved, which is a third and fourth hue encoding nothing the word does not already say, on a site
   whose legend promises that colour means one thing. */
.verdict { font-size: 12px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 10px; color: var(--ink); }
.ptop { list-style: none; }
.ptop li { display: flex; gap: 10px; align-items: center; padding: 3px 0; font-size: 11.5px; }
.ptop .pb-name { flex: 0 0 92px; overflow: hidden; text-overflow: ellipsis; }
.ptop .pb-bar { flex: 1; height: 6px; background: var(--bg2); border: 1px solid var(--line); position: relative; }
.ptop .pb-fill { position: absolute; inset: 0 auto 0 0; background: var(--ci); }
.ptop .pb-val { color: var(--ink); white-space: nowrap; font-size: 11px; font-variant-numeric: tabular-nums; }
.ptop .pb-val i { color: var(--dim); font-style: normal; }

/* ---- divergence ------------------------------------------------------------------------------ */
.div-table { border: 1px solid var(--line); background: var(--panel); }
.div-row {
  display: grid; grid-template-columns: 210px 1fr 300px; gap: 16px; align-items: center;
  padding: 11px 16px; border-bottom: 1px solid var(--line);
}
.div-row:last-child { border-bottom: none; }
.div-row .dn a { color: var(--ink); font-weight: 700; }
.div-row .dn .engs { display: block; color: var(--dim); font-size: 10.5px; margin-top: 2px; }
.div-num { font-size: 11.5px; color: var(--mut); text-align: right; white-space: nowrap; }
.div-num b { color: var(--ink); }

/* ---- coverage -------------------------------------------------------------------------------- */
.cov-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; margin-bottom: 16px; }
.cov-tile { border: 1px solid var(--line); background: var(--panel); padding: 14px 16px; }
.cov-tile b { display: block; font-size: 24px; font-weight: 700; }
.cov-tile .cv-cap { display: block; color: var(--dim); font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; margin-top: 4px; }
.cov-tile .cv-sub { display: block; color: var(--mut); font-family: var(--sans); font-size: var(--t-body); margin-top: 6px; line-height: 1.6; }
.cov-table { width: 100%; border-collapse: collapse; border: 1px solid var(--line); background: var(--panel); font-size: 11.5px; }
.cov-table th, .cov-table td { text-align: left; padding: 7px 14px; border-bottom: 1px solid var(--line); }
.cov-table th { color: var(--dim); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 400; }
.cov-table tr:last-child td { border-bottom: none; }
.cov-table td.num, .cov-table th.num { text-align: right; }

/* ---- prose ----------------------------------------------------------------------------------- */
.prose { max-width: 76ch; }
.prose h2 { font-size: 14px; letter-spacing: 0.18em; text-transform: uppercase; margin: 34px 0 10px; color: var(--ink); }
.prose h2 .pn { color: var(--dim); margin-right: 10px; }
.prose p { color: var(--mut); margin: 0 0 12px; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.prose strong { color: var(--ink); }
.prose ul { margin: 0 0 12px 18px; color: var(--mut); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.prose li { margin-bottom: 5px; }
/* Inline code and the probe ticker carry instrument readings inside the paper column. */
.prose code, .prose .probes { font-family: var(--mono); }
.methodology-changelog code { overflow-wrap: anywhere; }

/* Methodology two-column: prose left (capped at its reading measure), a sticky section index right,
   so the page fills its width instead of leaving the right ~45% empty on desktop. */
.method-layout { display: grid; grid-template-columns: minmax(0, 76ch) 1fr; gap: 44px; align-items: start; }
.method-layout .prose { max-width: none; }
.method-toc {
  position: sticky; top: 84px; align-self: start;
  border-left: 1px solid var(--line2); padding-left: 18px;
}
.method-toc .mt-head {
  color: var(--dim); font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; margin-bottom: 12px;
}
.method-toc .mt-list { list-style: none; }
.method-toc .mt-list li { margin-bottom: 8px; }
.method-toc .mt-list a { color: var(--mut); font-size: 11.5px; display: flex; gap: 9px; align-items: baseline; }
.method-toc .mt-list a:hover { color: var(--focus); }
.method-toc .mt-n { color: var(--ink); flex: 0 0 auto; }

.ladder { width: 100%; border-collapse: collapse; border: 1px solid var(--line); background: var(--panel); font-size: 12px; margin: 14px 0 20px; }
.ladder th, .ladder td { padding: 8px 14px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.ladder th { color: var(--dim); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 400; }
.ladder tr:last-child td { border-bottom: none; }
.ladder td.g { font-size: 14px; }

/* ---- brand page ------------------------------------------------------------------------------ */
/* ONE table, not three boxed cards each carrying its own repeated header row for a single data row.
   Three boxes and three header rows to show three numbers is divider soup; the rows are now rows. */
.standing { border-bottom: 1px solid var(--line); }
.standing:last-of-type { border-bottom: 0; }
.standing .st-head {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  padding: 10px 16px; border-bottom: 1px solid var(--line); background: var(--panel2);
}
.standing .st-body {
  align-items: center; padding: 12px 16px;
}
.standing .st-note { color: var(--dim); font-size: 11px; }
.standing .st-trend { justify-self: start; color: var(--dim); font-size: 10.5px; }
.standing .st-base { display: inline-flex; align-items: center; gap: 6px; }

.brand-links { color: var(--dim); font-family: var(--sans); font-size: var(--t-body); margin: 10px 0 4px; line-height: 1.6; }

/* ---- brands index ----------------------------------------------------------------------------
   Bordered cards with a real gap, NOT a 1px grid gap over a shared background: the shared-background
   trick painted a phantom "broken" tile in the empty slot of the last row. Transparent gaps + a border
   per card means an empty slot is simply nothing. */
.bx-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 10px; }
.bx-row {
  display: flex; flex-direction: column; align-items: stretch; gap: 8px; padding: 12px 14px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px; color: inherit;
  text-decoration: none;
}
.bx-row:hover { border-color: var(--dim); background: var(--panel2); text-decoration: none; }
.bx-head { display: flex; align-items: center; gap: 12px; min-width: 0; }
/* The name owns the width and truncates with an ellipsis; it never shatters character-by-character. */
.bx-name {
  color: var(--ink); font-weight: 700; font-size: 13px; flex: 1 1 auto; min-width: 0;
  /* wrap only at hyphens/spaces (samsung-galaxy-buds -> two clean lines), never mid-word: the shatter
     was overflow-wrap:anywhere breaking inside a word. */
  overflow-wrap: normal; word-break: normal; line-height: 1.25;
}
/* One row per measured surface (R110). Each row is one cell's own reading: no row is a function of
   any other row, and there is no summary line over them, because the summary was the fusion. */
.bx-surfaces { display: flex; flex-direction: column; gap: 1px; }
.bxs {
  display: grid; grid-template-columns: 78px minmax(0, 1fr) auto; align-items: baseline; gap: 8px;
  padding: 3px 0; border-top: 1px solid var(--line);
}
.bxs-eng { color: var(--mut); font-size: 10.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bxs .league-tag { color: var(--dim); font-size: 10px; letter-spacing: 0.06em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bxs .league-tag.league-low-precision { color: var(--mut); }
.bxs-val {
  color: var(--ink); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap;
  text-align: right;
}
.bxs-val b { font-weight: 700; }
.bxs-ci { color: var(--mut); font-size: 10px; margin-left: 6px; }
.bxs-n { color: var(--dim); font-size: 10px; margin-left: 6px; }
.bxs.lp .bxs-val b { color: var(--mut); }
/* A surface with no standing for this brand carries no league cell, so its words take both remaining
   tracks instead of leaving a hole where a league label would be. */
.bxs-none .bxs-val { grid-column: 2 / -1; color: var(--dim); font-size: 10.5px; text-align: left; }

/* ---- the engine picker (/e/chatgpt) -----------------------------------------------------------
   Two cards, the same bordered-card vocabulary the brands index uses, one per ChatGPT surface. The
   page exists because one vendor name maps to two measurements; the cards say which is which. */
.epick-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }
.epick {
  display: grid; gap: 6px; padding: 16px 18px; color: inherit; text-decoration: none;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
}
.epick:hover { border-color: var(--dim); background: var(--panel2); text-decoration: none; }
.epick-name { color: var(--ink); font-weight: 700; font-size: 15px; letter-spacing: 0.02em; }
.epick-sub { color: var(--mut); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.epick-go { color: var(--ink); font-family: var(--sans); font-size: var(--t-body); letter-spacing: 0.06em; margin-top: 4px; line-height: 1.6; }

/* ---- coverage map ----------------------------------------------------------------------------
   R114: the market CARDS lead the section and the map is an index beside the folded queue, at about
   half its old footprint (the fixed-size ISO markers now carry the "where" at a glance, so the map no
   longer needs to be the exhibit). */
.cov { display: grid; grid-template-columns: minmax(0, 460px) minmax(240px, 1fr); gap: 26px; align-items: start; margin-top: 18px; }
.covmap-wrap { position: relative; width: 100%; max-width: 460px; min-width: 0; }
#covmap { position: relative; border: 1px solid var(--line); background: var(--bg2); border-radius: 8px; overflow: hidden; }
/* The world, as a MASK over a token colour. The file carries geometry only (alpha), so ONE cached asset
   paints the dark ground and the warm-paper light ground from --cov-land, and the theme toggle keeps
   repainting it live. An <img> would have baked one palette into the file. */
.covmap-base {
  display: block; width: 100%; aspect-ratio: 1000 / 519; background-color: var(--cov-land);
  -webkit-mask-image: url("img/world-map-c7e7d057.svg"); mask-image: url("img/world-map-c7e7d057.svg");
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
}
/* The wave's own colouring, laid over the mask on the same viewBox. Its default colour is the land tone
   underneath, so a country that reaches this layer without a rule is invisible rather than wrong. */
#covmap svg.covmap-live {
  position: absolute; inset: 0; display: block; width: 100%; height: 100%; color: var(--cov-land);
}
/* Without mask support the base would paint a SOLID rectangle where the world should be, which reads as a
   broken panel rather than as a map. Hidden there instead, and the overlay returns to the flow: with the base
   gone it is the only child, and an absolutely-positioned only child leaves #covmap zero pixels tall.
   It has to sit AFTER the rule above, not before it: same specificity, so source order is what decides. */
@supports not ((mask-image: url("")) or (-webkit-mask-image: url(""))) {
  .covmap-base { display: none; }
  #covmap svg.covmap-live { position: static; height: auto; }
}
/* A printed board is a cited board. A background behind a mask is dropped by print's default colour
   economy, which would print the coloured markets floating with no coastline under them. */
@media print {
  .covmap-base { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}
/* live/queued are set inline per ISO */
#covmap [data-iso] {
  transition: color .2s;
  /* The coast preserves country boundaries; the queued fill now sits above unqueued land. */
  stroke: var(--cov-land); stroke-width: 1px; vector-effect: non-scaling-stroke;
}
/* R114: the fixed-size market markers. HTML badges positioned by percentage over the map, so their
   pixel size never scales with the map and the ISO code stays readable at any width. */
.cov-anchor { position: absolute; width: 0; height: 0; pointer-events: none; }
.cov-anchor::before {
  content: ""; position: absolute; width: var(--leader); height: 1px;
  background: var(--ink); box-shadow: 0 0 0 .5px var(--cov-land);
  transform-origin: 0 50%; transform: rotate(var(--angle));
}
.cov-mark {
  position: absolute; left: var(--dx); top: var(--dy); transform: translate(-50%, -50%); width: 24px; height: 24px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ink); color: var(--bg); font-size: 8.5px; font-weight: 700; letter-spacing: 0.04em;
  border: 2px solid var(--bg2); box-shadow: 0 0 0 1px var(--ink), 0 2px 8px rgba(0,0,0,0.35);
  pointer-events: none;
}
.covmap-key { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 10px; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--dim); }
.covmap-key .ck { display: inline-flex; align-items: center; gap: 6px; }
.covmap-key .ck::before { content: ""; width: 11px; height: 11px; border-radius: 3px; background: var(--cov-queued); }
.covmap-key .ck-live::before { background: var(--cov-measured); border: 1px solid var(--cov-land); }
.covmap-key .ck-land::before { background: var(--cov-land); }

/* R114: one card per measured market, three primary values big, the secondary line under them, the
   whole card a doorway onto that market's own board page. */
.mk-live-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }
.mk-live {
  display: flex; flex-direction: column; gap: 12px; padding: 16px; color: inherit; min-width: 0; text-decoration: none;
  border: 1px solid var(--ink); border-radius: 8px; background: var(--panel);
}
.mk-live:hover { border-color: var(--ink); text-decoration: none; }
.mk-head { display: flex; align-items: center; gap: 10px; min-width: 0; }
.mk-flag {
  flex: 0 0 auto; width: 34px; height: 24px; border-radius: 4px; display: inline-flex; align-items: center;
  justify-content: center; font-size: 10px; font-weight: 700; letter-spacing: 0.04em;
  background: var(--ink); color: var(--bg);
}
.mk-flag-q { background: var(--panel2); color: var(--dim); border: 1px solid var(--line2); }
.mk-title { display: flex; flex: 1 1 auto; min-width: 0; flex-direction: column; align-items: flex-start; gap: 3px; }
.mk-name { color: var(--ink); font-weight: 700; font-size: 13px; display: flex; align-items: center; gap: 8px; min-width: 0; }
.mk-tag { font-size: 8.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--acc); border: 1px solid var(--acc-dim); border-radius: 3px; padding: 0 5px; font-weight: 400; }
.mk-loc { white-space: nowrap; font-family: var(--mono); font-size: 10.5px; color: var(--dim); }
.mk-go { flex: 0 0 auto; margin-left: auto; color: var(--ink); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; }
.mk-vals { display: flex; gap: 22px; }
.mk-val { display: flex; flex-direction: column; min-width: 0; }
.mk-val b { font-size: 22px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; line-height: 1.15; }
.mk-cap { color: var(--dim); font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; margin-top: 3px; }
.mk-vsub { color: var(--mut); font-size: 10.5px; margin-top: 2px; }
.mk-sub { color: var(--mut); font-size: 11px; font-variant-numeric: tabular-nums; }
.mk-sub b { color: var(--ink); }
.mk-scope { color: var(--ink); }
/* R114: the queue folds. Collapsed by default; the summary still counts what is queued. */
.mk-qfold { min-width: 0; }
.mk-qsum {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  border: 1px solid var(--line); border-radius: 8px; padding: 10px 14px;
  color: var(--mut); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
}
.mk-qsum::-webkit-details-marker { display: none; }
.mk-qsum .mk-qn { color: var(--dim); font-variant-numeric: tabular-nums; }
.mk-qsum .fb-caret { margin-left: auto; }
.mk-qfold[open] > .mk-qsum { color: var(--ink); border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.mk-qfold[open] > .mk-qsum .fb-caret { transform: rotate(180deg); }
.mk-queue { border: 1px solid var(--line); border-top: 0; border-radius: 0 0 8px 8px; overflow: hidden; }
.mk-region { display: flex; align-items: center; justify-content: space-between; padding: 8px 14px 4px; color: var(--dim); font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase; background: var(--panel2); }
.mk-region-n { font-variant-numeric: tabular-nums; letter-spacing: 0; }
.mk-row { display: flex; align-items: center; gap: 10px; padding: 8px 14px; border-top: 1px solid var(--line); }
.mk-row .mk-flag { width: 26px; height: 18px; font-size: 8.5px; }
.mk-row .mk-name { flex: 1; font-weight: 400; font-size: 12px; color: var(--mut); }
.mk-q { color: var(--dim); font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase; }
/* Market-page boards: a category heading above each brand x engine matrix, and the hero's wave line. */
.cov-cat { font-size: 13px; font-weight: 600; letter-spacing: 0.01em; color: var(--ink); margin: 22px 0 10px; }
.cov-cat:first-of-type { margin-top: 6px; }
/* This line contains measurement dates, age and a wave id, so it keeps the instrument voice. */
.mkt-note { margin-top: 10px; color: var(--dim); font-size: 11.5px; font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ---- real answers: photorealistic ChatGPT chat recreations ---------------------------------- */
.ans-cat { margin-top: 34px; }
.ans-cat:first-of-type { margin-top: 10px; }
.ans-cat-h { font-size: 14px; font-weight: 700; color: var(--ink); margin: 0 0 16px; display: flex; align-items: baseline; gap: 10px; }
.ans-cat-n { font-size: 10px; font-weight: 400; letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim); }
.cell-state { display: block; margin-top: 4px; color: var(--dim); font-size: 9px; font-weight: 400; letter-spacing: 0.1em; text-transform: uppercase; }

/* /answers INDEX: a light linked list of every captured answer. No inlined product images here (the
 * fragment page carries its own), so the index stays tiny. */
.ans-idx-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.ans-idx-item { margin: 0; }
.ans-idx-link { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; padding: 12px 15px; border: 1px solid var(--line); border-radius: 9px; background: var(--panel); color: var(--ink); text-decoration: none; }
.ans-idx-link:hover, .ans-idx-link:focus-visible { border-color: var(--line2); background: var(--panel2); }
.ans-idx-q { font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.ans-idx-meta { flex: 0 0 auto; font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.06em; color: var(--dim); font-variant-numeric: tabular-nums; }

/* A fragment page's provenance line under the mounted recreation (specimen mat + caption). */
.frag { max-width: 660px; }
.frag-prov { margin-top: 14px; font-family: var(--sans); font-size: var(--t-body); color: var(--dim); line-height: 1.6; }
.frag-tier { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); border: 1px solid var(--line2); border-radius: 999px; padding: 1px 7px; margin-right: 8px; white-space: nowrap; }

/* Evidence doorway row under a category board: from each engine column to the real answers behind it. */
.evidence { margin-top: 14px; display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 14px; }
.evidence-lab { font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim); flex: 0 0 auto; }
.evidence-doors { display: flex; flex-wrap: wrap; gap: 8px; }
.door { display: inline-flex; align-items: baseline; gap: 8px; padding: 5px 11px; border: 1px solid var(--line); border-radius: 999px; background: var(--panel); color: var(--ink); text-decoration: none; font-size: 12.5px; }
.door:hover, .door:focus-visible { border-color: var(--line2); background: var(--panel2); }
.door-eng { font-weight: 600; }
.door-n { color: var(--dim); }
.door-go { color: var(--dim); }

/* The evidence drawer: a right-side panel that mounts the real answers behind a board cell, over a scrim.
 * Progressive enhancement over the doorway link; hidden until opened. Both themes via shared tokens. */
.drawer { position: fixed; inset: 0; z-index: 60; background: rgba(0,0,0,0.5); }
.drawer[hidden] { display: none; }
.dr-panel { position: absolute; top: 0; right: 0; height: 100%; width: min(560px, 94vw); background: var(--panel); border-left: 1px solid var(--line2); box-shadow: -12px 0 44px rgba(0,0,0,0.4); display: flex; flex-direction: column; }
.dr-head { display: flex; align-items: center; gap: 12px; padding: 15px 20px; border-bottom: 1px solid var(--line); flex: 0 0 auto; }
.dr-head-t { font-size: 13px; font-weight: 600; color: var(--ink); margin: 0; }
.dr-close { margin-left: auto; font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--dim); background: transparent; border: 1px solid var(--line2); border-radius: 999px; padding: 4px 12px; cursor: pointer; }
.dr-close:hover, .dr-close:focus-visible { color: var(--ink); border-color: var(--ink); }
.dr-body { overflow-y: auto; padding: 18px 20px 28px; flex: 1 1 auto; }
.dr-chats { display: flex; flex-direction: column; gap: 18px; }
.dr-load { color: var(--dim); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.dr-more { margin-top: 18px; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.dr-more a { color: var(--ink); } /* --accent-ink was phantom: its fallback was var(--ink), and the fallback is what shipped. */
/* The cell's own fact (rate, interval, n, tier), stated at the top of the panel before any fetch
 * lands, and the partial-load state under it ("5 of 6 loaded"). Honest even when the network is not. */
.dr-fact { color: var(--mut); font-size: 12px; margin: 0 0 14px; }
/* The download link for the cell's reproducibility bundle (R27). It sits with the fact line, above the
   evidence, because it is what the panel's own numbers came from rather than a further reading. */
.dr-bundle { margin: -6px 0 14px; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.dr-bundle a { color: var(--ink); } /* --accent-ink was phantom: its fallback was var(--ink), and the fallback is what shipped. */
.dr-state { color: var(--dim); font-family: var(--sans); font-size: var(--t-body); margin-top: 14px; line-height: 1.6; }
.dr-probes { overflow-x: auto; }

/* The per-prompt evidence sheet (API cells): one row per probe of the committed wave, on its own
 * /probes page and mounted inside the drawer. Brands alphabetical; a .hit marks the door's brand. */
.probe-sheet { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.probe-sheet .pb-cap { caption-side: top; text-align: left; color: var(--dim); font-family: var(--sans); font-size: var(--t-body); padding-bottom: 10px; line-height: 1.6; }
.probe-sheet thead th { text-align: left; color: var(--dim); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600; padding: 6px 12px 6px 0; border-bottom: 1px solid var(--line2); }
.probe-sheet tbody th, .probe-sheet tbody td { text-align: left; padding: 7px 12px 7px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.probe-sheet tbody tr:last-child th, .probe-sheet tbody tr:last-child td { border-bottom: 0; }
.probe-sheet .pb-id { font-family: var(--mono); font-size: 11.5px; color: var(--mut); font-weight: 400; white-space: nowrap; }
.probe-sheet .pb-mode { color: var(--dim); white-space: nowrap; }
.probe-sheet .pb-brands { color: var(--ink); }
.probe-sheet .pb-sep { color: var(--dim); padding: 0 5px; }
.probe-sheet .pb-none { color: var(--dim); font-size: 11.5px; }
.probe-sheet .pb-b.hit { color: var(--ink); font-weight: 600; }

/* The flagship UI-vs-API diptych: the real answer (left) beside the API distribution (right). */
.diptych { margin: 30px 0 8px; }
.dip-kicker { font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim); margin: 0 0 8px; }
.dip-h { font-size: clamp(1.2rem, 2.4vw, 1.55rem); line-height: 1.18; margin: 0 0 20px; max-width: 34ch; }
.dip-plate { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; align-items: start; }
/* min-width:0 because a grid ITEM's automatic minimum is its min-content width, and this panel holds
   the seven-card product rail. Without it the panel measures ~1215px inside a 350px track and takes the
   whole page sideways with it (measured at 390px on /c/running-shoes). The rail scrolls inside. */
.dip-panel { border: 1px solid var(--line); border-radius: 14px; padding: 16px; background: var(--panel); min-width: 0; }
.dip-lab { font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); margin-bottom: 14px; }
.dip-sub { color: var(--dim); text-transform: none; letter-spacing: 0; }
.dip-rows { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; column-gap: 12px; }
.dip-row { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: baseline; padding: 8px 6px; border-bottom: 1px solid var(--line); }
.dip-row:last-child { border-bottom: 0; }
.dip-brand { min-width: 0; font-size: 14px; overflow-wrap: anywhere; }
.dip-row .rate { grid-column: 2; justify-self: end; text-align: right; }
.dip-gap { background: var(--panel2); border-radius: 6px; } /* --accent-soft was phantom. */
.dip-flag { grid-column: 3; font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink); white-space: nowrap; } /* --accent-ink was phantom: its fallback was var(--ink), and the fallback is what shipped. */
@media (max-width: 600px) {
  .dip-rows { grid-template-columns: minmax(0, 1fr) auto; }
  .dip-flag { grid-column: 1; grid-row: 2; white-space: normal; }
  .dip-row .rate { max-width: 100%; white-space: normal; }
}
.dip-note { margin-top: 16px; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; color: var(--dim); max-width: 80ch; } /* --ink-dim was phantom. */
/* The Divergence Index register: exact membership counts + the null-results line, framed as one named index
   whose published number is still measuring. Counts and names only, never a rate, so it implies no interval. */
.dip-index { border: 1px solid var(--line); border-radius: 14px; padding: 14px 16px; margin: 0 0 20px; background: var(--panel); }
.dix-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px; }
.dix-name { font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); }
.dix-state { font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); border: 1px solid var(--dim); border-radius: 999px; padding: 2px 8px; }
.dix-num { font-size: 14px; color: var(--ink); }
.dix-num b { font-variant-numeric: tabular-nums; }
.dix-num .ci { font-size: 11px; color: var(--dim); font-variant-numeric: tabular-nums; }
/* The register carries no column header, so the interval names its own confidence level in place. */
.dix-lvl { font-size: 11px; color: var(--dim); }
.dix-facts { display: flex; flex-wrap: wrap; gap: 12px 28px; margin: 0; }
.dix-facts > div { display: flex; flex-direction: column; gap: 3px; }
.dix-facts dt { font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--dim); }
.dix-facts dd { margin: 0; font-size: 13.5px; color: var(--ink); }
.dix-null dd { color: var(--dim); } /* --ink-dim was phantom. */
.dix-foot { margin: 12px 0 0; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; color: var(--dim); max-width: 80ch; } /* --ink-dim was phantom. */
/* minmax(0, 1fr), like the two-column template above it. A bare 1fr carries an automatic min-content
   minimum, so the phone template was the one place the diptych could still expand to the product
   rail's intrinsic width: the fix on the base rule never reached the media override. */
@media (max-width: 760px) { .dip-plate { grid-template-columns: minmax(0, 1fr); } }

/* The glossary: term/definition rows on a dedicated readability page. */
.gloss { margin: 24px 0 0; }
.gloss-row { display: grid; grid-template-columns: 210px 1fr; gap: 20px; padding: 16px 0; border-bottom: 1px solid var(--line); }
.gloss-row:last-child { border-bottom: 0; }
.gloss-t { font-weight: 600; font-size: 14px; color: var(--ink); }
.gloss-d { font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; color: var(--dim); margin: 0; max-width: 72ch; } /* --ink-dim was phantom. */
.gloss-foot { margin-top: 26px; font-family: var(--sans); font-size: var(--t-body); color: var(--dim); line-height: 1.6; }
.gloss-foot a { color: var(--ink); } /* --accent-ink was phantom: its fallback was var(--ink), and the fallback is what shipped. */
@media (max-width: 640px) { .gloss-row { grid-template-columns: 1fr; gap: 4px; } }

/* A citable claim page: the fact, its provenance, and a cite-this block. */
.claim { max-width: 720px; }
.claim-legend { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--dim); margin: 8px 0 4px; }
.claim-members { display: flex; flex-direction: column; margin: 0 0 24px; }
.claim-row { display: flex; align-items: baseline; gap: 12px; padding: 9px 6px; border-bottom: 1px solid var(--line); }
.claim-row:last-child { border-bottom: 0; }
.claim-brand { flex: 1 1 auto; font-size: 15px; }
.claim-lp .claim-brand, .claim-lp .rate { color: var(--dim); }
.claim-flag { flex: 0 0 auto; font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dim); }
.claim-measuring { margin: 8px 0 24px; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; color: var(--dim); max-width: 66ch; } /* --ink-dim was phantom. */
.claim-archived, .claim-bundle, .claim-illustrative { font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.claim-meta { display: grid; grid-template-columns: 150px 1fr; gap: 8px 18px; margin: 0 0 22px; font-size: 13px; }
.claim-meta > div { display: contents; }
.claim-meta dt { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--dim); }
.claim-meta dd { margin: 0; color: var(--ink); }
.claim-evidence { margin: 0 0 24px; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
.claim-evidence a { color: var(--ink); } /* --accent-ink was phantom: its fallback was var(--ink), and the fallback is what shipped. */
.cite { border: 1px solid var(--line2); border-radius: 12px; padding: 16px 18px; background: var(--panel); }
.cite-lab { font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim); margin: 0 0 8px; }
.cite-text { margin: 0; font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; color: var(--ink); user-select: all; }
/* The copy-citation button (R101). Progressive enhancement: without JS the .cite-text above stays a
   selectable paragraph, so the button is a convenience, never the only path to the citation. */
.cite-copy {
  margin-top: 10px; padding: 6px 12px; border: 1px solid var(--line2); border-radius: 7px;
  background: var(--panel2); color: var(--ink); font-family: var(--mono);
  font-size: 11px; letter-spacing: 0.04em; cursor: pointer;
}
.cite-copy:hover, .cite-copy:focus-visible, .cite-copy[data-done="ok"] { border-color: var(--ink); color: var(--ink); }
@media (max-width: 560px) { .claim-meta { grid-template-columns: 1fr; gap: 2px 0; } }

/* ---- fragment identity (R101): the question as H1, prev/next in the set, the way back ---------- */
.frag-h1 { max-width: 46ch; }
.frag-nav {
  margin-top: 18px; display: flex; align-items: stretch; gap: 12px;
  border-top: 1px solid var(--line); padding-top: 14px;
}
.frag-adj {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 4px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 9px; background: var(--panel); color: var(--ink);
  text-decoration: none;
}
.frag-adj:hover, .frag-adj:focus-visible { border-color: var(--line2); background: var(--panel2); text-decoration: none; }
.frag-adj-none { border: 0; background: none; }
.fn-lab { font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim); }
.fn-q { font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.fn-count { flex: 0 0 auto; align-self: center; font-family: var(--mono); font-size: 10.5px; color: var(--dim); white-space: nowrap; }
.frag-links { margin-top: 14px; margin-bottom: 18px; }
@media (max-width: 560px) {
  .frag-nav { flex-wrap: wrap; }
  .fn-count { order: -1; flex-basis: 100%; text-align: center; }
}

/* ---- the engine page pyramid (R105): board first, the measuring tail under a divider ----------- */
.board-split {
  display: flex; align-items: center; gap: 12px; margin: 6px 0 2px;
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim);
}
.board-split::before, .board-split::after { content: ""; flex: 1 1 auto; border-top: 1px solid var(--line2); }
.board-split span { flex: 0 0 auto; }

/* The per-cell cite link (R102) and the first-use glossary link on the card's n (R105). */
.cell-cite { font-size: 11px; color: var(--dim); text-decoration: underline; text-underline-offset: 2px; }
.cell-cite:hover, .cell-cite:focus-visible { color: var(--focus); }
.m-gloss { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.m-gloss:hover, .m-gloss:focus-visible { color: var(--focus); }

/* The facet bar: the single spatial model, a sentence of linked segments under the wave band. */
.facetbar { display: flex; align-items: center; flex-wrap: wrap; gap: 2px 6px; padding: 8px 28px; border-bottom: 1px solid var(--line); font-family: var(--mono); font-size: 11.5px; }
.fb-seg { display: inline-flex; align-items: center; gap: 5px; color: var(--ink); cursor: pointer; list-style: none; padding: 3px 8px; border-radius: 6px; }
.fb-seg::-webkit-details-marker { display: none; }
.fb-static { cursor: default; color: var(--dim); }
.fb-caret { color: var(--dim); font-size: 9px; }
.fb-dot { color: var(--line2); }
/* A foldable segment plus the separator that belongs to it, as one unit (R111): the wave. It folds
   away at phone width and may not leave its "·" behind. */
.fb-wave { display: inline-flex; align-items: center; gap: 2px 6px; }
.fb-drop { position: relative; }
.fb-drop[open] > .fb-seg { background: var(--panel2); }
.fb-menu { position: absolute; top: 100%; left: 0; z-index: 40; margin-top: 4px; min-width: 180px; display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--line2); border-radius: 8px; box-shadow: 0 8px 26px rgba(0,0,0,0.35); padding: 5px; }
.fb-menu a { padding: 7px 10px; border-radius: 5px; color: var(--ink); text-decoration: none; font-size: 12px; white-space: nowrap; }
.fb-menu a:hover, .fb-menu a:focus-visible { background: var(--panel2); }
@media (max-width: 640px) { .facetbar { padding: 8px 16px; } }
/* The lens itself moved OUT of the facet bar (R107): its control and all of its emphasis rules live
   in MATRIX_CSS, beside the table markup they read, and no lens rule may name an engine. */

/* The citation observatory: which publishers the engines drew on, counted per category. */
.src-cat { margin-top: 30px; }
.src-cat:first-of-type { margin-top: 12px; }
.src-rows { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; max-width: 640px; }
.src-row { display: grid; grid-template-columns: 210px 1fr 36px; align-items: center; gap: 12px; }
.src-dom { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.src-bar { height: 8px; border-radius: 999px; background: var(--panel2); overflow: hidden; }
.src-fill { display: block; height: 100%; background: var(--ci); border-radius: 999px; } /* --accent was phantom. */
.src-n { font-family: var(--mono); font-size: 12px; color: var(--dim); text-align: right; font-variant-numeric: tabular-nums; }
/* The scope of the whole page, and the scale rule of each section's bars: both stated, never implied. */
.src-scope { margin: 10px 0 0; font-family: var(--sans); font-size: var(--t-body); color: var(--dim); font-variant-numeric: tabular-nums; line-height: 1.6; }
.src-scale { margin: 8px 0 0; font-family: var(--sans); font-size: var(--t-body); color: var(--dim); max-width: 640px; line-height: 1.6; }
.src-note { font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; }
@media (max-width: 560px) { .src-row { grid-template-columns: 130px 1fr 30px; gap: 8px; } .src-dom { font-size: 12px; } }
/* A gallery of recreations: two ChatGPT windows up on a wide screen, one on a phone. */
.chat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(430px, 1fr)); gap: 18px; align-items: start; }
/* One recreation = a light ChatGPT window on Luce's dark page (reads like a screenshot). Colours are
   explicit, NOT Luce tokens, so it stays a faithful ChatGPT light theme whatever the page theme is. */
.chat {
  background: #ffffff; color: #0d0d0d; border-radius: 16px; border: 1px solid rgba(0,0,0,0.06);
  box-shadow: 0 1px 2px rgba(0,0,0,0.30), 0 10px 30px rgba(0,0,0,0.28); overflow: hidden;
  font-family: ui-sans-serif, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  display: flex; flex-direction: column; min-width: 0;
}
.chat-bar { display: flex; align-items: center; gap: 8px; padding: 10px 15px; border-bottom: 1px solid #ececec; }
.chat-mark { width: 17px; height: 17px; color: #000; flex: 0 0 auto; display: inline-flex; }
.chat-name { font-size: 13px; font-weight: 600; color: #0d0d0d; }
.chat-market { white-space: nowrap; flex: 0 0 auto; font-size: 10px; font-weight: 600; letter-spacing: 0.02em; color: #10725a; background: #e7f6f1; border-radius: 5px; padding: 1px 6px; font-variant-numeric: tabular-nums; }
.chat-tag { margin-left: auto; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: #6e6e80; }
.chat-thread { padding: 16px; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.msg-user { display: flex; justify-content: flex-end; }
.msg-user .ub { background: #f4f4f4; color: #0d0d0d; border-radius: 18px; padding: 9px 15px; font-size: 14px; line-height: 1.42; max-width: 86%; }
.msg-asst { display: flex; gap: 11px; align-items: flex-start; min-width: 0; }
.asst-ava { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; background: #000; color: #fff; display: inline-flex; align-items: center; justify-content: center; padding: 5px; }
.asst-ava svg { width: 100%; height: 100%; }
.asst-body { min-width: 0; flex: 1; }
.asst-lead p { font-size: 14px; line-height: 1.6; color: #2d2d33; margin: 0 0 8px; }
.asst-lead strong { color: #0d0d0d; font-weight: 600; }
/* The product carousel: real photos, ChatGPT-shopping-card style, horizontal scroll. */
.prod-carousel { min-width: 0; }
.prod-controls { display: flex; align-items: center; justify-content: flex-end; gap: 7px; margin: 4px 0 2px; }
.prod-arrow { width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid #d9d9de; border-radius: 999px; background: #fff; color: #40414f; cursor: pointer; touch-action: manipulation; font-size: 18px; line-height: 1; }
.prod-arrow:hover, .prod-arrow:focus-visible { border-color: #8e8e98; color: #0d0d0d; }
.prod-arrow:focus-visible { outline: 2px solid #3b6fd4; outline-offset: 2px; }
.prod-arrow:disabled { cursor: default; opacity: 0.35; }
.prod-count { min-width: 54px; color: #6e6e80; font-size: 10.5px; text-align: center; font-variant-numeric: tabular-nums; }
.prod-rail { list-style: none; margin: 3px 0 4px; padding: 2px 0 10px; display: flex; gap: 10px; min-width: 0; overflow-x: auto; overscroll-behavior-inline: contain; scroll-snap-type: x mandatory; scrollbar-width: thin; }
.prod { flex: 0 0 150px; width: 150px; border: 1px solid #e6e6e6; border-radius: 12px; background: #fff; overflow: hidden; display: flex; flex-direction: column; scroll-snap-align: start; }
.prod-img { display: block; width: 100%; height: 116px; background: #f6f6f7; padding: 7px; }
.prod-img img { width: 100%; height: 100%; object-fit: contain; display: block; }
.prod-img-none { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; }
.prod-photo-note { color: #6e6e80; font-size: 9.5px; line-height: 1.2; text-align: center; }
.prod-info { padding: 8px 10px 11px; display: flex; flex-direction: column; gap: 4px; }
.prod-title { font-size: 12px; font-weight: 600; color: #0d0d0d; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.6em; }
.prod-meta { display: flex; flex-direction: column; gap: 1px; }
.prod-price { font-size: 13px; font-weight: 700; color: #0d0d0d; font-variant-numeric: tabular-nums; }
.prod-merch { font-size: 10.5px; color: #6e6e80; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The full verbatim reply, collapsed by default (ChatGPT's link-blue affordance). */
.chat-full { margin-top: 8px; }
.chat-full > summary { cursor: pointer; font-size: 12.5px; color: #3b6fd4; list-style: none; }
.chat-full > summary::-webkit-details-marker { display: none; }
.chat-full > summary::before { content: "▸ "; color: #a0a0ab; }
.chat-full[open] > summary::before { content: "▾ "; }
/* Uncapped: it is already click-gated behind the details, so let the full reply be readable rather than
   trapping it in a nested scroll box that fights the page. */
.chat-verbatim { margin-top: 9px; padding: 0 8px 0 12px; border-left: 2px solid #ececec; }
.chat-verbatim p { font-size: 13px; line-height: 1.6; color: #40414f; margin: 0 0 9px; }
.chat-verbatim strong { color: #0d0d0d; font-weight: 600; }
.chat-src { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 13px; }
.chat-src .src-lab { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: #6e6e80; margin-right: 2px; }
.chat-src .src-chip { font-size: 11px; color: #40414f; background: #f4f4f4; border: 1px solid #e6e6e6; border-radius: 5px; padding: 2px 8px; }
@media (max-width: 760px) {
  .chat-grid { grid-template-columns: 1fr; }
}

/* ---- footer ---------------------------------------------------------------------------------- */
.site-foot { border-top: 1px solid var(--line); padding: 22px 0 34px; background: var(--railbg); }
.disclosure { color: var(--mut); font-family: var(--sans); font-size: var(--t-body); margin-bottom: 6px; line-height: 1.6; }
.foot-line { color: var(--dim); font-family: var(--sans); font-size: var(--t-fine); line-height: 1.6; }

/* ---- scroll guards --------------------------------------------------------------------------- */
.scroll-x { overflow-x: auto; }

/* ---- responsive ------------------------------------------------------------------------------ */
/* The rail is a desktop affordance. Below 1000px it unfolds into the top of the page as a single
   horizontally-scrolling strip: the same items, the same order, still the whole site map, but it
   costs one row instead of a column the content cannot spare. */
@media (max-width: 1000px) {
  .app { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; }
  .rail {
    position: static; height: auto; width: 100%;
    border-right: 0; border-bottom: 1px solid var(--line);
    padding: 16px 0 0;
  }
  .rail-sub { display: none; }
  /* WRAP, do not scroll. A one-row horizontal scroll strip clipped "All brands" to "All b" under the
     active underline and hid Coverage, Methodology and the three engine pages off the right edge with no
     affordance. Wrapping shows every destination, on two or three rows, and never clips a label. */
  .rail-nav {
    margin-top: 12px; flex-direction: row; flex-wrap: wrap; gap: 4px 2px; align-items: center;
    padding: 0 12px 6px;
  }
  /* display:contents flattens the groups so every LINK is a direct wrap unit of the nav; a wide group
     can no longer stay a single un-wrappable row. The group labels are hidden either way. */
  .rail-grp { display: contents; }
  .rail-lab { display: none; }
  .rail-nav a {
    padding: 6px 9px; border-left: 0; border: 1px solid var(--line); border-radius: 6px; white-space: nowrap; gap: 5px;
  }
  .rail-nav a.on { border-color: var(--ink); background: var(--panel); color: var(--ink); }
  .rail-foot {
    margin-top: 12px; padding: 10px 20px; width: 100%;
    flex-direction: row; align-items: center; justify-content: space-between;
  }
  .wrap { padding: 0 20px; }
  .wavebar { padding-left: 20px; padding-right: 20px; }
}
@media (max-width: 900px) {
  .sec-note { flex-basis: 100%; margin-left: 0; text-align: left; }
  .league-rail { padding-right: 8px; }
  /* The column header is a desktop affordance; on a stacked mobile row each value sits under its own
     label already, and the header would just eat a line. */
  .member-head, .league.cols { display: none; }
  /* Both selectors, or the .cell-card.no-trend override (higher specificity) keeps its desktop
     4-column grid inside this media query and the rate column runs off the viewport. */
  .member,
  .cell-card.no-trend .member,
  .cell-card.no-rank .member, .cell-card.no-rank.no-trend .member { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-auto-rows: auto; row-gap: 8px; }
  .member .rate { grid-column: 1; }
  .member .spark { grid-column: 2; grid-row: 2; justify-self: end; }
  /* Empty rank slots reserve the desktop spine and leave the stacked phone flow. */
  .member.lp .rank-cell, .standing.lp .rank-cell { display: none; }
  .member.lp .rate, .cell-card.no-rank .member .rate { grid-column: auto; }
  .member.lp .spark, .cell-card.no-rank .member .spark { grid-column: 1 / -1; grid-row: auto; }
  .probe { grid-template-columns: 92px 1fr 1fr; row-gap: 2px; }
  .probe .prompt, .probe .pb { grid-column: 1 / -1; }
  .div-row { grid-template-columns: 1fr; row-gap: 8px; }
  /* Let the long single-column lines wrap instead of running off a phone viewport (~360-390px):
     .div-num "0.23 bits excess · 95% CI … · noise floor … subtracted" is ~450px intrinsic and
     .rate "46% 95% CI 39-52%" ~238px, both nowrap on desktop. On mobile they wrap cleanly. */
  .div-num { text-align: left; white-space: normal; }
  .member .rate { white-space: normal; }
  .standing .st-body,
  .standing .st-body.no-trend, .standing .st-body.no-rank, .standing .st-body.no-rank.no-trend,
  .cell-card.no-rank .member, .cell-card.no-rank.no-trend .member { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  /* The standings rate ("80% 95% CI 63-93%") is nowrap on desktop and is NOT inside a .member, so the
     .member .rate rule above never reached it. */
  .standing .st-body .rate { white-space: normal; }
  /* The rank BAR is the component that was being misread as a rate bar. On a phone the row stacks and
     the bar has no header to name it, so it is pure ambiguity: drop it. The rank RANGE text
     ("ranks 1-3.5") stays and says the same thing, unambiguously. */
  .member .rr, .standing .st-body .rr { display: none; }
  .method-layout { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  /* the coverage map stacks above the markets list on a phone */
  .cov { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .bx-grid { grid-template-columns: minmax(0, 1fr); }
  /* The provenance ladder is a 5-column table with ~428px of min-content: it expanded its grid track
     and pushed the page sideways. Stack it label:value like the coverage table already does. */
  .ladder thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .ladder, .ladder tbody, .ladder tr, .ladder td { display: block; width: 100%; }
  .ladder tr { border: 1px solid var(--line); margin-bottom: 10px; }
  .ladder tr:last-child { margin-bottom: 0; }
  .ladder td { display: flex; justify-content: space-between; gap: 14px; text-align: right; padding: 6px 12px; border-bottom: 0; }
  .ladder td::before { content: attr(data-label); color: var(--dim); font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase; text-align: left; }
  .prose { min-width: 0; }
  .method-toc { position: static; border-left: none; padding-left: 0; }
  /* The 5-column coverage table cannot fit a phone width. Stack each engine into a label:value card
     so "cells passing precision gate" and "categories" (the real precision result) are never clipped
     the right edge. Column headers move into each cell via the data-label attribute. */
  .cov-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .cov-table, .cov-table tbody, .cov-table tr, .cov-table td { display: block; width: 100%; }
  .cov-table tr { border: 1px solid var(--line); margin-bottom: 10px; }
  .cov-table tr:last-child { margin-bottom: 0; }
  .cov-table td { display: flex; justify-content: space-between; gap: 14px; text-align: right; padding: 6px 12px; }
  .cov-table td.num { text-align: right; }
  .cov-table td::before { content: attr(data-label); color: var(--dim); font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase; text-align: left; align-self: center; }
}
@media (max-width: 560px) {
  /* The chip row (engine · tier · n = 30 · small-wave flag) bled a couple of pixels past the card's
     right padding at 360px. Let it wrap onto its own lines with real spacing. */
  .cell-head { flex-wrap: wrap; row-gap: 8px; }
  .cell-meta { margin-left: 0; row-gap: 6px; min-width: 0; }
  .member,
  .cell-card.no-trend .member,
  .standing .st-body,
  .standing .st-body.no-trend, .standing .st-body.no-rank, .standing .st-body.no-rank.no-trend,
  .cell-card.no-rank .member, .cell-card.no-rank.no-trend .member { grid-template-columns: minmax(0, 1fr); }
  .member .rate { grid-column: auto; }
  .member .spark { grid-column: auto; grid-row: auto; justify-self: stretch; }
  .member.lp .spark, .cell-card.no-rank .member .spark { grid-column: auto; grid-row: auto; justify-self: stretch; }
  /* The fixed 170px sparkline is the last thing forcing a league card wider than a ~360px phone.
     Let it (and the whole card chain) shrink to the column so nothing overflows the viewport. */
  .cell-card, .cell-head, .league, .members, .member { min-width: 0; }
  .spark { max-width: 100%; min-width: 0; }
  .spark svg { width: 100%; height: auto; }
  /* Wider rail + tighter tracking so "LEAGUE A" stays on one line instead of wrapping to "LEAGUE / A". */
  .league-rail { flex-basis: 90px; }
  .league-rail .league-tag { letter-spacing: 0.08em; }
  .bn, .st-head { overflow-wrap: anywhere; }
  /* Two-up on a 360px row. An odd final tile spans the row so there is no empty quadrant beside it. */
  .strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .strip .stat { border-bottom: 1px solid var(--line); }
  .strip .stat:nth-child(2n) { border-right: 0; }
  .strip .stat:nth-last-child(-n+2) { border-bottom: 0; }
  /* With an odd tile count the penultimate tile still belongs to the preceding two-up row. Restore
     its divider; only the full-width final tile closes the strip without one. */
  .strip .stat:nth-last-child(2):nth-child(even) { border-bottom: 1px solid var(--line); }
  .strip .stat:last-child:nth-child(odd) { grid-column: 1 / -1; border-right: 0; }
  .strip .st-lab { white-space: normal; }
}

/* ---- R111: the chrome is paid ONCE, at phone width ---------------------------------------------
   Measured at 390px, the shell cost about 375px before the first H1: a wordmark row, a search row,
   sixteen destinations wrapped over five rows of pills, a rail foot, a three-line honesty band and a
   two-line facet bar. That is a screenful of furniture in front of every page.

   Here the same chrome is ONE sticky 46px row (wordmark, wave tag, search, the Board button), a
   wrapping honesty band and one 32px facet line.

   Nothing is dropped to get there:
     - the sixteen destinations and the rail foot live in the Board panel, one tap away, and the panel
       is a native <details> so it opens with no JavaScript at all;
     - the band keeps its tag, its wave sentence AND the mandatory provenance statement; both text
       runs wrap inside the viewport, so every word and glossary link stays reachable;
     - the wave tag moves from the band into the header, and the band's own copy is hidden, so the
       reader sees exactly one tag; the facet bar's wave segment folds away for the same reason. */
@media (max-width: 430px) {
  .rail {
    position: sticky; top: 0; z-index: 60;
    /* min-height, not height: the header row is 46px, and the rail GROWS when the Board panel opens
       into its second row. A hard height would have clipped the panel instead. */
    height: auto; min-height: 46px; align-self: auto; overflow: visible;
    flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0 8px;
    padding: 0 12px;
    border-right: 0; border-bottom: 1px solid var(--line);
  }
  /* display:contents so the identity block's children ARE the header row. The row WRAPS, so the open
     Board panel can take a full second row instead of covering the page (see .rail-panel below). */
  .rail-top { display: contents; }
  .wordmark { padding: 0; font-size: 11px; letter-spacing: 0.1em; flex: 0 0 auto; }
  /* --ink, not gold. At phone width the band's own tag is hidden and this chip is the ONLY wave
     disclosure on the page; gold on the rail ground measures 3.38:1 in the light theme, which is the
     same unreadable-disclosure defect the band comment records at 3.09:1.
     The border and the disclosure both use neutral ink. */
  .rail-wave {
    display: inline-block; flex: 0 0 auto;
    border: 1px solid var(--ink); color: var(--ink);
    font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; font-weight: 700;
    padding: 1px 5px; white-space: nowrap;
  }
  .rail-search { margin: 0; width: auto; flex: 1 1 auto; min-width: 0; padding: 5px 8px; }
  .rail-search .rs-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .rail-search .rs-kbd { display: none; }
  .railfold { flex: 0 0 auto; display: block; min-height: 0; }
  .rail-more {
    display: inline-flex; align-items: center; gap: 5px; cursor: pointer; list-style: none;
    border: 1px solid var(--line2); border-radius: 6px; padding: 5px 9px;
    color: var(--mut); font-size: 11px; white-space: nowrap;
  }
  .rail-more::-webkit-details-marker { display: none; }
  .rail-more:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
  .railfold[open] > .rail-more { color: var(--ink); background: var(--panel2); border-color: var(--dim); }
  .railfold[open] > .rail-more .rm-caret { transform: rotate(180deg); }
  /* IN FLOW, on its own row, never floating over the page.
     The first version dropped the panel out of flow with position:absolute. That looks tidy with
     JavaScript on and is a LIE with it off: the shell ships the details OPEN precisely so every
     destination survives without scripting, and an open absolute panel then painted an opaque list
     over the honesty band, the facet bar and the H1 of every page. Measured at 390px with scripting
     disabled: the panel covered from y=45 to y=302, and the H1 sits at y=150.
     So the open details takes a full row of the (wrapping) header instead, and the panel pushes the
     page down. With JS the details starts closed, the Board button rides the header row, and the
     chrome budget below is the one the reader actually pays. */
  .railfold[open] { flex: 1 1 100%; }
  .rail-panel {
    position: static; display: block; max-height: 72vh; overflow-y: auto;
    background: var(--railbg); border-top: 1px solid var(--line);
    margin: 0 -12px; padding: 10px 0 12px;
  }
  .rail-nav { margin-top: 0; padding: 0 12px; }
  .rail-foot { margin-top: 10px; }
  /* The band grows with its copy at 390px. The horizontal overflow on this element created the hidden
     1014px row that placed the L3 and L1 glossary links beyond the viewport. */
  .wavebar {
    height: auto; padding: 6px 12px; gap: 4px 10px;
    flex-wrap: wrap; overflow: visible;
    -webkit-mask-image: none; mask-image: none;
  }
  .wavebar .sample-banner { display: none; }
  .wavebar .wb-text, .wavebar .wb-prov { flex: 1 1 100%; min-width: 0; white-space: normal; }
  /* The facet bar keeps the two MENUS (the only controls on it that navigate) and the locale, on one
     line, without pushing the page sideways. The one segment it can shed does go: the wave, which the
     header chip above now carries. The bar gets NO overflow container of its own, because an overflow
     container would clip the dropdown menus, which are the reason the bar exists. */
  .facetbar { height: 32px; padding: 0 12px; flex-wrap: nowrap; }
  .facetbar .fb-wave { display: none; }
  /* The segments are what shrinks when a long category title arrives, ellipsis first, so the bar can
     never widen the page. */
  .fb-drop { min-width: 0; flex: 0 1 auto; }
  .fb-dot, .fb-static { flex: 0 0 auto; }
  .fb-seg { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .page-title { padding-top: 16px; }
  .crumbs { margin-top: 12px; }
}
/* Every interactive element, including theme, lens, form, summary and custom tabindex controls. */
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.pal-input:focus-visible { outline-offset: -2px; }
.rail-nav a:focus-visible { outline-offset: -2px; }
/* Card geometry carries the hit area; its destination label stays underlined in every state, because a
   label sitting beside non-link text may not be told apart by weight alone. It is drawn as a HAIRLINE
   though: a board column where every cell is a destination underlined at full ink reads as a ruled
   ledger, and the rule was louder than the names it sat under. Hover and focus bring it to full ink. */
.ans-idx-q, .fn-q, .door-eng, .fb-menu a, .epick-name, .bx-name, .mk-go, .mx-name a, .bn a {
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: var(--link-line);
}
a:hover :is(.ans-idx-q, .fn-q, .door-eng, .epick-name, .bx-name, .mk-go),
a:focus-visible :is(.ans-idx-q, .fn-q, .door-eng, .epick-name, .bx-name, .mk-go),
.fb-menu a:hover, .fb-menu a:focus-visible,
.mx-name a:hover, .mx-name a:focus-visible, .bn a:hover, .bn a:focus-visible {
  text-decoration-color: currentColor;
}
/* The rail is a list in which EVERY item is a destination, so nothing is being told apart from
   anything: the underline carried no information there and stacked into a wall down the left edge.
   The active item already states itself with a left border, a panel ground and weight. */
.rail-nav a { text-decoration: none; }
.rail-nav a:hover, .rail-nav a:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
/* The recreation retains its own light-theme focus, including inherited link focus. */
.chat { --focus: #0d0d0d; }


/* ---- THE MATRIX: one table, a row per brand, a column per engine ------------------------------- */
.mx { width: 100%; border-collapse: collapse; font-size: 13px; }
.mx-cap {
  caption-side: top; text-align: left; color: var(--mut);
  font-family: var(--sans); font-size: var(--t-body); line-height: 1.6;
  padding-bottom: 14px; max-width: 62ch;
}
.mx thead th {
  text-align: left; padding: 0 14px 10px; border-bottom: 1px solid var(--line2);
  color: var(--ink); font-size: 11px; letter-spacing: 0.06em; font-weight: 700;
  vertical-align: bottom;
}
.mx thead th.mx-b { padding-left: 0; }
/* What the numbers under this column ARE. Said once, here, so every cell can stay two tokens wide. */
.mx thead .mx-h {
  display: block; margin-top: 3px;
  color: var(--dim); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; font-weight: 400;
}
.mx tbody tr { border-bottom: 1px solid var(--line); }
.mx tbody tr:last-child { border-bottom: 0; }
.mx tbody tr:hover { background: var(--panel); }

.mx .mx-b {
  text-align: left; font-weight: 700; letter-spacing: 0.02em; color: var(--ink);
  padding: 14px 14px 14px 0; white-space: nowrap;
}
.mx .mx-b a { color: var(--ink); }
.mx .mx-b a:hover { color: var(--focus); }
/* logo + name, the scannable brand cell. The logo carries the graphical clarity a bare name does not. */
.mx .mx-brand { display: inline-flex; align-items: center; gap: 10px; }
.mx .mx-name { min-width: 0; }

/* Trend column: keyed to the ordering engine, never a cross-engine aggregate. */
.mx thead th.mx-t, .mx td.mx-t { text-align: right; padding-right: 0; }
.mx td.mx-t { vertical-align: middle; }
.mx .mx-tr { font-size: 10.5px; letter-spacing: 0.04em; white-space: nowrap; }
.mx .mx-tr-base { color: var(--dim); text-transform: uppercase; font-size: 9px; letter-spacing: 0.14em; }
/* A real multi-wave series: neutral CI ink; movement direction is carried by its glyph. */
.mx .mx-tr-series { display: inline-flex; align-items: center; color: var(--ci); }
.mx .mx-tr-series svg { display: block; }
.mx .mx-tr.mv-up { color: var(--ci); }
.mx .mx-tr.mv-down { color: var(--ci); }

.mx .mx-c { padding: 12px 14px; vertical-align: middle; min-width: 118px; }
/* The rate leads; its interval sits beside it, always. Tabular figures so the column reads as a column. */
.mx .mx-r { display: flex; align-items: baseline; flex-wrap: wrap; gap: 7px; min-width: 0; font-variant-numeric: tabular-nums; }
/* tabular-nums equalises digit WIDTH, not digit COUNT: "7%" and "80%" are different widths, so the CI
   beside them jittered a character left on every single-digit row. Reserve the widest rate. */
.mx .mx-r b { font-size: 15px; font-weight: 700; color: var(--ink); min-width: 3.2ch; text-align: right; }
.mx .mx-ci { color: var(--dim); font-size: 10.5px; max-width: 18ch; white-space: normal; overflow-wrap: anywhere; }
/* The interval, drawn: a whisker on a zero-to-one track, with the point estimate marked. */
.mx .mx-w { position: relative; display: block; height: 3px; margin-top: 7px; background: var(--line); }
.mx .mx-w i { position: absolute; top: 0; bottom: 0; background: var(--ci); }
.mx .mx-w u { position: absolute; top: -2px; width: 2px; height: 7px; background: var(--ci); margin-left: -1px; }

/* Tied for the top on THIS engine. The only accent in the table. */
.mx .mx-c.lead .mx-r b { color: var(--acc); }
.mx .mx-c.lead .mx-w i { background: var(--acc); }
.mx .mx-c.lead .mx-w u { background: var(--acc); }

/* The number is real; its precision is not. The picture says so. */
.mx .mx-c.lp .mx-r b { color: var(--mut); font-weight: 400; }
.mx .mx-c.lp .mx-w i {
  background: repeating-linear-gradient(-45deg, var(--ci) 0 3px, transparent 3px 6px);
}
.mx .mx-c.lp .mx-w u { background: var(--ci); }
/* Never a zero for something an engine did not publish. */
.mx .mx-c.mx-none span { color: var(--dim); font-size: 11px; }

/* ---- THE LENS (R107): a control attached to the boards it governs ---------------------------- */
/* One control per page, above the first table; on multi-board pages it declares its whole-page
   scope in text. The pills toggle body[data-lens]; every emphasis rule below keys on a class or a
   SEMANTIC data attribute the builder stamped from the data, and no lens rule may name an engine,
   so a rename or a fifth engine changes nothing here. With no JavaScript the SoV default shows,
   its legend line included, and the pills stay inert. */
.mx-lens { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px; margin: 0 0 14px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.mx-lens-pills { display: inline-flex; gap: 3px; flex: 0 0 auto; }
.mx-pill { font-family: inherit; font-size: 11px; color: var(--dim); background: transparent; border: 1px solid var(--line); border-radius: 5px; padding: 2px 8px; cursor: pointer; }
.mx-pill:hover { color: var(--ink); }
.mx-pill[aria-pressed="true"] { color: var(--ink); background: var(--panel2); border-color: var(--line2); }
.mx-lens-scope { color: var(--dim); font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; }
/* The provenance gloss (R28). It does NOT swap with the lens: it qualifies the whole board whichever
   lens is on, so it takes its own full-width row under the legend rather than a fourth .mx-ll slot. */
.mx-lens-gloss { flex: 1 0 100%; color: var(--mut); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; max-width: 68ch; }
/* The legend swaps with the lens, so a screenshot of the control and its table names the active
   lens. Default (no data-lens stamped, or sov): the SoV line. */
.mx-ll { display: none; color: var(--mut); font-family: var(--sans); font-size: var(--t-body); line-height: 1.6; max-width: 68ch; }
body:not([data-lens="gap"]):not([data-lens="precision"]) .mx-ll[data-for="sov"] { display: inline; }
body[data-lens="gap"] .mx-ll[data-for="gap"] { display: inline; }
body[data-lens="precision"] .mx-ll[data-for="precision"] { display: inline; }
/* PRECISION: positive emphasis on the low-precision cells, a dashed border plus the textual tag the
   builder placed IN the cell. Dimming everything else made opacity the only channel (WCAG 1.4.1)
   while the lp cells were already grey; now every other cell keeps its full ink. */
body[data-lens="precision"] .mx-c.lp { outline: 1px dashed var(--dim); outline-offset: -3px; }
body[data-lens="precision"] :is(.member, .standing).lp { outline: 1px dashed var(--dim); outline-offset: -3px; }
/* GAP: the divergence marks. data-gap was computed in the builder from the intervals themselves. */
body[data-lens="gap"] .mx-c[data-gap="1"] { outline: 2px solid var(--ink); outline-offset: -2px; }
body[data-lens="gap"] .standing[data-gap="1"] { outline: 2px solid var(--ink); outline-offset: -2px; }
/* A crop of the table must still explain an empty Gap view. The row exists inside each matrix, stays
   absent from SoV and Precision, and appears only when that matrix has a provider pair but no marks. */
.mx-gap-empty { display: none; }
body[data-lens="gap"] .mx-gap-empty { display: table-row; }
.mx .mx-gap-empty td {
  padding: 12px 10px; color: var(--mut); background: transparent; border: 0; border-left: 2px solid var(--line2);
  font-family: var(--mono); font-size: 11px; line-height: 1.5;
}
/* The in-cell tags: text present in the markup of every marked cell, revealed by its lens. */
.mx-lpt, .mx-gapt { display: none; width: fit-content; font-size: 8.5px; letter-spacing: 0.12em; text-transform: uppercase; border-radius: 3px; padding: 0 5px; margin-top: 6px; }
body[data-lens="precision"] .mx-lpt { display: inline-block; color: var(--dim); border: 1px solid var(--line2); }
body[data-lens="gap"] .mx-gapt { display: inline-block; color: var(--ink); border: 1px solid var(--ink); }

/* THE DOOR (R100): every measured cell is an anchor onto its own evidence. The td's padding moves onto
   the anchor so the whole cell is the target (well past 44x44), the hover draws a contour, and the
   keyboard focus is unmistakable. */
.mx .mx-c.mx-open { padding: 0; }
.mx .mx-door {
  display: block; padding: 12px 14px; min-height: 44px; min-width: 44px; box-sizing: border-box;
  color: inherit; text-decoration: none; cursor: pointer;
}
.mx .mx-door:hover { outline: 1px solid var(--line2); outline-offset: -1px; background: var(--panel2); }
/* Leave the Gap contour visible outside the keyboard ring. */
.mx .mx-door:focus-visible { outline: 2px solid var(--focus); outline-offset: -5px; }

@media (max-width: 760px) {
  /* A 4-column table cannot survive a phone. One card per brand, each engine a labelled row inside it,
     so the rate and its interval keep their pairing. */
  .mx, .mx tbody, .mx tr, .mx td, .mx th { display: block; width: 100%; }
  /* A <caption> inside a table forced to display:block collapses to its longest WORD: the legend
     rendered one word per line down the whole phone. Give it back its width. */
  .mx .mx-cap { display: block; width: 100%; max-width: none; }
  .mx thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .mx tbody tr { border: 1px solid var(--line); margin-bottom: 10px; padding: 4px 0; }
  .mx .mx-b { padding: 10px 14px 6px; border-bottom: 1px solid var(--line); }
  .mx .mx-c { display: flex; align-items: center; gap: 12px; padding: 9px 14px; }
  .mx .mx-c::before {
    content: attr(data-engine); flex: 0 0 84px;
    color: var(--dim); font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase;
  }
  .mx .mx-c .mx-r { flex: 0 0 auto; }
  .mx .mx-c .mx-w { flex: 1; margin-top: 0; }
  /* The engine label stays on the td; the door fills the rest of the row and keeps the whole strip
     tappable at its full 44px height. */
  .mx .mx-c.mx-open { padding: 0 0 0 14px; }
  .mx .mx-door { flex: 1; display: flex; align-items: center; gap: 12px; padding: 9px 14px 9px 0; min-height: 44px; }
  /* A baseline trend cell is dropped on mobile as a second guard. Single-wave matrices suppress the whole
     column, while a real movement chip still shows because that is the one thing worth a row. */
  .mx td.mx-t.mx-t-base { display: none; }
  .mx td.mx-t { display: flex; align-items: center; gap: 12px; padding: 9px 14px; text-align: left; }
  .mx td.mx-t::before {
    content: attr(data-trend-label); flex: 0 0 84px;
    color: var(--dim); font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase;
  }
  body[data-lens="gap"] .mx-gap-empty { display: block; }
  .mx .mx-gap-empty td { display: block; width: auto; margin: 0 10px; }
}

.blogo {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  border-radius: 5px; overflow: hidden; background: #fff; border: 1px solid var(--line2);
  vertical-align: middle; padding: 2px;
}
.blogo img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* The monogram fallback carries its own colour, so it overrides the white chip and stays legible. No
   brand needs it this wave (all 15 have a real mark), but it must stay correct for a future roster. */
.blogo-mono {
  color: #fff; font-weight: 700; letter-spacing: 0; padding: 0;
  font-size: 0.62em; line-height: 1;
}
.blogo-neutral {
  background: #e7e7e8; border-color: #d0d0d4; color: #4b4b52;
}

.wgx{margin-bottom:20px}

/* ONE grid for the captions AND the cells. The left captions used to sit in their own
   grid-template-rows:1fr 1fr, which halves the gutter no matter how tall the two quadrant rows
   actually are. Measured on the live board at 1280px: row 1 was 447px and row 2 was 42px, so the
   caption "absent from the crawl" sat ENTIRELY beside three brands that are in the crawl with
   published ranks. Sharing one grid makes each caption share its own cells' row by construction. */
.wgx-axtop{display:grid;grid-template-columns:22px 1fr 1fr;gap:12px;margin-bottom:8px}
.wgx-main{display:grid;grid-template-columns:22px 1fr 1fr;gap:12px;align-items:stretch}
.wgx-axtop .lab{color:var(--dim);font-size:10px;letter-spacing:.14em;text-transform:uppercase;text-align:center}
.wgx-main>.lab{writing-mode:vertical-rl;transform:rotate(180deg);color:var(--dim);font-size:10px;letter-spacing:.14em;text-transform:uppercase;justify-self:center;align-self:center;text-align:center}

/* The board does not load tools-css.ts. Keep its row and label layout here; ciBand owns the
   interval presentation in the shared stylesheet. */
.wgx-cell{border:1px solid var(--line);background:var(--panel);display:flex;flex-direction:column;min-height:132px}
.wgx-qhead .wgx-count{margin-left:auto}
/* NO ORDINALS. These are <ol class="rows"> for the same document semantics the board's league lists
   use, but a visible "1." beside a brand is a POINT RANK in disguise, and this board publishes rank
   RANGES and leagues, never a position (REVIEW-GUIDE doctrine 2). The marker also rendered outside
   the cell, into the axis gutter, because nothing on this host suppresses it. */
.wgx-cell .rows{list-style:none;margin:0;padding:0}
.wgx-cell .row{display:grid;grid-template-columns:1fr auto;gap:6px 14px;padding:10px 16px;align-items:baseline;border-top:1px solid var(--line)}
.wgx-cell .bn{color:var(--ink);font-size:12.5px;font-weight:700;letter-spacing:.03em}
.wgx-cell .rate{display:flex;align-items:baseline;gap:8px;justify-content:flex-end;color:var(--mut);font-size:11px;text-align:right}
.wgx-cell .rate b{color:var(--ink);font-size:14px}
.wgx-cell .row.lp .bn,.wgx-cell .row.lp .rate b{color:var(--mut)}
.wgx-cell .rr-rate{grid-column:1/-1}
/* The crawl axis is the point of the section, so it is not set in the dimmest ink on the page. */
.wgx-cell .wgx-cc{grid-column:1/-1;color:var(--mut);font-size:11px;letter-spacing:.03em;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.wgx .board-foot{padding:10px 16px;border-top:1px solid var(--line);color:var(--dim);font-size:10.5px}
.wgx-cell>.board-foot{margin-top:auto;margin-bottom:auto;border-top:none;text-align:center}
/* The under-grid honesty footnotes: direct children of .wgx, which is what distinguishes them from
   a not-assessed cell body (a .board-foot INSIDE a .wgx-cell). Each is its own panel on the grid's
   own 12px gutter, because the sentences that say what this section cannot know may not render as
   stray lines dropped under a bordered box. */
.wgx>.board-foot{margin-top:12px;border:1px solid var(--line);background:var(--panel)}
.wgx .empty{border:1px solid var(--line);background:var(--panel);padding:26px}
.wgx .empty .tag{display:inline-block;color:var(--dim);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;border:1px solid var(--line2);padding:2px 8px;margin-bottom:12px}
.wgx .empty h3{font-size:14px;margin-bottom:6px}
.wgx .empty p{color:var(--mut);font-size:11.5px}
@media (max-width:900px){
  .wgx-axtop{display:none}
  .wgx-main{grid-template-columns:1fr}
  .wgx-main>.lab{display:none}
}
