/* 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
   gold is spent in exactly one place: the brand that leads a cell. */
:root {
  --bg: #0a0b0d;
  --bg2: #0e1013;
  --panel: #101317;
  --panel2: #14181d;
  --line: #1d2126;
  --line2: #2b3138;
  --ink: #e7eaed;
  --mut: #9aa3ac;
  --dim: #79838d; /* 4.9:1 on the panel */
  --acc: #ffd23f;
  --acc-dim: #8a7524;
  --cyan: #6fd3f2;
  --up: #59d68c;
  --down: #ff7b6b;
  --watch: #e6b84c;
  --railbg: #0c0e11;
  --headbg: rgba(10, 11, 13, 0.92);
  --bannerbg: #14120c;
  --bannerbd: #3d3417;
  --bannerstripe1: rgba(255, 210, 63, 0.05);
  --bannerstripe2: rgba(255, 210, 63, 0.01);
  --glow1: transparent;
  --glow2: transparent;
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;
  --railw: 232px;
}

/* ---- 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;
  --ink: #1e1c18;
  --mut: #6d675c;
  --dim: #7b7468; /* 4.6:1 */
  --acc: #a8750a;
  --acc-dim: #c19a3a;
  --cyan: #0d7f9c;
  --up: #1f9a55;
  --down: #c34a39;
  --watch: #a97c0a;
  --railbg: #efebe1;
  --headbg: rgba(245, 242, 234, 0.9);
  --bannerbg: #f4eeda;
  --bannerbd: #e0d3ab;
  --bannerstripe1: rgba(168, 117, 10, 0.06);
  --bannerstripe2: rgba(168, 117, 10, 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;
    --ink: #1e1c18;
    --mut: #6d675c;
    --dim: #7b7468;
    --acc: #a8750a;
    --acc-dim: #c19a3a;
    --cyan: #0d7f9c;
    --up: #1f9a55;
    --down: #c34a39;
    --watch: #a97c0a;
    --railbg: #efebe1;
    --headbg: rgba(245, 242, 234, 0.9);
    --bannerbg: #f7f0dd;
    --bannerbd: #e5d8b4;
    --bannerstripe1: rgba(168, 117, 10, 0.06);
    --bannerstripe2: rgba(168, 117, 10, 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(--cyan); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---- 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);
}
.wordmark {
  color: var(--ink); font-size: 14px; font-weight: 800; letter-spacing: 0.16em; white-space: nowrap;
  padding: 0 20px;
}
.wordmark:hover { text-decoration: none; color: var(--acc); }
.wordmark .wm-dot { color: var(--acc); margin: 0 2px; }
.rail-sub {
  padding: 2px 20px 0; color: var(--dim); font-size: 10px; letter-spacing: 0.06em; line-height: 1.5;
}

.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: block; padding: 6px 20px; color: var(--mut); font-size: 12px;
  border-left: 2px solid transparent;
}
.rail-nav a:hover { color: var(--ink); background: var(--panel); text-decoration: none; }
/* The reader always knows which surface they are on. */
.rail-nav a.on { color: var(--ink); background: var(--panel); border-left-color: var(--acc); 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;
}
.themebtn:hover { color: var(--ink); border-color: var(--dim); }

/* ---- 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 gold is spent on the
     LIVE PILOT chip only, which is where the eye should land, and there is no stripe behind a text run. */
  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-size: 11px; line-height: 1.5;
}
.wavebar .sample-banner {
  border: 1px solid var(--acc); color: var(--acc); padding: 1px 8px; font-weight: 700;
  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); }
/* 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; }
.wavebar .wb-wave {
  margin-left: auto; color: var(--mut); white-space: nowrap;
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
}
.wavebar .wb-sep { color: var(--line2); }
.wc-sep { color: var(--line2); }

/* The matrix legend: what the ink means. Stated once per page, above the tables. */
.legend { color: var(--dim); font-size: 11.5px; 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: flex; flex-wrap: wrap;
  border: 1px solid var(--line); background: var(--panel);
  margin: 26px 0 30px;
}
.strip .stat {
  flex: 1 1 116px; min-width: 116px;
  padding: 13px 18px; border-right: 1px solid var(--line);
  display: flex; flex-direction: column; 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: nowrap;
}
.strip .st-val {
  color: var(--ink); font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums;
  line-height: 1.25;
}

/* 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;
}
.standing .st-body.no-trend { grid-template-columns: 150px minmax(160px, 220px) 178px; }
@media (max-width: 900px) {
  .standing.st-hd { display: none; }
}

/* The brand page's takeaway. It was a list with no conclusion. */
.brand-deck {
  margin-top: 12px; color: var(--ink); font-size: 13px; line-height: 1.6;
  border-left: 2px solid var(--acc); padding-left: 12px;
}
.brand-deck .bd-detail { display: block; margin-top: 5px; color: var(--mut); font-size: 11px; }

/* ---- 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 {
  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(--acc); }
.lede {
  margin-top: 14px; max-width: 68ch; color: var(--mut);
  font-size: 14px; line-height: 1.65;
}
.lede b { color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }
.page-title .sub { margin-top: 10px; max-width: 68ch; color: var(--dim); font-size: 12px; }

/* ---- 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-size: 11px; margin-left: auto; text-align: right; }
/* 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-size: 11px; margin: 4px 0 18px;
  border-left: 2px solid var(--line2); padding-left: 10px;
}

/* ---- 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(--acc); text-decoration: none; }
.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; }
/* An unranked row HAS no rank and no position. Reserving both columns for it left eleven blank cells
   under two headers, which reads as a rendering fault rather than as "we will not name a rank here". */
.league.lp .member,
.cell-card.no-trend .league.lp .member { grid-template-columns: 0 1fr 0 178px; }
.league.lp .member .rk, .league.lp .member .rr, .league.lp .member .rr-none { display: none; }
.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-tag {
  color: var(--mut); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  writing-mode: initial; line-height: 1.5;
}
.league-sub { color: var(--dim); font-size: 10px; }
.league.lp .league-tag { color: var(--dim); }
.members { list-style: none; flex: 1; min-width: 0; }
.member {
  display: grid;
  grid-template-columns: 88px minmax(110px, 1fr) 150px minmax(150px, 200px) 178px;
  gap: 14px; align-items: center;
  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; }

/* First wave: no trend column at all (a one-point sparkline is noise), so the row is four columns. */
.cell-card.no-trend .member,
.cell-card.no-trend .member-head { grid-template-columns: 88px minmax(110px, 1fr) 150px minmax(150px, 200px); }

/* 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 {
  display: grid;
  grid-template-columns: 88px minmax(110px, 1fr) 150px minmax(150px, 200px) 178px;
  gap: 14px; 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;
}
.member .rk { color: var(--mut); font-size: 11px; }
.member .bn { font-weight: 700; letter-spacing: 0.04em; overflow: hidden; text-overflow: ellipsis; }
.member .bn a { color: var(--ink); }
.member .bn a:hover { color: var(--acc); }
.member.lp .bn, .member.lp .rk { 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); }
.member.leader .bn { font-weight: 800; }
.member.leader .rr-span { background: rgba(255, 210, 63, 0.26); border-color: rgba(255, 210, 63, 0.62); }
.member.leader .rr-med { background: var(--acc); }

/* THE RANK AXIS. Deliberately NOT the same picture as a rate bar.
   A rate is a magnitude: continuous, drawn from zero, more is more. A rank is a position: discrete,
   counted, and low is good. They used to render as the same bordered track with a filled span, so a
   reader who learned one misread the other. This one is a bracket on a ticked axis: you can count the
   positions, and nothing is filled, because nothing here is a quantity. */
.rr { position: relative; height: 16px; }
/* One tick per position in the field: the axis is countable, so it reads as discrete. */
.rr-ticks {
  position: absolute; inset: 2px 0;
  background-image: repeating-linear-gradient(
    to right, var(--line2) 0 1px, transparent 1px calc(100% / var(--field, 8))
  );
  opacity: 0.5;
}
.rr-track { position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--line2); }
/* The range as an END-CAPPED BRACKET: from its best possible rank to its worst. Not a bar. */
.rr-span {
  position: absolute; top: 3px; bottom: 3px;
  border-left: 2px solid var(--cyan); border-right: 2px solid var(--cyan);
}
.rr-span::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 1px; background: var(--cyan);
}
/* The median position: a diamond, not a bar segment. */
.rr-med {
  position: absolute; top: 50%; width: 5px; height: 5px; margin-left: -2.5px;
  background: var(--cyan); transform: translateY(-50%) rotate(45deg);
}
.member.leader .rr-span { border-color: var(--acc); }
.member.leader .rr-span::after, .member.leader .rr-med { background: var(--acc); }

.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; }
.rate .ci { color: var(--mut); margin-left: 7px; font-size: 11px; }
.member.lp .rate b, .member.lp .rate .ci { color: var(--dim); }

.spark { color: var(--cyan); display: inline-flex; }
.spark svg { display: block; max-width: 100%; }
.member.lp .spark { color: var(--dim); }

.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(--up); border-color: #1f5233; background: rgba(89, 214, 140, 0.08); }
.mv-down { color: var(--down); border-color: #5c2e28; background: rgba(255, 123, 107, 0.08); }
.mv-stable { color: var(--mut); border-color: var(--line2); }
.mv-watch { color: var(--watch); border-color: #5a4a16; background: rgba(230, 184, 76, 0.07); }
.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(--watch); background: rgba(230, 184, 76, 0.08);
  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); opacity: 0.85; }
.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-size: 10.5px; line-height: 1.5; }
.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: rgba(111, 211, 242, 0.45); }
.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-bar { position: relative; height: 12px; background: var(--bg2); border: 1px solid var(--line); }
.div-fill { position: absolute; inset: 2px auto 2px 2px; background: rgba(255, 210, 63, 0.4); }
.div-ci { position: absolute; top: 50%; height: 1px; background: var(--acc); }
.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-size: 11px; margin-top: 6px; }
.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; }

/* ---- method cards / prose -------------------------------------------------------------------- */
.method-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 14px; }
.method-card { border: 1px solid var(--line); background: var(--panel); padding: 16px; }
.method-card .mc-no { color: var(--acc); font-size: 11px; letter-spacing: 0.2em; }
.method-card h3 { font-size: 13px; margin: 8px 0 8px; letter-spacing: 0.04em; }
.method-card p { color: var(--mut); font-size: 12px; }

.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-size: 12.5px; }
.prose strong { color: var(--ink); }
.prose ul { margin: 0 0 12px 18px; color: var(--mut); font-size: 12.5px; }
.prose li { margin-bottom: 5px; }

/* 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(--ink); text-decoration: none; }
.method-toc .mt-n { color: var(--acc); 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 {
  display: grid; grid-template-columns: 150px minmax(160px, 220px) 178px 1fr; gap: 16px;
  align-items: center; padding: 12px 16px;
}
.standing .st-league { color: var(--ink); font-size: 12px; font-weight: 700; letter-spacing: 0.04em; }
.standing .st-note { color: var(--dim); font-size: 11px; }

.brand-links { color: var(--dim); font-size: 11.5px; margin: 10px 0 4px; }

/* ---- footer ---------------------------------------------------------------------------------- */
.site-foot { border-top: 1px solid var(--line); padding: 22px 0 34px; background: var(--railbg); }
.disclosure { color: var(--mut); font-size: 11.5px; margin-bottom: 6px; }
.foot-line { color: var(--dim); font-size: 11px; }
.foot-nav { margin-top: 10px; font-size: 11px; }

/* ---- 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); }
  .rail {
    position: static; height: auto; width: 100%;
    border-right: 0; border-bottom: 1px solid var(--line);
    padding: 16px 0 0;
  }
  .rail-sub { display: none; }
  .rail-nav {
    margin-top: 12px; flex-direction: row; gap: 0; align-items: center;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    /* The strip scrolls, and it must LOOK like it scrolls: without the fade, four of eight destinations
       sat off the right edge of a 390px phone with nothing to say they existed. */
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent 100%);
  }
  .rail-grp { flex-direction: row; align-items: center; flex: 0 0 auto; }
  /* The group labels cost ~270px of a row that is already too long, and a single row of links does not
     need them. */
  .rail-lab { display: none; }
  .rail-grp + .rail-grp { border-left: 1px solid var(--line); margin-left: 8px; padding-left: 8px; }
  .rail-grp:first-child { padding-left: 12px; }
  .rail-nav a:last-child { margin-right: 28px; }
  .rail-nav a {
    padding: 8px 10px; border-left: 0; border-bottom: 2px solid transparent; white-space: nowrap;
  }
  .rail-nav a.on { border-left: 0; border-bottom-color: var(--acc); background: transparent; }
  .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) {
  /* 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 { grid-template-columns: 74px 1fr 120px; grid-auto-rows: auto; row-gap: 4px; }
  .member .rate { grid-column: 1 / 3; }
  .member .spark { grid-column: 3 / 4; grid-row: 2; justify-self: end; }
  .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 { grid-template-columns: 1fr 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 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 { grid-template-columns: 1fr; }
  .member .rate { grid-column: auto; }
  .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: 78px; }
  .league-tag { letter-spacing: 0.08em; }
  .bn, .st-head { overflow-wrap: anywhere; }
  /* Two-up rather than five cells on a 360px row. Every strip is now 3 or 4 tiles, so the last row is
     never a lone tile with an empty quadrant beside it and a divider pointing at nothing. */
  .strip .stat { flex: 1 1 50%; min-width: 0; border-bottom: 1px solid var(--line); }
  .strip .stat:nth-child(2n) { border-right: 0; }
  .strip .stat:nth-last-child(-n+2) { border-bottom: 0; }
  .strip .st-lab { white-space: normal; }
  /* The wave id + tier chip line is the one thing in the band that can push past a 360px viewport. */
  .wavebar .wb-wave { margin-left: 0; }
}

/* ---- 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-size: 11px; 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(--acc); }

.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; gap: 7px; 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; }
/* 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(--cyan); opacity: 0.55; }
.mx .mx-w u { position: absolute; top: -2px; width: 2px; height: 7px; background: var(--cyan); 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(--dim) 0 3px, transparent 3px 6px); opacity: 0.7;
}
.mx .mx-c.lp .mx-w u { background: var(--dim); }
/* Never a zero for something an engine did not publish. */
.mx .mx-c.mx-none span { color: var(--dim); font-size: 11px; }

@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; }
}

.wgx{margin-bottom:20px}
.wgx-axtop{display:grid;grid-template-columns:22px 1fr 1fr;gap:12px;margin-bottom:8px}
.wgx-axtop .lab{color:var(--dim);font-size:10px;letter-spacing:.14em;text-transform:uppercase;text-align:center}
.wgx-main{display:grid;grid-template-columns:22px 1fr;gap:12px;align-items:stretch}
.wgx-axleft{display:grid;grid-template-rows:1fr 1fr;gap:12px}
.wgx-axleft .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}
.wgx-quad{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.wgx-cell{border:1px solid var(--line);background:var(--panel);display:flex;flex-direction:column}
.wgx-qhead .wgx-count{margin-left:auto}
.wgx-cell .row{grid-template-columns:1fr auto;gap:8px 14px;padding:10px 16px;align-items:baseline}
.wgx-cell .row .cibar{grid-column:1/-1}
.wgx-cell .wgx-cc{grid-column:1/-1;color:var(--dim);font-size:10.5px;letter-spacing:.03em;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
@media (max-width:900px){
  .wgx-axtop{display:none}
  .wgx-main{grid-template-columns:1fr}
  .wgx-axleft{display:none}
  .wgx-quad{grid-template-columns:1fr}
}
