
:root { color-scheme: light dark;
  --ground:#f2f3f5; --bg:#ffffff; --ink:#191b1f; --ink-2:#5d636c; --ink-3:#676e78; --line:#e4e6ea; --line-2:#f0f1f3; --tint:#f6f7f8; --edge:#c6cbd2; --accent:#4f46e5; --stage-2:#17191c;
  --low:#6f8194; --low-ink:#556879; --moderate:#c07c00; --moderate-ink:#8a5a00;
  --high:#e04a1c; --high-ink:#b23a12; --extreme:#c8102e; --extreme-ink:#a10c25;
  --unscored:#b8bdc4; --unscored-ink:#676e78; --up:#1f7a3f; --down:#c1121f; --focus:#2563eb;
  --font:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans", "Helvetica Neue", Arial, sans-serif; --radius-pill:999px;
  --fs-12:12px; --fs-13:13px; --fs-14:14px; --fs-15:15px; --fs-16:16px; --fs-18:18px; --fs-20:20px; --fs-24:24px; --fs-28:28px; --fs-32:32px; --fs-36:36px; --fs-44:44px; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {
  --ground:#0a0b0d; --bg:#141719; --ink:#eceef0; --ink-2:#a3a9b2; --ink-3:#7f8791; --line:#282c32; --line-2:#1f2327; --tint:#1a1e22; --edge:#3d434b; --accent:#a5a0ff; --stage-2:#17191c;
  --low:#8fa3b8; --low-ink:#a9bccf; --moderate:#f0a92e; --moderate-ink:#f5bd57;
  --high:#ff7a45; --high-ink:#ff9a6e; --extreme:#ff5470; --extreme-ink:#ff7f95;
  --unscored:#5c636c; --unscored-ink:#8a919a; --up:#5fcf86; --down:#ff6b6b; --focus:#7aa2ff; } }
:root[data-theme="dark"] {
  --ground:#0a0b0d; --bg:#141719; --ink:#eceef0; --ink-2:#a3a9b2; --ink-3:#7f8791; --line:#282c32; --line-2:#1f2327; --tint:#1a1e22; --edge:#3d434b; --accent:#a5a0ff; --stage-2:#17191c;
  --low:#8fa3b8; --low-ink:#a9bccf; --moderate:#f0a92e; --moderate-ink:#f5bd57;
  --high:#ff7a45; --high-ink:#ff9a6e; --extreme:#ff5470; --extreme-ink:#ff7f95;
  --unscored:#5c636c; --unscored-ink:#8a919a; --up:#5fcf86; --down:#ff6b6b; --focus:#7aa2ff; }

* { box-sizing: border-box; }
html { font-family: var(--font); font-size: 16px; line-height: 1.5; -webkit-font-smoothing: antialiased; }
body { margin: 0; background: var(--ground); color: var(--ink); }
a { color: inherit; text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 2px; }
h1, h2, h3, p, ol, ul, figure { margin: 0; }
ol, ul { padding: 0; list-style: none; }
img { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; }
small { font-size: var(--fs-13); }

/* chrome */
.site { display: flex; align-items: center; gap: 28px; height: 60px; padding: 0 32px; background: var(--bg); border-bottom: 1px solid var(--line); }
.brand { font-weight: 650; letter-spacing: -0.01em; font-size: var(--fs-16); display: flex; align-items: center; gap: 8px; }
.brand:hover { text-decoration: none; }
/* A49.2: the Trace mark -- the line takes the brand's own ink, the dot the accent, so both themes follow the tokens */
.brand-mark { width: 22px; height: 22px; flex: none; display: block; }
.brand-mark path { fill: none; stroke: currentColor; stroke-width: 3.25; stroke-linecap: round; stroke-linejoin: round; }
.brand-mark circle { fill: var(--accent); }
.site nav > div { display: flex; gap: 22px; }
.edge-guard { display: none; }
@media (display-mode: standalone) {
  .edge-guard { display: block; position: fixed; top: 0; left: 0; right: 0; height: 12px; background: var(--bg); z-index: 25; }
}
.site nav a { color: var(--ink-2); padding: 20px 0 18px; border-bottom: 2px solid transparent; }
.site nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }
.site nav a:hover { text-decoration: none; color: var(--ink); }
.tools { margin-left: auto; display: flex; gap: 18px; color: var(--ink-2); }
.tools svg { width: 20px; height: 20px; display: block; }
.page { max-width: 1440px; margin: 0 auto; padding: 32px 32px 64px; }
.site-foot { border-top: 1px solid var(--line); padding: 24px 32px; color: var(--ink-3); font-size: var(--fs-13); display: flex; gap: 20px; flex-wrap: wrap; }

/* settings menu (a <details> the dropdown controller closes on outside click / Escape) */
.settings { position: relative; }
.settings > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 4px; color: var(--ink-2); }
.settings > summary::-webkit-details-marker { display: none; }
.settings > summary svg { width: 20px; height: 20px; display: block; }
.settings-panel { position: absolute; right: 0; top: calc(100% + 10px); min-width: 220px; background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 6px; z-index: 10; box-shadow: 0 8px 24px rgba(0,0,0,.08); }
.settings-group { padding: 6px 8px; }
.settings-group + .settings-group { border-top: 1px solid var(--line); }
.settings-label { font-size: var(--fs-12); color: var(--ink-3); margin-bottom: 4px; }
.settings-choice { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; font: inherit; background: none; border: 0; padding: 6px 8px; border-radius: 6px; color: var(--ink-2); cursor: pointer; }
.settings-choice[aria-current] { color: var(--ink); background: var(--tint); font-weight: 550; }
.settings-choice:hover { color: var(--ink); text-decoration: none; }
/* the panel sits inside .tools, whose 20px block svg rule would otherwise stack each glyph above its label */
.settings-choice svg { width: 16px; height: 16px; flex: none; }
/* A67.1: the phone nav menu; hidden here, shown by the phone block. A67.2: .tab-menu is the chart kinds' and the calendar views' disclosure and shares these rules */
.nav-menu, .tab-menu { display: none; }
.nav-menu > summary, .tab-menu > summary { list-style: none; cursor: pointer; display: flex; align-items: center; color: var(--ink-2); }
.nav-menu > summary::-webkit-details-marker, .tab-menu > summary::-webkit-details-marker { display: none; }
.nav-menu[open] > summary, .tab-menu[open] > summary { color: var(--ink); }
.live { display: inline-flex; align-items: center; gap: 6px; }
.live::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--down); }
.skip, .offscreen { position: absolute; left: -9999px; }
.skip:focus { left: 16px; top: 8px; background: var(--bg); padding: 8px 12px; z-index: 20; }
.flash { margin: 0 0 24px; padding: 10px 14px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink-2); }
.flash--warn { border-color: var(--down); color: var(--ink); }

/* type */
.lead { font-size: var(--fs-32); font-weight: 600; letter-spacing: -0.02em; line-height: 1.15; max-width: 40ch; text-wrap: balance; }
.lead-note { color: var(--ink-2); margin-top: 10px; max-width: 72ch; }
h2 { font-size: var(--fs-18); font-weight: 600; letter-spacing: -0.01em; }
/* panels (A15): the page ground is grey and every list, trace, grid and section sits on a white panel; the lead, tabs and controls stay on the ground */
.panel, .section, .verdict-strip, .cal, .lists > *, .article { background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 20px 24px; box-shadow: 0 1px 2px rgba(0,0,0,.03); }
.section { margin-top: 24px; }
.lead-note + .section { margin-top: 32px; }
.tabs + .panel, .tab-menu + .panel, .tabs + .cal, .tab-menu + .cal, .muted + .panel, .verdict-strip + .panel, .lead-note + .panel, .lead-note + .article { margin-top: 24px; }
.muted + .lists { margin-top: 12px; }
.panel > .remaining { padding-bottom: 0; }
.section-head { display: flex; align-items: baseline; gap: 16px; margin-bottom: 12px; }
.section-head a { color: var(--ink-2); font-size: var(--fs-14); margin-left: auto; }
.muted { color: var(--ink-2); }

/* hype colour semantics: text wears -ink, marks wear the fill */
.hype { font-variant-numeric: tabular-nums; font-weight: 600; }
.hype--low { color: var(--low-ink); } .hype--moderate { color: var(--moderate-ink); }
.hype--high { color: var(--high-ink); } .hype--extreme { color: var(--extreme-ink); } .hype--unscored { color: var(--unscored-ink); font-weight: 400; }
/* A21.1: the chip lives inside one .row-standing cell -- rank and movement are one fact, and an empty column of its own explained nothing */
/* A40/A41: fixed slots, ledger-style -- the rank right-aligned in 26px, then a 64px Move slot 14px away, which is itself two columns: the figure right-aligned in 44px, then an unheaded 14px arrow column after it */
.row-standing { display: grid; grid-template-columns: 26px; column-gap: 14px; align-items: center; justify-content: start; min-width: 0; }
/* A43: the Move slot exists only where a figure fills it -- a chart that reports no movement (reviewed, awaited, a page with no baseline) keeps the rank alone */
.row-standing:has(> .move) { grid-template-columns: 26px 64px; }
.row-standing .row-rank { color: var(--ink); font-size: var(--fs-18); font-weight: 600; text-align: right; }
.move { font-variant-numeric: tabular-nums; font-size: var(--fs-13); line-height: 1.1; }
.move--up { color: var(--up); } .move--down { color: var(--down); } .move--flat, .move--new { color: var(--ink-3); }
.row-standing .move { display: grid; grid-template-columns: 44px 14px; column-gap: 6px; align-items: center; font-size: var(--fs-14); font-weight: 500; line-height: 1; }
.row-standing .move > span { grid-column: 1; justify-self: end; }
.row-standing .move > .icon { grid-column: 2; width: 13px; height: 13px; }
/* A40: a debut is a small tag, not a number -- NEW has no distance to report */
.row-standing .move--new > span { font-size: var(--fs-12); font-weight: 600; text-transform: uppercase; color: var(--ink-2); border: 1px solid var(--edge); border-radius: 3px; padding: 0 4px; line-height: 16px; }
/* A76.4: the dated lead (Releasing soon) -- the date over its countdown in the 116px lead, start-aligned. It follows the `.row-standing` grid above at equal specificity and so wins its `display`; tabular figures (T2), the date 14px 550, its `small` a block of --ink-3 at 12px, both nowrap at every width. The phone block restates what a media query would otherwise lose (A43.3). */
.row-standing--date { display: block; font-variant-numeric: tabular-nums; font-size: var(--fs-14); font-weight: 550; line-height: 1.2; text-align: start; white-space: nowrap; }
.row-standing--date small { display: block; color: var(--ink-3); font-weight: 400; font-size: var(--fs-12); white-space: nowrap; }
/* A76.4: a window lead (TBA, month, quarter, year) sets its date line at 12px 550 at every width -- es "septiembre 2027" measured 115.2px at 14px against the 116px track */
.row-standing--window { font-size: var(--fs-12); }
/* A76.6: a month-precision lead carries its full month (desktop) and the locale's abbreviated one (phones, where the 84px track cannot hold "September 2027"); the phone block swaps them */
.date-short { display: none; }

/* ranked rows: 56px, the trace is the row */
.rows { border-top: 1px solid var(--line); }
.row { display: grid; grid-template-columns: 48px 42px minmax(0,1fr) 240px 64px; align-items: center; height: 64px; border-bottom: 1px solid var(--line); gap: 12px; }
.row-rank { font-variant-numeric: tabular-nums; color: var(--ink-3); font-size: var(--fs-15); }
/* cover art (A6): a 3:4 thumbnail in every game list; the placeholder keeps the cell when a game has none */
.cover { display: block; width: 36px; height: 48px; object-fit: cover; border-radius: 3px; background: var(--tint); }
.cover--none { background: var(--line-2); }
.row .cover { width: 42px; height: 56px; }
.row-name { min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.row-name a { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row-name small { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row .mini { width: 235px; height: 30px; margin: 5px 5px 5px 0; display: block; }
.mini--empty { visibility: hidden; }
/* A60.3: the quiet list-row trace. The drawn box sits 5px inside its 240x40 cell on the top, right and bottom, so the tip on its right edge paints into the margin, hence overflow visible. */
.mini--quiet { overflow: visible; }
.mini-line { fill: none; stroke: var(--ink-3); stroke-width: 1.5px; stroke-linejoin: miter; stroke-linecap: round; }
/* A73.9: the tread across a night with no reading, dashed; it keeps the run's stroke. A butt cap: a round one on the 1.5px stroke would turn 1.5 2.5 into 3 on, 1 off. */
.mini-hole { stroke-dasharray: 1.5 2.5; stroke-linecap: butt; }
.mini-ref { fill: none; stroke: var(--ink-3); stroke-width: 1px; stroke-dasharray: 1 3; opacity: .8; }
.mini-ring { fill: none; stroke: var(--bg); stroke-width: 9px; }
.mini-tip { fill: none; stroke-width: 6px; }
/* era-seams ES8: a moving formula change, a dashed hairline the full height of the box. */
.mini-seam { fill: none; stroke: var(--ink-3); stroke-width: 1px; stroke-dasharray: 2 2; opacity: .6; }
/* A74.3: the A65 hover layer is retired -- the quiet trace's high and low are the package below, always on screen, not a hover. */
/* A74.8: a list and its head are one inline-size container, so the package's columns follow the LIST's width (980px, below) and not the viewport's. Outside the query the two cells and two head spans (A75.2) are display: none and take no grid slot; the compact `.trace-range` under the trace shows instead. */
.rowset { container-type: inline-size; container-name: rowset; }
.row-trend, .row-range, .rows-head-trend, .rows-head-range { display: none; }
.trace-range { display: flex; align-items: center; gap: 3px; font-size: var(--fs-12); line-height: 14px; color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.trace-range .icon { width: 11px; height: 11px; flex: none; }
/* A74.4: a run too short to call prints its dash in the glyph's own 14px box, so the dash lines up with the glyphs above and below it. */
.trend-dash { width: 14px; flex: none; text-align: center; }
/* A74.8: in the compact range only the glyph takes the trend colour; the digits stay --ink-2 */
.trace-range.trend--rising .icon { color: var(--up); }
.trace-range.trend--falling .icon { color: var(--down); }
.trace-range.trend--steady .icon { color: var(--ink-2); }
/* The reviewed kind's trace cell: the launch phase's frozen hype -- its last 45 days up to the lock, then the figure it froze at. The 188px mini leaves the 240px cell room for the gap and a two-digit figure. */
.launch-hype { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.launch-hype .mini { width: 188px; }
.launch-hype .hype { font-size: var(--fs-16); min-width: 28px; text-align: right; font-variant-numeric: tabular-nums; }
.launch-hype-word { display: none; }
/* A76.7: the awaited row's "Hype N" aside is a phone-only stand-in for the trace; the phone block shows it */
.row-aside-hype { display: none; }
.launch-hype--none { color: var(--ink-3); }
.row-hype { text-align: right; font-size: var(--fs-20); }
.rows > .row:last-child { border-bottom: 0; }
/* A67.5/A67.10: the search results' rows are 64px at every width -- the same height the .row above gives them; the class exists so the phone block can name them */
.rows--search > .row { height: 64px; }
.rows-head { display: grid; grid-template-columns: 38px 42px minmax(0,1fr) 240px 64px; gap: 12px; font-size: var(--fs-12); color: var(--ink-3); padding: 0 0 6px; }
.rows-head span:last-child { text-align: right; }
/* A40: the head's first cell carries the same two slots as the standing cell below it, and the Game label spans the cover and the name, which are one column */
.rows-head-standing { display: grid; grid-template-columns: 26px; column-gap: 14px; justify-content: start; }
.rows-head-standing:has(> span + span) { grid-template-columns: 26px 64px; }
.rows-head-standing span { text-align: right; }
/* A42: Move heads the figures, not the unheaded arrow column after them */
.rows-head-standing span + span { padding-right: 20px; }
.rows-head-game { grid-column: span 2; }
/* A39/A40: a row that carries a movement figure (and the head over it) widens its first track to hold both slots plus 12px of air, so the cover groups with the name rather than the figure; rows whose rank cell is empty (search, the showcase line-up) keep 48px */
/* A43: a ranked row with NO figure -- a chart that reports no movement -- drops the Move slot's spacer: the rank's 26px plus the same 12px of air */
/* A76.4: every `charts/_entry` row -- one selector, one 64px height, 12px gap, for every list (the dated variant below takes the dated lead) */
.rows > .row:has(> .row-standing) { grid-template-columns: 38px 42px minmax(0,1fr) 240px 64px; gap: 12px; height: 64px; }
.rows > .row:has(> .row-standing > .move), .rows-head:has(> .rows-head-standing > span + span) { grid-template-columns: 116px 42px minmax(0,1fr) 240px 64px; }
/* A76.4: the dated lead is 116px too, so on a day that reports movement Releasing soon shares Most anticipated's left edge; its head cell reads "Date", start-aligned */
.rows > .row:has(> .row-standing--date), .rows-head:has(> .rows-head-standing--date) { grid-template-columns: 116px 42px minmax(0,1fr) 240px 64px; }
.rows-head-standing--date { display: block; text-align: start; }
/* A30 (owner, 2026-09-20): the column labels sit CENTRED in the gap between
   the band's border and the list's first rule. That gap is 42px and was paid
   18 / 18 / 6 -- the band's own stacking margin, the head's line box, the
   head's padding -- so the words sat 6px low (measured off the render, not
   the cascade: band border y=326, list rule y=369, cap top y=349 at 1295px).
   The head owns the whole gap instead: the band's margin is cancelled where a
   head follows it, and the head pays it back as EQUAL padding above and
   below its line box. The two numbers are one number -- move `.band`'s
   margin and this must move with it, which `rows_head_centred_test` is. */
.band + .rows-head { margin-top: -18px; padding-top: 12px; padding-bottom: 12px; }
/* A28 (2026-09-20): a divider inside a panel reaches the panel's edge.
   `.band` already bleeds through the panel's own 20px/24px padding, so a row
   divider stopping 24px short of the border drew a second box inside the
   first -- the owner's word for it. The LIST bleeds and each row pays the
   padding back, so only the rules move; every cell stays on the band's own
   left edge. The bleed must equal `.panel`'s horizontal padding, which the
   phone block restates at 16px (H). */
.panel .rows, .panel .rows-head { margin-left: -24px; margin-right: -24px; }
.panel .row, .panel .rows-head { padding-left: 24px; padding-right: 24px; }
/* A28: `.rows`' own top rule is a head rule -- it separates the list from
   whatever heads it. Bled to the panel's edge it would double the panel's
   own top border when the list heads the panel itself (search results), so
   there it is dropped rather than drawn 20px below an identical line. */
.panel > .rows:first-child { border-top: 0; }
.remaining { padding: 14px 0; color: var(--ink-2); font-size: var(--fs-14); }
.no-rows { padding: 40px 0; color: var(--ink-2); max-width: 60ch; }

/* tabs and controls */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 20px; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.lead-note + .tabs { margin-top: 24px; }
/* A67.9: a long intro folds on a phone only. Desktop shows .lead-full alone; .lead-more sits between the note and the tabs in the DOM, so it carries the gap `.lead-note + .tabs` used to. */
.lead-first, .lead-more { display: none; }
.lead-more + .tabs { margin-top: 24px; }
/* A44: the charts heading and blurb hold one height across kinds -- every kind's pair shares one grid cell and all but the current one are invisible sizers, so the tabs and the list never move when the copy is longer */
.intro-stack { display: grid; }
.intro-stack > * { grid-area: 1 / 1; }
.intro-stack > [aria-hidden] { visibility: hidden; }
.intro-stack + .tabs { margin-top: 24px; }
.tabs a { padding: 10px 12px; color: var(--ink-2); border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap; }
.tabs a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); font-weight: 550; }
.tabs a:hover { text-decoration: none; color: var(--ink); }
/* best-new-releases B16: the front-page period tabs sit inside a section, so they take a tighter margin than the page-level .tabs (after .tabs, equal specificity, source order wins); the note is one quiet line above the rows */
.best-tabs { margin: 4px 0 12px; }
.best-note { margin: 0 0 10px; color: var(--ink-2); font-size: var(--fs-13); }
/* the period walker (A25): text, not pills -- the cut being viewed is the anchor, in weight, and each neighbour is a link that names where it leads; a bound simply has no link on that side */
.walk { display: inline-flex; gap: 16px; align-items: baseline; padding: 7px 0; white-space: nowrap; }
.walk a { color: var(--ink-2); }
.walk a:hover { color: var(--ink); }
.walk a[aria-current="page"] { color: var(--ink); font-weight: 600; }
/* A45.5 retired `.select`/`.select-panel`/`.select-option`/bare `.control`
   from the sheet along with /games's own sort disclosure, their last public
   emitter -- the sort menu is a `.fmenu` now (public_class_census_test.rb's
   orphan check is what catches a rule nothing renders any more). A45.1
   retired `.control-label` and `.facet .ic`/`.rail .ic`/`.filters-btn .ic`
   the same way: /calendar was their last emitter, and the bar's own
   `.fmenu .k`/`.opt .ic` (below) replace them. */

/* the filter bar (A45, 2026-09-28): replaces the rail on /charts, /games
   and /calendar -- one details.fmenu per axis, the applied fill read off
   aria-current alone (A45.3), never a state class. Transcribed from
   docs/design/rebuild-8/mockups/filter-bar.html with the contract's own
   names (.fline -> .fbar, .chip -> .fmenu, .menu -> .fmenu-panel,
   .chip-t -> .ftoggle). The bar is the list's own head band's second line
   (flex-basis: 100%, A45.1). */
.fbar { flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.band.stampband .fbar { margin-top: 2px; }
/* A45.9 "tap targets": WCAG 2.5.8 -- a text link with no border box of its
   own needs vertical padding to clear the 24px minimum. */
.fclear { font-size: var(--fs-13); color: var(--ink-2); text-decoration: underline; text-underline-offset: 2px; margin-left: 4px; padding: 4px 0; }
/* A45.4: the calendar's own tail link(s) -- "TBA games ->" on month/quarter/
   year, "<- Back to <month>" in its place on the day page -- pinned to the
   bar's right end, ahead of everything that follows it in source. */
.fside { margin-left: auto; font-size: var(--fs-14); color: var(--ink-2); padding: 4px 0; }
.fside:hover { color: var(--ink); }
.fmenu { position: relative; }
.fmenu > summary, .ftoggle, .fopen { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 10px 0 12px; border: 1px solid var(--edge); border-radius: 6px; background: var(--bg); color: var(--ink); font-size: var(--fs-14); white-space: nowrap; user-select: none; }
.fmenu > summary::-webkit-details-marker { display: none; }
.fmenu > summary:hover, .ftoggle:hover, .fopen:hover { border-color: var(--ink-2); text-decoration: none; }
/* A67.3: the phone bar's one Filters button (styled as a menu button, the
   native <button> only needing its font inherited) and one .ftag token per
   applied cut. Neither displays outside a ready phone bar; the phone block
   below turns them on. */
.fopen { font-family: inherit; display: none; }
.ftag { display: none; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 10px; max-width: 100%; border: 1px solid var(--edge); border-radius: 6px; background: var(--bg); color: var(--ink); font-size: var(--fs-13); white-space: nowrap; }
.ftag > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ftag:hover { border-color: var(--ink-2); text-decoration: none; }
.ftag [aria-hidden="true"] { color: var(--ink-2); flex: none; }
.fmenu .k { color: var(--ink-3); }
.fmenu .v { font-weight: 550; }
.fmenu .chev, .ftoggle .chev { width: 12px; height: 12px; flex: none; color: var(--ink-2); }
.fmenu[open] > summary { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink) inset; }
/* A45.3: filled iff the axis has an all-option AND the current option is not
   it -- a menu with no all-option (View, Sort) can never fill. */
.fmenu:has(.opt--all):has(.opt[aria-current]:not(.opt--all)) > summary { background: var(--accent); border-color: var(--accent); color: var(--bg); }
.fmenu:has(.opt--all):has(.opt[aria-current]:not(.opt--all)) > summary .k,
.fmenu:has(.opt--all):has(.opt[aria-current]:not(.opt--all)) > summary .chev { color: color-mix(in srgb, var(--bg) 84%, var(--accent)); }
.ftoggle { padding: 0 12px 0 10px; gap: 8px; }
.ftoggle .c { color: var(--ink-3); font-variant-numeric: tabular-nums; font-size: var(--fs-13); }
.ftoggle[aria-current="true"] { background: var(--accent); border-color: var(--accent); color: var(--bg); }
/* the count keeps the label's register on the fill: --ink-3 on --accent reads ~1.4:1. */
.ftoggle[aria-current="true"] .c { color: color-mix(in srgb, var(--bg) 84%, var(--accent)); }
.sw { position: relative; width: 26px; height: 16px; border-radius: var(--radius-pill); background: var(--line); border: 1px solid var(--edge); flex: none; }
.sw::after { content: ""; position: absolute; top: 1px; left: 1px; width: 12px; height: 12px; border-radius: 50%; background: var(--bg); box-shadow: 0 1px 2px rgba(0,0,0,.25); }
.ftoggle[aria-current="true"] .sw { background: var(--bg); border-color: var(--bg); }
.ftoggle[aria-current="true"] .sw::after { left: 11px; background: var(--accent); }
.fmenu-panel { position: absolute; top: calc(100% + 6px); left: 0; min-width: 240px; max-height: 372px; overflow-y: auto; background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 4px; z-index: 30; box-shadow: 0 10px 28px rgba(0,0,0,.12); font-size: var(--fs-14); font-weight: 400; text-align: left; line-height: 1.5; }
/* a menu whose rows carry a platform glyph (Platform, and any future icon
   axis) is wider, so the name column has room -- keyed on :has(.ic) rather
   than a second class (A45's mapping note), matching mock.css's .menu--wide. */
.fmenu-panel:has(.ic) { min-width: 300px; }
/* A45.5: Sort opens right-aligned -- it stands at the band's far end, and a
   left-aligned panel there would run off the page. */
.fsort .fmenu-panel { left: auto; right: 0; }
.opt { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; color: var(--ink-2); white-space: nowrap; }
.opt:hover { background: var(--tint); color: var(--ink); text-decoration: none; }
.opt[aria-current] { color: var(--ink); font-weight: 600; }
.opt[aria-current]::after { content: "✓"; margin-left: 4px; }
.opt[aria-disabled] { color: var(--ink-3); opacity: .7; }
/* A45.9 "tap targets"/A27.2 mirror: a pruned Availability toggle (nothing to
   show, not already applied) looks exactly as inert as a pruned `.opt` row --
   .ftoggle's base rule above still sets `cursor: pointer`, so without this it
   would look clickable while going nowhere new. */
.ftoggle[aria-disabled] { cursor: default; color: var(--ink-3); }
.ftoggle[aria-disabled]:hover { border-color: var(--edge); }
.opt .fn { overflow: hidden; text-overflow: ellipsis; }
.opt .c { margin-left: auto; color: var(--ink-3); font-variant-numeric: tabular-nums; font-size: var(--fs-13); font-weight: 400; }
.opt .ic { width: 16px; height: 16px; flex: none; }
/* the mockup drew a `.sep` divider after the first row (A45's mapping note);
   here it is a border on the all-option itself, no separator element --
   below the all-row everywhere except Period, whose all-option (All
   upcoming) is the LAST row, where the border moves above it instead. */
.opt--all { border-bottom: 1px solid var(--line); margin-bottom: 4px; padding-bottom: 10px; }
.opt--all:last-child { border-bottom: 0; border-top: 1px solid var(--line); margin-bottom: 0; margin-top: 4px; padding-bottom: 6px; padding-top: 10px; }

/* A45.6: the phone batch sheet -- shared/_filter_sheet.html.erb, one per
   bar page, rendered as .fbar's own last child. `dialog` is closed (no
   `open` attribute, so no native `display: none` override is ever needed)
   until filter_sheet_controller.js calls showModal() below 640px; at
   desktop width, or with JS disabled, it is simply never opened, so no
   media query gates any of this. Transcribed from mock.css's `.sheet`
   family with the contract's own names (`.sheet` -> `dialog.fsheet`, the
   rail's `.grp`/`.gl` -> `.fgroup`/`.gl`), and radios rather than the
   mockup's fake `.radio` glyph -- a real `<input type="radio">` with
   `accent-color` needs no glyph span at all. */
dialog.fsheet { margin: 0; padding: 0; border: 0; position: fixed; inset: auto 0 0 0; width: 100%; max-width: none; max-height: 80vh; border-radius: 14px 14px 0 0; background: var(--bg); color: var(--ink); box-shadow: 0 -8px 30px rgba(0,0,0,.18); font-family: var(--font); }
/* an unopened <dialog> is display: none by default, but that UA rule loses
   to ANY author rule of equal-or-greater specificity -- `display: flex`
   declared unconditionally above would have kept the sheet on the page
   (and, being `position: fixed`, pinned to the viewport's bottom) even
   with no `open` attribute and no JS. `[open]` is what actually shows it. */
dialog.fsheet[open] { display: flex; flex-direction: column; }
/* A45.9 "sheet layout": the dialog's own single child is the <form> --
   without this, `.sheet-body`'s `flex: 1` below has no flex CONTAINER to
   answer to (a plain block form lays out head/body/foot at their natural
   heights instead), so the body never scrolls independently and the head/
   foot can be pushed off a short viewport. */
dialog.fsheet[open] > form { display: flex; flex-direction: column; flex: 1; min-height: 0; }
dialog.fsheet::backdrop { background: rgba(10,11,13,.42); }
dialog.fsheet .grab { width: 36px; height: 4px; border-radius: 2px; background: var(--edge); margin: 8px auto 2px; flex: none; }
dialog.fsheet .sheet-head { display: flex; justify-content: space-between; align-items: baseline; padding: 8px 16px 10px; border-bottom: 1px solid var(--line); flex: none; }
dialog.fsheet .sheet-head span { font-size: var(--fs-16); font-weight: 600; }
dialog.fsheet .close { color: var(--ink-2); background: none; border: 0; padding: 4px; cursor: pointer; display: inline-flex; }
/* `min-height: 0` overrides a flex item's default `min-height: auto`, which
   would otherwise let the body grow to fit ALL its content and push past
   the dialog's own max-height instead of scrolling internally. */
dialog.fsheet .sheet-body { overflow-y: auto; padding: 4px 12px 12px; font-size: var(--fs-15); flex: 1; min-height: 0; }
dialog.fsheet .fgroup { border-bottom: 1px solid var(--line); }
dialog.fsheet .fgroup:last-of-type { border-bottom: 0; }
dialog.fsheet .fgroup > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 8px; padding: 12px 4px; }
dialog.fsheet .fgroup > summary::-webkit-details-marker { display: none; }
dialog.fsheet .fgroup > summary .k { font-weight: 600; font-size: var(--fs-14); color: var(--ink); }
dialog.fsheet .fgroup > summary .v { margin-left: auto; font-size: var(--fs-13); color: var(--ink-2); max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A45.9 "a11y/nits": `.gl` is a `<fieldset>` now (the group's own radios,
   under a visually-hidden `<legend>`), so the UA's default border/margin/
   padding box needs resetting -- the visible spacing is unchanged from the
   plain `<div>` this replaces. */
dialog.fsheet .gl { border: 0; margin: 0; padding: 0 0 8px; min-inline-size: 0; min-width: 0; }
dialog.fsheet .gl .opt { padding: 8px 4px; }
dialog.fsheet .opt input[type="radio"], dialog.fsheet .opt input[type="checkbox"] { accent-color: var(--ink); flex: none; }
dialog.fsheet .opt--disabled { color: var(--ink-3); opacity: .7; }
dialog.fsheet .opt--sw { padding: 10px 4px; }
dialog.fsheet .sheet-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px; padding: 10px 16px 14px; border-top: 1px solid var(--line); flex: none; }
dialog.fsheet .sheet-foot .go { flex: 1; text-align: center; padding: 11px; border-radius: 8px; background: var(--ink); color: var(--bg); font-weight: 600; }
dialog.fsheet .sheet-foot .go:hover { text-decoration: none; }
dialog.fsheet .sheet-foot .fclear { font-size: var(--fs-14); margin-left: 0; }
/* A45.9 "the sheet carries the cut it does not show" 's sibling clause, the
   side link: the bar's own `.fside` pins itself to the row's far end
   (`margin-left: auto`), which inside this flex-wrapped foot would instead
   shove Clear and Show results down to their own line -- reset to a plain
   leading item, wrapping onto its own line ABOVE the foot row when the three
   don't fit at 390px (flex-wrap on the foot itself, above). */
dialog.fsheet .sheet-foot .fside { font-size: var(--fs-14); margin-left: 0; flex-basis: 100%; }

/* the applied-cut band: heads the list panel, bleeding to its edges (the
   panel's own 20px/24px padding) the way a table's own head band would. */
.band { display: flex; gap: 12px 24px; align-items: flex-end; flex-wrap: wrap; margin: -20px -24px 18px; padding: 14px 24px; border-bottom: 1px solid var(--line); background: var(--bg); border-radius: 10px 10px 0 0; font-size: var(--fs-14); }
.stamp { font-size: var(--fs-20); font-weight: 600; letter-spacing: -0.01em; }
.band-count { font-size: var(--fs-13); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.band.stampband { align-items: baseline; }
.band.stampband .band-count { margin-left: auto; }
/* one-clock B34/B41: the rolling cut's dates, quiet beside the stamp; the walker wraps only when it holds a range, so a long locale's range drops under the stamp instead of running past the panel at 390 (each item keeps .walk's nowrap) */
.band.stampband .band-range { color: var(--ink-3); font-size: var(--fs-13); font-variant-numeric: tabular-nums; }
.band.stampband .walk:has(.band-range) { flex-wrap: wrap; row-gap: 0; }
/* A26.8: the reception count note as the first list panel's head band. */
.band.note { padding: 12px 24px; color: var(--ink-2); align-items: center; }
/* A26.4: an empty cut keeps its walker -- no panel exists to head, so the
   same band stands on the ground above `.no-rows`, unbled and uncounted.
   A28.2 (2026-09-20) withdrew this on /charts, where the panel now stands
   with or without rows so the walker cannot move; the calendar's day,
   quarter and year pages are what still emit it. */
.band--ground { margin: 0 0 18px; padding: 0 0 14px; border-radius: 0; background: none; }
/* N17: the quarter/year/day panel is a plain block (never a grid like
   `.cal`, whose own `.cal > .band` rule already zeroes this out), so
   `.band`'s own -18px bottom margin left an 18px dead strip under it. */
.band--flush { margin-bottom: 0; }
/* A47.2: the horizon's head band -- a title and the head count on the
   baseline, the count at the right, the filter bar on its own second line
   (A45.1), as the walker bands lay theirs out. No walker: the horizon
   always starts today. */
.horizon > .band { align-items: baseline; }
.horizon > .band .band-count { margin-left: auto; }
.horizon > .band .fbar { margin-top: 2px; }
/* the title takes the walker's row box (.walk's 7px), so switching to Horizon from a walker view moves nothing */
.horizon > .band > .stamp { display: inline-flex; padding: 9px 0 5px; }
/* A45.1 retired the `.rail-layout .row`/`.rail-layout .rows-head` trace-
   column override -- the rail is gone from every page, so the trace column
   is full width again (never narrowed for a sidebar that no longer stands). */
.remaining > summary { list-style: none; cursor: pointer; display: inline; }
.remaining > summary::-webkit-details-marker { display: none; }
.remaining > summary:hover { text-decoration: underline; text-underline-offset: 3px; }
.remaining[open] > summary { margin-bottom: 14px; display: block; }
.g > .remaining { padding: 10px 0 4px; }

/* trace-hero trace (home #1, game page) -- A33 (2026-09-20): terminal. The
   readout column sits where the line finishes, and its own left border is
   the 0-100 ruler, so "the line ends at 75" and "75" are one reading.
   Every item names both its column and its row: an item with only a
   grid-column drops to row 2. Supersedes A20.1-A20.5/A20.7 and A22.1's
   derivation inputs. */
.trace-hero { display: grid; gap: 0; --readout-w: 176px; grid-template-columns: minmax(0,1fr) var(--readout-w); align-items: start; padding: 24px 0 8px; }
.panel > .trace-hero { padding: 0 0 8px; }
.trace-hero-title { grid-column: 1 / -1; grid-row: 1; font-size: var(--fs-24); font-weight: 600; letter-spacing: -0.02em; margin: 0 0 14px; }
.trace-hero .trace { width: 100%; height: auto; display: block; }
/* A18: the home hero carries the #1's cover and ends before a rows-head, so the leader is set apart from the rows under it */
/* A33.7: the cover derivation, re-solved -- the column beside the cover is
   now the plot (svg + axis) and the readout column, so the chrome is the
   axis alone: --fs-12 * 1.5 + the axis's own 4px margin-top = 22px.
   --trace-ratio is the home hero's own 680:200 viewBox. Measured, not
   guessed -- every input is named here, and a fatal test re-derives the
   result from them. */
.trace-hero--lead { --trace-ratio: 3.4; --hero-gap: 28px; --column-chrome: 22px;
  grid-template-columns: calc((100% - var(--readout-w) - var(--hero-gap) + var(--trace-ratio) * var(--column-chrome)) * 3 / (4 * var(--trace-ratio) + 3)) minmax(0,1fr) var(--readout-w);
  }
.trace-hero--lead .cover { grid-column: 1; grid-row: 2; width: 100%; height: auto; aspect-ratio: 3 / 4; border-radius: 6px; align-self: start; }
.trace-plot { grid-column: 1; grid-row: 2; min-width: 0; }
.trace-hero--lead .trace-plot { grid-column: 2; margin-left: var(--hero-gap); }
.axis { display: flex; justify-content: space-between; font-size: var(--fs-12); color: var(--ink-3); font-variant-numeric: tabular-nums; margin-top: 4px; padding-right: 6px; }
/* launch-guess P5/P8: with a guess the axis carries three labels -- the start at left, today (or the held guess's distance) centred on the split, the launch right-aligned to the launch line -- each placed by an inline left percentage of the plot. P7: the guess's sentence sits under the axis, before the change list. */
.axis--guess { position: relative; display: block; height: 16px; }
.axis--guess > span { position: absolute; top: 0; left: 0; white-space: nowrap; }
.axis-split { transform: translateX(-50%); }
.axis-launch { transform: translateX(-100%); padding-right: 4px; color: var(--ink-2); }
/* launch-guess V7: a month or quarter guess puts the bare period on the axis, centred on its span. */
.axis-window { transform: translateX(-50%); color: var(--ink-2); }
/* launch-guess V7: a span narrower than a fifth of the plot right-aligns its label to the launch edge, as .axis-launch does, so a far-out month's label never runs past the plot. */
.axis-window--end { transform: translateX(-100%); padding-right: 4px; }
.trace-guess { margin: 12px 0 0; max-width: 72ch; font-size: var(--fs-14); line-height: 1.45; color: var(--ink-2); }

/* the annotated trace */
.trace { overflow: visible; }
.trace .mark-stem { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 2 2; }
.trace .base { stroke: var(--line); stroke-width: 1; }
.trace .tick { stroke: var(--edge); stroke-width: 1; }
.trace .gap-hatch { stroke: var(--edge); stroke-width: 1; }
/* launch-guess P2-P4: the ahead zone (tint), its dashed launch line, the two band polygons (outer p10..p90, inner p25..p75) and the 8-in-10 bracket. */
.trace .trace-ahead { fill: var(--tint); }
.trace .trace-launch { stroke: var(--edge); stroke-width: 1; stroke-dasharray: 3 3; }
.trace .trace-band--outer { fill: var(--ink-3); opacity: .16; }
.trace .trace-band--inner { fill: var(--ink-3); opacity: .22; }
.trace .trace-bracket { fill: none; stroke: var(--ink-2); stroke-width: 1.25; }
/* launch-guess V7: a month or quarter guess draws its period's span (a darker window with two dashed edges) in place of the launch line, and a dashed 8-in-10 box across the span in place of the bracket. The box is in the zone, not the gutter, so it stays at phone width. */
.trace .trace-window { fill: var(--edge); opacity: .22; }
.trace .trace-window-edge { stroke: var(--edge); stroke-width: 1; stroke-dasharray: 3 3; }
.trace rect.trace-box { fill: none; stroke: var(--ink-2); stroke-width: 1.25; stroke-dasharray: 4 3; }
/* era-seams ES9: the dashed hairline per seam (a long dash, so it reads apart from the dotted event stems beside it), and its label above the plot: one block per cluster in normal flow, padded in from the side it hangs on so the text wraps inside the plot and never overhangs it; the label's dashed border is the seam. */
.trace .trace-seam { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 6 4; opacity: .6; }
/* A73.9: the hero's hole. A butt cap: a round one on a 2-unit stroke would turn 2 4 into 4 on, 2 off. */
.trace .trace-hole { stroke-dasharray: 2 4; stroke-linecap: butt; }
.trace-seams { min-height: 0; margin-bottom: 4px; }
.trace-seam-block { font-size: var(--fs-12); line-height: 16px; }
.trace-seam-block--right { text-align: right; }
.trace-seam-block--left { text-align: left; }
.trace-seam-label { display: inline-block; box-sizing: border-box; max-width: 100%; font-size: var(--fs-12); line-height: 16px; color: var(--ink-2); text-align: inherit; vertical-align: top; }
.trace-seam-block--right .trace-seam-label { padding-right: 5px; border-right: 1px dashed var(--ink-3); }
.trace-seam-block--left .trace-seam-label { padding-left: 5px; border-left: 1px dashed var(--ink-3); }
/* ES9: the home spotlight's cover derivation counts the label rows, one 16px line per cluster (a second or third cluster is a later sibling; a wrapped label is not counted). */
.trace-hero--lead:has(.trace-seams) { --column-chrome: calc(22px + 16px + 4px); }
.trace-hero--lead:has(.trace-seam-block + .trace-seam-block) { --column-chrome: calc(22px + 2 * 16px + 4px); }
.trace-hero--lead:has(.trace-seam-block + .trace-seam-block + .trace-seam-block) { --column-chrome: calc(22px + 3 * 16px + 4px); }

/* A33.3: the axis is absolute -- a fixed 0-100 ruler, its ticks ending on
   the svg's own right edge (the readout's own border), three HTML labels
   (never SVG text, so they never scale with the viewBox) reading 0/50/100. */
.trace-box { position: relative; box-sizing: border-box; }
.trace-box .trace-empty { position: absolute; left: 0; bottom: 16px; margin: 0; font-size: var(--fs-14); color: var(--ink-3); }
.trace-box .scale { position: absolute; right: 14px; transform: translateY(-50%); font-size: var(--fs-12); color: var(--ink-3); font-variant-numeric: tabular-nums; line-height: 1; }
/* A61: the event numbers leave the line for a rail under the plot. Every tag
   and leader is positioned as a percentage of the rail, once per rung of
   Hype::TraceRail (--x0..--x5, g[data-rung]); the rail's own width picks the
   rung. The stem's dash pattern starts at its junction with the leader. */
.ev-rail { position: relative; height: 32px; container-type: inline-size; }
.ev-leaders { position: absolute; top: 0; left: 0; width: 100%; height: 32px; overflow: visible; }
.ev-leaders line { stroke: var(--ink-3); stroke-width: 1; vector-effect: non-scaling-stroke; }
.ev-leaders g { display: none; }
.ev-leaders g[data-rung="0"] { display: inline; }
.ev { position: absolute; top: 12px; left: var(--x0); transform: translateX(-50%); box-sizing: border-box; height: 18px; min-width: 18px; padding: 0 5px; border: 1.25px solid var(--ink); border-radius: var(--radius-pill); background: var(--bg); color: var(--ink); font: 600 10.5px/15.5px var(--font); text-align: center; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ev[data-lit] { background: var(--ink); color: var(--bg); }
@container (min-width: 340px) {
  .ev { left: var(--x1); }
  .ev-leaders g[data-rung] { display: none; }
  .ev-leaders g[data-rung="1"] { display: inline; }
}
@container (min-width: 440px) {
  .ev { left: var(--x2); }
  .ev-leaders g[data-rung] { display: none; }
  .ev-leaders g[data-rung="2"] { display: inline; }
}
@container (min-width: 560px) {
  .ev { left: var(--x3); }
  .ev-leaders g[data-rung] { display: none; }
  .ev-leaders g[data-rung="3"] { display: inline; }
}
@container (min-width: 700px) {
  .ev { left: var(--x4); }
  .ev-leaders g[data-rung] { display: none; }
  .ev-leaders g[data-rung="4"] { display: inline; }
}
@container (min-width: 860px) {
  .ev { left: var(--x5); }
  .ev-leaders g[data-rung] { display: none; }
  .ev-leaders g[data-rung="5"] { display: inline; }
}

/* A33.4: the readout column -- figure, band word, the day's own delta, then
   the window's high/low under a hairline. Its own left border IS the ruler. */
.trace-readout { grid-column: -2 / -1; grid-row: 2; align-self: stretch; border-left: 1px solid var(--line); padding-left: 16px; display: flex; flex-direction: column; font-variant-numeric: tabular-nums; }
.trace-readout .big { font-size: var(--fs-44); line-height: 1; font-weight: 600; letter-spacing: -0.03em; }
.trace-readout .word { color: var(--ink); font-size: var(--fs-15); font-weight: 550; margin-top: 8px; }
.trace-readout .delta { font-size: var(--fs-13); color: var(--ink-2); margin-top: 4px; }
.trace-readout .delta b { font-weight: 550; }
.trace-readout .facts { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--line-2); display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; font-size: var(--fs-13); color: var(--ink-2); }
.trace-readout .facts b { color: var(--ink); font-weight: 550; text-align: right; }
/* launch-guess P6: the At launch (or Guessed) range, a second facts block under High / Low. */
.trace-readout .facts--guess { margin-top: 10px; }
/* launch-guess V7: "if it launches in <period>" under a period guess's range, across both columns. */
.trace-readout .facts-note { grid-column: 1 / -1; margin-top: -2px; font-size: var(--fs-12); color: var(--ink-3); }

/* A51.4 (superseding A33.6's ledger): the change list is the chart's own
   caption -- it sits in the plot's own column, directly under the axis, one
   52px row per change on number, date, change, context and the hype move. */
/* the selector reaches both the wrapper div and each group's ol; the ol is no
   grid item and takes no margin of its own */
.trace-hero .changes { grid-column: 1 / -1; grid-row: 3; margin-top: 14px; }
.trace-hero ol.changes { margin-top: 0; }
.changes-head { display: grid; grid-template-columns: 22px 52px minmax(0,1fr) 230px 128px; gap: 12px; height: 28px; align-items: end; padding-bottom: 6px; border-bottom: 1px solid var(--line); font-size: var(--fs-12); color: var(--ink-3); }
.changes-head span:last-child { text-align: right; }
.changes li { display: grid; grid-template-columns: 22px 52px minmax(0,1fr) 230px 128px; gap: 12px; height: 52px; align-items: center; border-bottom: 1px solid var(--line-2); font-size: var(--fs-14); }
.changes li:hover { background: var(--tint); }
.changes .n { font-weight: 600; font-size: var(--fs-12); }
.changes .d { color: var(--ink-3); font-variant-numeric: tabular-nums; font-size: var(--fs-13); }
.changes .c { min-width: 0; display: grid; grid-template-columns: 12px minmax(0,1fr); column-gap: 6px; align-items: center; line-height: 1.25; }
.changes .c b { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.changes .c small { grid-column: 2; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.changes .x { color: var(--ink-2); font-size: var(--fs-13); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.m { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.25; font-variant-numeric: tabular-nums; }
.m small { color: var(--ink-3); font-size: var(--fs-12); white-space: nowrap; }
.mv { font-size: var(--fs-13); font-weight: 550; color: var(--ink-2); white-space: nowrap; }
.mv--up { color: var(--up); }
.mv--down { color: var(--down); }
.mv--same { font-weight: 400; color: var(--ink-3); }
.m--none { color: var(--ink-3); text-align: right; display: block; }
.m--none small { display: block; white-space: normal; text-align: right; }
.changes-sub { margin-top: 18px; padding-bottom: 6px; border-bottom: 1px solid var(--line); font-size: var(--fs-12); color: var(--ink-3); }
.changes-head + .changes-sub { margin-top: 6px; }
.changes-more > summary, .why-more > summary { display: flex; align-items: center; height: 52px; list-style: none; cursor: pointer; font-size: var(--fs-13); color: var(--ink-2); border-bottom: 1px solid var(--line-2); }
.why-more > summary { border-bottom: 0; }
.changes-more > summary::-webkit-details-marker, .why-more > summary::-webkit-details-marker { display: none; }
.changes-more > summary:hover, .why-more > summary:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
/* A54: the launch step's "Why N" seats, a closed reveal under its changes */
.trace-hero .why-more { grid-column: 1 / -1; grid-row: 4; }
.why-more > p { margin-top: 12px; font-size: var(--fs-14); }
.why-link a { color: var(--ink-2); }
.trace .mk[data-lit] .mark-stem { stroke: var(--ink); stroke-dasharray: none; }
.ic { display: block; color: var(--ink-2); fill: currentColor; }

/* game page */
.game-head { display: grid; grid-template-columns: 96px minmax(0,1fr); gap: 24px; align-items: start; }
.game-head img { width: 96px; border-radius: 3px; }
.game-head h1 { font-size: var(--fs-36); font-weight: 650; letter-spacing: -0.02em; line-height: 1.1; }
.game-meta { color: var(--ink-2); margin-top: 8px; font-size: var(--fs-15); }
.game-meta b { color: var(--ink); font-weight: 550; }
.status-line { margin-top: 10px; display: flex; gap: 8px 20px; flex-wrap: wrap; font-size: var(--fs-15); }
.status-line .k { color: var(--ink-3); }
.game-head .about-text { margin-top: 14px; }
.game-tabs { margin-top: 28px; }
/* A37: the game page is a stepper -- one step per phase down the page, the
   current step open on its own hypemeter, every other step one 76px row
   that opens in place (details.step-more) to the same anatomy. Three glyph
   states (Material stepper): done = ring with a check, current = ring with a
   solid core, later = dashed ring; the row's own word carries the state too. */
.steps { margin-top: 2px; }
.step { display: grid; grid-template-columns: 28px minmax(0,1fr); column-gap: 14px; position: relative; }
.step::before { content: ""; position: absolute; left: 13.5px; top: 0; bottom: 0; border-left: 1px solid var(--line); }
.step:first-child::before { top: 38px; }
.step:last-child::before { bottom: auto; height: 38px; }
.step:only-child::before { display: none; }
.step-node { grid-column: 1; height: 76px; display: flex; align-items: center; justify-content: center; position: relative; }
.step-node .node { width: 20px; height: 20px; background: var(--bg); border-radius: 50%; color: var(--ink-3); }
.step--done .step-node .node { color: var(--ink-3); }
.step--current .step-node .node { color: var(--ink); }
.step--later .step-node .node { color: var(--ink-3); }
.step-row { grid-column: 2; display: grid; grid-template-columns: 200px minmax(0,1fr) 200px 176px; gap: 16px; align-items: center; height: 76px; border-bottom: 1px solid var(--line); }
.step:first-child .step-row { border-top: 1px solid var(--line); }
.step-name { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.step-name small { display: block; color: var(--ink-2); font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.step-when { color: var(--ink-2); font-size: var(--fs-15); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.step-when b { color: var(--ink); font-weight: 550; }
.step-row .mini { width: 200px; height: 32px; }
.step-row .fig { text-align: right; font-size: var(--fs-20); }
.step-row .fig small { display: block; font-size: var(--fs-12); color: var(--ink-3); font-weight: 400; }
.step--current .step-name { font-weight: 650; }
.step--current .step-when b { font-weight: 650; }
.step-more { grid-column: 2; }
.step-more > summary { list-style: none; cursor: pointer; }
.step-more > summary::-webkit-details-marker { display: none; }
.step-more > summary:hover .step-name { text-decoration: underline; text-underline-offset: 3px; }
.step-open { grid-column: 2; padding: 4px 0 20px; border-bottom: 1px solid var(--line); }
.step-more .step-open { border-top: 0; }
.step-open .trace-hero { padding: 8px 0 4px; }
.step-open .trace-hero-title { font-size: var(--fs-18); margin-bottom: 10px; }
.node { width: 14px; height: 14px; flex: none; }
.node circle { fill: none; stroke: currentColor; stroke-width: 1.5; }
.node path { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.node--done circle { fill: var(--bg); }
.node--current .core { fill: currentColor; stroke: none; }
.node--later circle { stroke-dasharray: 3 2.5; }
/* A71 (docs/design/rebuild-8/00-contract.md A71.7, transcribed from the generator's PROPOSED sheet): a step with nothing recorded behind it is not a disclosure (quiet, A71.3) and a run of such steps is one fold (K1) whose closed details opens to 44px sub-rows aligned to the step row's own columns. */
.step--quiet .step-row { color: var(--ink-2); }
.step--quiet .step-name { font-weight: 500; }
.node--fold .dot { fill: currentColor; stroke: none; }
.step--fold .step-name { font-weight: 500; }
.step-anchor { position: absolute; top: 0; left: 0; }
.step--fold .step-open { padding: 0 0 6px; }
.sub-rows { list-style: none; margin: 0; padding: 0; }
.sub-row { display: grid; grid-template-columns: 200px minmax(0,1fr) 176px; gap: 16px; align-items: center; height: 44px; border-bottom: 1px solid var(--line-2); font-size: var(--fs-15); }
.sub-row:last-child { border-bottom: 0; }
.sub-date { color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.sub-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sub-name small { color: var(--ink-2); font-size: var(--fs-13); margin-left: 4px; }
.sub-fig { text-align: right; color: var(--ink-3); font-size: var(--fs-13); white-space: nowrap; }
.seat-list { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 0 40px; }
.seat { display: grid; grid-template-columns: minmax(0,1fr) 120px 72px; gap: 12px; align-items: center; height: 38px; border-bottom: 1px solid var(--line-2); font-size: var(--fs-14); }
.seat > span:first-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.seat .bar { height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; }
.seat .bar i { display: block; height: 100%; background: var(--ink-2); }
.seat .pts { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.seat .pts b { color: var(--ink); font-weight: 550; }
.about-text { max-width: 64ch; color: var(--ink-2); }
.links { display: flex; gap: 6px 18px; flex-wrap: wrap; font-size: var(--fs-14); margin-top: 12px; }
.links a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line); }
.verdict-strip { display: grid; grid-template-columns: repeat(3, auto) minmax(0,1fr); gap: 40px; align-items: end; }
.verdict-strip .big { font-size: var(--fs-44); line-height: 1; font-weight: 600; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.verdict-strip .word { display: block; font-size: var(--fs-13); color: var(--ink-2); margin-bottom: 6px; }
.verdict-strip-word { font-size: var(--fs-18); font-weight: 600; }
.verdict-strip-word small { display: block; font-weight: 400; color: var(--ink-2); }

/* A50.5 / A76.5: the shaded last week, drawn first in the quiet trace of a risers row */
.mini-week { fill: var(--line-2); }

/* dated rows (releasing soon, calendar day) */
.dated { border-top: 1px solid var(--line); }
.dated li { display: grid; grid-template-columns: 96px minmax(0,1fr) 64px; gap: 16px; align-items: center; height: 56px; border-bottom: 1px solid var(--line); }
.dated .d { font-variant-numeric: tabular-nums; font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dated .d small { display: block; color: var(--ink-3); font-weight: 400; }
.dated .n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dated .n small { color: var(--ink-2); margin-left: 8px; }
.dated .n > .icon { width: 14px; height: 14px; vertical-align: -2px; margin-right: 6px; color: var(--ink-3); }
.dated .cover { display: inline-block; vertical-align: middle; margin-right: 10px; }
.dated .hype { text-align: right; font-size: var(--fs-18); }

/* A56.2: the showcase rows -- dated rows with the key art as a 16:9 thumb and the show's changes on the note line */
.sc-list li { grid-template-columns: 96px 64px minmax(0,1fr); gap: 16px; height: 60px; } /* A68.1: 96px, .dated's own, so the time's zone fits */
.sc-list .n { display: flex; flex-direction: column; line-height: 1.3; }
.sc-list .n a { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sc-list .n small { margin-left: 0; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sc-list .n small .ic, .sc-strip dt .ic, .section-head h2 .ic { display: inline-block; vertical-align: -2px; margin-right: 4px; }
.sc-list .n small .ic { color: var(--ink-3); }
.sc-list .n small.sc-up a { color: var(--ink-2); font-weight: 400; display: inline-flex; align-items: center; gap: 4px; }
.sc-list .n small.sc-up .icon { width: 13px; height: 13px; }
.sc-list .n small.sc-up a::before { content: "·"; margin: 0 6px 0 4px; color: var(--ink-3); }
.sc-list .n small .live { font-weight: 600; color: var(--ink); }
.sc-thumb { width: 64px; height: 36px; object-fit: cover; border-radius: 4px; background: var(--tint); display: block; }
.sc-thumb--none { background: var(--line-2); }
.feed-day + .sc-list { border-top: 0; }
.section > .sc-list + .feed-day { margin-top: 8px; }

/* A56.4: the front page's showcase band -- one show is a 16:9 key art beside its date, phrase and links; two or
   three are columns of art over a name and two lines. A live show wears the .live chip on its art. `.scb--many li`
   carries no height on a desktop (its second grid row is the text's own 66px); the phone rows below carry 84px. */
.scb-band .section-head a { white-space: nowrap; }
.scb { min-width: 0; }
.scb--one { display: grid; grid-template-columns: 400px minmax(0,1fr); gap: 28px; align-items: start; }
.scb-art { position: relative; display: block; }
.scb-art > a { display: block; }
.scb-img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 8px; background: var(--tint); }
.scb-img--none { background: var(--line-2); }
.scb-flag { position: absolute; top: 8px; left: 8px; padding: 2px 8px; border-radius: 4px; background: var(--bg); font-size: var(--fs-13); font-weight: 600; line-height: 20px; }
.scb-body h3 { color: var(--ink); font-size: var(--fs-24); font-weight: 600; letter-spacing: -0.01em; line-height: 1.2; text-wrap: balance; }
.scb-when { color: var(--ink-2); margin-top: 8px; }
.scb-rel { font-size: var(--fs-20); font-weight: 600; margin-top: 6px; font-variant-numeric: tabular-nums; }
.scb-links { display: flex; gap: 18px; margin-top: 14px; font-size: var(--fs-14); }
.scb-links a { display: inline-flex; align-items: center; gap: 6px; color: var(--ink-2); }
.scb--many { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px; }
.scb--n2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.scb--many li { display: grid; grid-template-rows: auto 66px; min-width: 0; }
.scb-t { display: flex; flex-direction: column; min-width: 0; padding-top: 10px; line-height: 1.3; }
.scb-name { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.scb-t small { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* A56.3: the show page leads with its stream -- the name on one line, the on-air line, the player spanning
   the content width on the ground (no stage band, owner 2026-10-06), the strip of
   facts on the ground (a stated C5 exception), the description clamped to three lines, the line-up by change */
.sc-h1 { max-width: none; }
.sc-onair { margin-top: 8px; font-weight: 600; }
.sc-onair .live + span { font-weight: 400; color: var(--ink-2); margin-left: 6px; }
.sct { margin-top: 20px; }
.sct .playbox { border-radius: 10px; background: var(--stage-2); }
.sct .playbox button { width: 76px; height: 76px; }
.sct-tag { position: absolute; left: 16px; bottom: 14px; padding: 2px 8px; border-radius: 4px; background: rgba(0,0,0,.66); color: #fff; font-size: var(--fs-13); }
.sc-stage .sc-count { position: absolute; left: 0; right: 0; bottom: 0; padding: 96px 24px 20px; background: linear-gradient(transparent, rgba(0,0,0,.72) 45%, rgba(0,0,0,.92)); color: #fff; }
.sc-stage .sc-count b { display: block; font-size: var(--fs-32); font-weight: 600; letter-spacing: -0.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
.sc-stage .sc-count small { color: rgba(255,255,255,.86); font-size: var(--fs-14); }
.sc-strip { display: flex; flex-wrap: wrap; margin: 0; border-bottom: 1px solid var(--line); }
.sc-strip > div { padding: 14px 28px 14px 0; margin-right: 28px; border-right: 1px solid var(--line); min-width: 0; }
.sc-strip > div:last-child { border-right: 0; }
.sc-strip dt { color: var(--ink-2); font-size: var(--fs-13); white-space: nowrap; }
.sc-strip dd { margin: 2px 0 0; font-size: var(--fs-18); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; display: flex; align-items: baseline; gap: 6px; }
.sc-strip dd small { font-size: var(--fs-13); font-weight: 400; color: var(--ink-2); }
.sc-strip dd a { display: inline-flex; align-items: center; gap: 6px; }
.sc-strip dd .icon { align-self: center; }
.sc-strip .sc-quiet { font-size: var(--fs-15); }
.sc-strip + .lead-note { margin-top: 16px; }
.sc-quiet { color: var(--ink-2); font-weight: 400; }
.lead-note.sc-desc { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.sc-count-h { color: var(--ink-3); font-weight: 400; font-size: var(--fs-14); margin-left: 4px; }
.sc-lineup { border-top: 1px solid var(--line); }
.sc-lineup li { display: grid; grid-template-columns: 42px minmax(0,1fr) 56px; gap: 14px; align-items: center; height: 64px; border-bottom: 1px solid var(--line); }
.sc-lineup .n { min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.sc-lineup .n a { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sc-lineup .n small { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sc-lineup .hype { text-align: right; font-size: var(--fs-20); }
/* A70.3/A70.5: what the show did for demand -- the arrow is the charts' svg.icon, so every size is set per
   place, never by a group selector that would also hit the upcoming rows' external-link glyph */
#rose .section-head h2 .icon { width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; color: var(--up); }
.sc-strip dt .icon { display: inline-block; width: 12px; height: 12px; vertical-align: -2px; margin-right: 4px; color: var(--up); }
.sc-rise { display: inline-flex; align-items: center; justify-content: flex-end; gap: 2px; color: var(--up); font-size: var(--fs-20); font-weight: 600; font-variant-numeric: tabular-nums; }
.sc-rise .icon { width: 14px; height: 14px; }
p.sc-dnote { color: var(--ink-2); font-size: var(--fs-13); max-width: 70ch; margin: -4px 0 12px; }
span.sc-dv { font-variant-numeric: tabular-nums; }
.sc-mv .icon { display: inline-block; width: 12px; height: 12px; vertical-align: -1px; margin-right: 2px; color: var(--ink-3); }
.section > .remaining { padding-bottom: 0; }

/* the date list (home, releasing soon): each group is a heading above its divider, the rows under it (A16).
   Named `.soon`, not `.rail` -- A26.1 (2026-09-19) gave `.rail` to the aside alone. */
.soon > .g + .g { margin-top: 8px; }
.g-label { display: flex; align-items: baseline; gap: 10px; padding: 12px 0 8px; font-weight: 600; border-bottom: 1px solid var(--line); }
.g-label small { color: var(--ink-3); font-weight: 400; font-variant-numeric: tabular-nums; }
/* A76.4: a rail group's label gives its rule to the head under it (the list's own top rule then closes the head); phones draw the head nowhere, so the label keeps its rule there (phone block) */
.g-label:has(+ .rows-head) { border-bottom: 0; padding-bottom: 6px; }
/* launch-guess R4: the guess opens the meta line, so its digits take equal widths and the ranges line up row to row. */
.rail-guess { font-variant-numeric: tabular-nums; }
/* A74.8: the trend and range package, at a LIST width of 980px (`.rowset`, a register of its own: ROWSET_BREAKPOINTS). It follows every base rule it overrides -- a container query adds no specificity -- so keep it below `.rows > .row`, `.rows-head`, the two cells, the two head spans and `.trace-range`. The tracks bound the copy (A75.2): every locale's Range head fits 72px at --fs-12, and its trend word plus 18px (14px glyph, 4px gap) fits 92px at --fs-13. The glyph takes the trend colour; no trend rule ever sets the range digits'. */
@container rowset (min-width: 980px) {
  .row-trend { display: flex; align-items: center; gap: 4px; font-size: var(--fs-13); white-space: nowrap; }
  .row-trend .icon { width: 14px; height: 14px; flex: none; }
  .row-range { display: block; text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-2); font-size: var(--fs-14); }
  .rows-head-trend { display: block; }
  .rows-head-range { display: block; text-align: right; }
  .trace-range { display: none; }
  .rows > .row:has(> .row-standing):has(> .row-trend), .rows-head:has(> .rows-head-trend) { grid-template-columns: 38px 42px minmax(0,1fr) 240px 92px 72px 64px; }
  .rows > .row:has(> .row-standing > .move):has(> .row-trend), .rows-head:has(> .rows-head-standing > span + span):has(> .rows-head-trend) { grid-template-columns: 116px 42px minmax(0,1fr) 240px 92px 72px 64px; }
  .rows > .row:has(> .row-standing--date):has(> .row-trend), .rows-head:has(> .rows-head-standing--date):has(> .rows-head-trend) { grid-template-columns: 116px 42px minmax(0,1fr) 240px 92px 72px 64px; }
  .row-trend.trend--rising { color: var(--up); }
  .row-trend.trend--falling { color: var(--down); }
  .row-trend.trend--steady { color: var(--ink-2); }
  .row-trend.trend--none { color: var(--ink-3); }
}

/* pagination (updates, search, browse, showcases) and the search form */
.pagerow { display: flex; justify-content: space-between; gap: 16px; margin-top: 24px; font-size: var(--fs-14); }
.pagerow a { padding: 6px 12px; border: 1px solid var(--line); border-radius: 6px; color: var(--ink-2); }
.pagerow a:hover { color: var(--ink); border-color: var(--ink-2); text-decoration: none; }
.pagerow span { color: var(--ink-3); align-self: center; font-variant-numeric: tabular-nums; }
.searchbar { display: flex; gap: 8px; margin: 24px 0; max-width: 640px; position: relative; }
/* A45.5: the search field and button match the menu buttons -- 34px, --edge,
   6px radius, 14px type. A26.5's finding still holds: a `--bg` field inside
   a `--bg` panel has only the 1.6:1 `--edge` border to say "type here", so
   the field keeps `--tint`; the button is outlined like every other control,
   never solid `--ink`. */
.searchbar .search-ic { position: absolute; left: 11px; top: 50%; width: 16px; height: 16px; margin-top: -8px; color: var(--ink-3); pointer-events: none; }
.searchbar input { flex: 1; min-width: 0; height: 34px; padding: 0 12px 0 34px; font-size: var(--fs-14); border: 1px solid var(--edge); border-radius: 6px; background: var(--tint); color: var(--ink); }
.searchbar input:focus { border-color: var(--ink-2); outline: none; box-shadow: 0 0 0 1px var(--ink-2) inset; }
.searchbar button { height: 34px; padding: 0 14px; font-size: var(--fs-14); border: 1px solid var(--edge); border-radius: 6px; background: var(--bg); color: var(--ink); font-weight: 550; cursor: pointer; }
.searchbar button:hover { background: var(--bg); border-color: var(--ink-2); }
/* A26.5: inside the browse band the searchbar shares the row with the sort
   control instead of standing alone at its own fixed width. */
.band .searchbar { flex: 1; max-width: none; margin: 0; }
/* A45.5: Sort stands beside the search, pushed to the row's far end -- the
   searchbar's own `flex: 1` already does the pushing, so this only matters
   where a `.fsort` stands without a preceding `.searchbar`. */
.fsort { margin-left: auto; display: inline-flex; gap: 8px; align-items: center; }
.band .searchbar + .fsort { margin-left: 0; }
/* the sort direction toggle, beside the sort menu, both on `--edge` (A26.7). */
.dir { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border: 1px solid var(--edge); border-radius: 6px; color: var(--ink-2); }
.dir:hover { color: var(--ink); background: var(--tint); text-decoration: none; }
/* A45.4: the applied-cut line under the band -- the total alone now; the
   per-cut chips and Clear moved into the bar. */
.applied { font-size: var(--fs-13); color: var(--ink-2); margin-bottom: 16px; }

/* prose pages (about, hypemeter, privacy) */
.article { max-width: calc(68ch + 48px); }
.article h2 { margin-top: 36px; }
.article > :first-child { margin-top: 0; }
.article h3 { font-size: var(--fs-16); font-weight: 600; margin-top: 24px; }
.article p, .article ul, .article ol, .article table, .article dl { margin: 12px 0; color: var(--ink-2); }
.article ul { padding-left: 20px; list-style: disc; }
.article ol { padding-left: 20px; list-style: decimal; }
.article li { margin: 4px 0; }
.article table { width: 100%; border-collapse: collapse; font-size: var(--fs-14); }
.article th, .article td { text-align: left; padding: 8px 0; border-bottom: 1px solid var(--line-2); vertical-align: top; }
.article th { color: var(--ink); font-weight: 600; }
.article td:last-child, .article th:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.article a { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line); }
.article strong, .article b { color: var(--ink); font-weight: 600; }
.article code { font-size: 0.92em; background: var(--tint); padding: 1px 5px; border-radius: 4px; }

/* the changelog as a release index (A57): the latest release open in its own
   panel, every earlier one a closed 48px row that opens to its change lines.
   An OPEN row is exempt from A3 (A57.5) so its headline reads in full. */
.cl-latest { max-width: 920px; padding: 28px 32px 30px; }
.cl-kicker { color: var(--ink-3); font-size: var(--fs-14); }
.cl-title { font-size: var(--fs-24); font-weight: 600; letter-spacing: -0.01em; line-height: 1.25; margin-top: 6px; text-wrap: balance; }
.cl-version { font-variant-numeric: tabular-nums; }
.cl-changes { display: grid; gap: 12px; margin-top: 14px; max-width: 68ch; }
.cl-changes li { position: relative; padding-left: 18px; color: var(--ink-2); }
/* the bullet is a 5px square by aspect-ratio, not a height: it is a dot, not a list row, and the R census reads any li rule that declares a height */
.cl-changes li::before { content: ""; position: absolute; left: 2px; top: .68em; width: 5px; aspect-ratio: 1; border-radius: 50%; background: var(--ink-3); }
.cl-lead { color: var(--ink); font-weight: 500; }
.cl-latest + .cl-index { margin-top: 24px; }
.cl-index { max-width: 920px; padding: 20px 0 8px; }
.cl-index > h2 { padding: 0 24px; }
.cl-month { font-size: var(--fs-13); font-weight: 600; color: var(--ink-3); padding: 18px 24px 6px; }
.cl-row { border-top: 1px solid var(--line-2); }
.cl-row > summary { list-style: none; cursor: pointer; display: grid; grid-template-columns: 88px minmax(0,1fr) 120px 64px 16px; align-items: center; gap: 16px; height: 48px; padding: 0 24px; }
.cl-row > summary::-webkit-details-marker { display: none; }
.cl-row > summary:hover { background: var(--tint); }
.cl-date { color: var(--ink-2); font-size: var(--fs-14); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cl-stack { display: none; }
.cl-headline { color: var(--ink); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cl-count { color: var(--ink-3); font-size: var(--fs-13); text-align: right; white-space: nowrap; }
.cl-row > summary .cl-version { color: var(--ink-3); font-size: var(--fs-13); text-align: right; white-space: nowrap; }
.cl-chev { width: 8px; height: 8px; border-right: 1.5px solid var(--ink-3); border-bottom: 1.5px solid var(--ink-3); transform: rotate(45deg) translate(-2px,-2px); justify-self: end; }
.cl-row[open] > summary .cl-chev { transform: rotate(-135deg) translate(-1px,-1px); }
.cl-row[open] > summary { background: var(--tint); height: auto; min-height: 48px; padding-top: 10px; padding-bottom: 10px; }
.cl-row[open] .cl-headline { white-space: normal; display: block; -webkit-line-clamp: unset; overflow: visible; text-overflow: clip; }
.cl-body { padding: 4px 24px 22px 128px; }
.cl-body .cl-changes { margin-top: 10px; }
.cl-meta { display: none; color: var(--ink-3); font-size: var(--fs-13); }

/* screenshots (stills) and the lightbox (viewer) */
.stills { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 12px; }
.stills a { display: block; aspect-ratio: 16 / 9; overflow: hidden; border-radius: 3px; background: var(--tint); }
.stills img { width: 100%; height: 100%; object-fit: cover; }
/* a modal <dialog> keeps the UA's width/height: fit-content, max-width/max-height, margin and border -- reset all of them or the viewer
   shrinks to its image: the dark field covers only the image and the absolutely placed buttons land on the image's top corners */
.viewer { position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; border: 0; background: rgba(0,0,0,.92); color: #fff; display: grid; place-items: center; z-index: 30; padding: 16px; }
.viewer:not([open]) { display: none; }
.viewer img { max-width: 100%; max-height: 92vh; object-fit: contain; }
.viewer button { position: absolute; top: 12px; right: 12px; width: 40px; height: 40px; border: 0; border-radius: 50%; background: rgba(255,255,255,.12); color: #fff; cursor: pointer; font-size: var(--fs-20); }
/* .viewer .viewer-* (0,2,0), not bare .viewer-* (0,1,0): the generic `.viewer button` (0,1,1) above would otherwise win top/right */
.viewer .viewer-prev, .viewer .viewer-next { top: 50%; transform: translateY(-50%); }
.viewer .viewer-prev { right: auto; left: 12px; }
.viewer button svg { width: 20px; height: 20px; }

/* the video facade (playbox) */
.playbox { position: relative; aspect-ratio: 16 / 9; background: var(--tint); border-radius: 8px; overflow: hidden; }
.playbox img, .playbox iframe { position: absolute; inset: 0; width: 100%; height: 100%; display: block; object-fit: cover; border: 0; }
.playbox button { position: absolute; inset: 0; margin: auto; width: 64px; height: 64px; border-radius: 50%; border: 0; background: var(--bg); color: var(--ink); cursor: pointer; display: grid; place-items: center; }
.playbox button[hidden] { display: none; }
.playbox button svg { width: 24px; height: 24px; }
/* the video strip (A62, replacing A13's clip grid): one strip per release, a caption under the playbox, thumbnails that scroll sideways */
.film { display: grid; grid-auto-flow: column; grid-auto-columns: 190px; gap: 12px; overflow-x: auto; scroll-snap-type: x proximity; scroll-padding-inline: 4px; padding: 4px 4px 10px; margin: 16px -4px 0; scrollbar-width: thin; }
.film li { scroll-snap-align: start; }
.film button { display: block; width: 100%; padding: 0; border: 0; background: none; color: inherit; text-align: left; cursor: pointer; }
.film-thumb { position: relative; display: block; aspect-ratio: 16 / 9; border-radius: 6px; overflow: hidden; background: var(--tint); }
.film-thumb img { width: 100%; height: 100%; object-fit: cover; }
.film button[aria-current] .film-thumb { outline: 2px solid var(--ink); outline-offset: 2px; }
.film-name { display: block; margin-top: 8px; font-size: var(--fs-14); font-weight: 550; line-height: 20px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.film small { display: block; height: 18px; color: var(--ink-2); line-height: 18px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.film-now { color: var(--ink); font-weight: 600; }
.film button[aria-current] .film-month, .film button:not([aria-current]) .film-now { display: none; }
.film-group { margin-top: 20px; }
.film-group + .film-group { margin-top: 12px; padding-top: 16px; border-top: 1px solid var(--line); }
.film-head { display: flex; gap: 8px; align-items: baseline; height: 22px; margin: 0; font-size: var(--fs-14); font-weight: 400; white-space: nowrap; overflow: hidden; }
.film-head b { font-weight: 600; flex: none; }
.film-head span { color: var(--ink-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.film-group .film { margin-top: 8px; }
.vid-cap { display: grid; margin-top: 10px; min-width: 0; }
.vid-cap[hidden] { display: none; }
.vid-cap b { font-weight: 600; font-size: var(--fs-16); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vid-cap small { color: var(--ink-2); }
.vid-dur { position: absolute; right: 4px; bottom: 4px; padding: 0 4px; border-radius: 3px; background: rgba(0,0,0,.78); color: #fff; font-size: var(--fs-12); line-height: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }

/* the operator bar: an admin-only aside on a game page (docs/ingestion/content-curation.md) */
.operator { margin: 0 0 24px; padding: 12px 16px; border: 1px solid var(--line); border-radius: 8px; font-size: var(--fs-13); display: grid; grid-template-columns: auto minmax(0,1fr) auto; gap: 8px 20px; align-items: center; }
.operator-label { font-weight: 600; color: var(--ink); }
.operator-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.operator-tag { padding: 2px 8px; border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--ink-2); }
.operator-tag--alert { border-color: var(--down); color: var(--down); }
.operator-facts { grid-column: 1 / -1; display: flex; gap: 20px; flex-wrap: wrap; margin: 0; color: var(--ink-2); }
.operator-fact { display: flex; gap: 6px; }
.operator-fact dt { color: var(--ink-3); }
.operator-fact dd { margin: 0; color: var(--ink); font-variant-numeric: tabular-nums; }
.operator-actions { display: flex; gap: 8px; }
.operator-actions a, .operator-actions button { padding: 5px 10px; border: 1px solid var(--line); border-radius: 6px; color: var(--ink-2); background: none; cursor: pointer; }
.operator-actions a:hover, .operator-actions button:hover { color: var(--ink); border-color: var(--ink-2); text-decoration: none; }

/* A51.7: the front page's sentence feed, a day heading over its own list */
.feed-day { display: flex; align-items: flex-end; height: 36px; padding-bottom: 6px; font-size: var(--fs-13); font-weight: 600; color: var(--ink-2); border-bottom: 1px solid var(--line); }
.feed li { display: grid; grid-template-columns: 36px minmax(0,1fr) 48px; gap: 16px; height: 56px; align-items: center; border-bottom: 1px solid var(--line-2); }
.feed li:last-child { border-bottom: 0; }
.feed .t { min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.feed .s { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.feed .s a { font-weight: 650; }
.feed .t small { display: flex; align-items: center; gap: 6px; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.feed .t small .ic { flex: none; }
.feed .hype { text-align: right; font-size: var(--fs-18); }

/* calendar month grid */
/* A46.2: weekends are the narrow tracks, the dow head row included (one grid) */
.cal { display: grid; grid-template-columns: repeat(5, minmax(0,1fr)) repeat(2, minmax(0,.58fr)); padding: 0; overflow: hidden; }
/* A26.4: the walker band is the grid's own first child, spanning every
   column -- `.cal` carries no padding of its own (the cells' own borders do
   the framing), so the band restates it, at 8px to match `.cal-dow`'s own
   left padding (measured, not guessed) so the band's text lines up with the
   "Mon" column head under it. */
.cal > .band { grid-column: 1 / -1; margin: 0; padding: 14px 24px; border-radius: 0; }
.today { padding: 4px 0; color: var(--ink-2); font-size: var(--fs-14); }
.stampband .today { margin-left: 2px; }
/* B3: the band is child 1 now (A26.4), which shifted every :nth-child
   count by one -- :not(.band) restates the count from the dow row's own
   first cell rather than the band's position. */
.cal > :nth-child(7n+1):not(.band) { border-right: 0; }
/* A46.14: the grid ends on its cells, so the last row is the last seven CELLS */
.cal > .cell:nth-last-child(-n+7 of .cell) { border-bottom: 0; }
.cal-dow { padding: 6px 8px; font-size: var(--fs-12); color: var(--ink-3); border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.cell { min-height: 214px; padding: 8px 10px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); font-size: var(--fs-14); }
.cell--pad { background: var(--tint); }
.cell .dn { display: flex; align-items: baseline; justify-content: space-between; font-variant-numeric: tabular-nums; color: var(--ink-3); margin-bottom: 4px; }
.cell .dn .dc { font-size: var(--fs-12); font-weight: 400; color: var(--ink-3); }
/* A46.3: the peak edge, an inset shadow so the cell box keeps its geometry; redundant with the figure's ink */
.cell--peak-moderate { box-shadow: inset 0 3px 0 color-mix(in srgb, var(--moderate) 55%, transparent); }
.cell--peak-high { box-shadow: inset 0 3px 0 var(--high); }
.cell--peak-extreme { box-shadow: inset 0 3px 0 var(--extreme); }
.cell .dn small { display: none; }
.cell--today .dn { color: var(--ink); font-weight: 600; }
.cell a { display: flex; gap: 6px; line-height: 1.35; padding: 1px 0; }
.cell a span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cell a .hype { margin-left: auto; font-size: var(--fs-13); flex: none; }
/* A46.10: a showcase row leads with the header's Showcases glyph, so a broadcast never reads as a game */
.cell a.ent--show { align-items: center; color: var(--ink-2); }
.cell a.ent--show .icon { width: 14px; height: 14px; flex: none; color: var(--ink-3); }
.cell .others { color: var(--ink-3); }
/* A46.1: a headliner row, in place -- cover, name clamped to two lines, figure */
.cell a.ent--head { display: grid; grid-template-columns: 30px minmax(0,1fr) auto; gap: 8px; align-items: center; height: 48px; padding: 4px; margin: 0 -4px; border-radius: 5px; }
.cell .ent--head .cover { width: 30px; height: 40px; }
.cell .ent--head .nm { font-size: var(--fs-13); font-weight: 600; line-height: 1.2; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; overflow: hidden; }
.cell a.ent--head .hype { font-size: var(--fs-15); margin-left: 0; }
/* A46.11: the name box clips at two lines, so a:hover's 3px offset put the second line's underline outside it; 2px stays inside the line box */
.cell a.ent--head:hover { text-underline-offset: 2px; }
/* A46.12: a week that ended before the current one steps back a little, so the current week leads */
.cell--past > * { opacity: .6; }
/* A46.7: the legend, three keys in their fills, then one sentence */
.cal-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 12px; font-size: var(--fs-12); color: var(--ink-2); }
.cal-legend .k { display: inline-block; width: 10px; height: 10px; border-radius: 2px; vertical-align: -1px; margin-right: 6px; }
.cal-legend .k--extreme { background: var(--extreme); } .cal-legend .k--high { background: var(--high); } .cal-legend .k--moderate { background: var(--moderate); }

/* A47.4-A47.8: the horizon. The key, the year note, the chart (a fixed
   viewBox scrolled sideways inside .hz-scroll, never the page) and the
   lineup. Every drawn shape names its own fill or stroke from a band token
   so it reads in both themes. */
.hz-key { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: center; margin: 0 0 6px; font-size: var(--fs-12); color: var(--ink-2); }
.hz-key > span { display: inline-flex; align-items: center; gap: 6px; }
.hz-key .k { display: inline-block; flex: none; }
.hz-key .k--dot { width: 9px; height: 9px; border-radius: 50%; background: var(--high); }
.hz-key .k--win { width: 22px; height: 4px; border-radius: 2px; background: var(--high); opacity: .6; }
.hz-key .k--q { width: 22px; height: 0; border-top: 3px dashed var(--high); opacity: .45; }
.hz-yearnote, .hz-qnote { margin: 0 0 6px; font-size: var(--fs-13); color: var(--ink-2); }
.hz-yearnote a, .hz-qnote a { text-decoration: underline; text-underline-offset: 3px; }
.hz-scroll { overflow-x: auto; }
.hz { display: block; width: 100%; min-width: 1100px; height: auto; font-family: var(--font); }
.hz-xband { fill: color-mix(in srgb, var(--extreme) 7%, transparent); stroke: none; }
.hz-grid { stroke: var(--line); stroke-width: 1; fill: none; }
.hz-grid--band { stroke: var(--edge); stroke-dasharray: 3 3; }
.hz-ytick { fill: var(--ink-3); font-size: var(--fs-12); }
.hz-ytick--band { fill: var(--ink-2); }
.hz-mline { stroke: var(--line); stroke-width: 1; fill: none; }
.hz-mlab { fill: var(--ink-2); font-size: var(--fs-12); font-weight: 600; }
.hz-today { stroke: var(--ink); stroke-width: 1.5; fill: none; }
.hz-todaylab { fill: var(--ink); font-size: var(--fs-12); font-weight: 600; }
.hz-dot { stroke: var(--bg); stroke-width: 1.5; }
.hz-f--high { fill: var(--high); } .hz-f--extreme { fill: var(--extreme); }
.hz-win { stroke-width: 4; stroke-linecap: round; opacity: .5; fill: none; }
.hz-win--quarter { stroke-width: 3; stroke-dasharray: 5 4; stroke-linecap: butt; opacity: .38; }
.hz-s--high { stroke: var(--high); } .hz-s--extreme { stroke: var(--extreme); }
.hz-lab { font-size: var(--fs-12); fill: var(--ink); font-weight: 500; paint-order: stroke; stroke: var(--bg); stroke-width: 3px; stroke-linejoin: round; }
.hz-lab--extreme { font-weight: 650; }
/* A47.6 review finding 1: a callout's 1px leader, from the dot's edge to its label's left end; never an obstacle */
.hz-lead { stroke: var(--ink-3); stroke-width: 1; fill: none; }
.lineup { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(160px, 1fr); margin-top: 16px; padding: 0; overflow-x: auto; }
.lu-col { display: flex; flex-direction: column; min-width: 0; padding: 14px 14px 12px; }
.lu-col + .lu-col { border-left: 1px solid var(--line); }
.lu-h { display: flex; flex-direction: column; margin-bottom: 8px; }
.lu-h b { font-size: var(--fs-16); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lu-h .muted { font-size: var(--fs-12); }
.lineup li { display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; gap: 6px; align-items: baseline; height: 26px; font-size: var(--fs-13); }
.lu-d { color: var(--ink-3); font-variant-numeric: tabular-nums; text-align: right; font-size: var(--fs-12); }
.lu-n { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lu-n:hover { text-decoration: underline; text-underline-offset: 3px; }
.lu-extreme .lu-n { font-weight: 650; }
.lu-v .lu-n { color: var(--ink-2); font-style: italic; }
.lineup .lu-more, .lineup .lu-none { display: block; line-height: 26px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-13); color: var(--ink-3); }
.lu-all { margin-top: auto; padding-top: 8px; font-size: var(--fs-12); color: var(--ink-2); }
.lu-all:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* reception */
.pair { display: grid; grid-template-columns: 36px 36px minmax(0,1fr) 56px 56px 128px; gap: 12px; align-items: center; height: 56px; border-bottom: 1px solid var(--line); }
.pairs-head { display: grid; grid-template-columns: 36px 36px minmax(0,1fr) 56px 56px 128px; gap: 12px; font-size: var(--fs-12); color: var(--ink-3); padding-bottom: 6px; border-bottom: 1px solid var(--line); }
.pair .hype, .pair .crit { text-align: right; font-size: var(--fs-18); font-variant-numeric: tabular-nums; }
.pairs-head span:nth-child(4), .pairs-head span:nth-child(5) { text-align: right; }
.pair .crit { font-weight: 600; }
.pair .v { font-size: var(--fs-14); color: var(--ink-2); padding-left: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A67.4: the phone-only words of a pair row -- the lower figure's label, the tier word at the head of the meta, the key over the trailing column. Markup, never CSS content; hidden here, shown by the phone block. */
.lbl, .tier, .pairs-key { display: none; }
.lists { display: grid; gap: 40px; }

/* A32: posters -- the browse and the game page's related panels draw a game as
   a 3:4 cover stood up over a fixed text block; one height per list at each
   width, the art by the column and the text by the rows (poster_cards_test).
   The count falls out of a minimum column width (auto-fill), never a fixed
   number: the sheet's one breakpoint is 640, and a fixed five drew 75px
   posters at 768 (review, 2026-09-20). auto-fill keeps its empty tracks, so a
   panel of one poster keeps the column width. The related panels are the
   exception: one row of RelatedGames::CAP tracks that share the width and
   scroll sideways once they reach their floor, never wrapping (owner,
   2026-09-30). */
.posters { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--min, 170px), 1fr)); gap: 24px 16px; }
.panel > .posters { margin-top: 18px; }
.section > .posters { grid-template-columns: repeat(6, minmax(150px, 1fr)); overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 6px; }
.poster { display: grid; grid-template-rows: auto 24px 20px 20px; min-width: 0; position: relative; }
.section > .posters > .poster { grid-template-rows: auto 24px 20px; scroll-snap-align: start; }
/* A46.13: the month page's port and Early Access lists -- one row of any count,
   never wrapping, scrolling sideways. Same rule weight as `.section > .posters`
   and later, so it wins; the phone block's flex row (42%) replaces it. */
/* A46.15: the row's tracks are sized so seven whole cards and 0.4 of an eighth fit
   (100% less the six 16px gaps, over 7.4) -- an overflowing row always ends mid-card,
   which is the scroll hint; 140px floors it on narrow screens. A short row keeps the
   same explicit card width, it is never stretched. */
.section > .posters.posters--row { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: max(140px, calc((100% - 7 * 16px) / 7.4)); }
/* A46.15/A46.16: a card names its stage on the cover's top-left corner (the cover is the poster's first row; .poster is the positioning parent) */
.poster-tag { position: absolute; top: 6px; left: 6px; max-width: calc(100% - 12px); padding: 2px 6px; border-radius: 4px; font-size: var(--fs-12); font-weight: 600; line-height: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--bg); background: color-mix(in srgb, var(--ink) 78%, transparent); pointer-events: none; }
.poster-link { display: block; min-width: 0; }
.poster-link:hover { text-decoration: none; }
.poster-art { display: block; width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: 6px; background: var(--tint); margin-bottom: 10px; }
.poster-art--none { background: var(--line-2); display: grid; place-items: center; color: var(--ink-3); font-size: var(--fs-28); font-weight: 600; }
.poster-name { display: block; min-width: 0; line-height: 24px; font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.poster-line { display: flex; align-items: baseline; gap: 10px; min-width: 0; line-height: 20px; }
.poster-line .poster-meta { flex: 1; }
.poster-line .hype { font-size: var(--fs-18); line-height: 20px; }
.poster-meta { display: block; color: var(--ink-2); font-size: var(--fs-13); line-height: 20px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* A72 (docs/design/rebuild-8/00-contract.md A72.2/A72.3/A72.5/A72.8, transcribed from generator/release-dates/build.rb's PROPOSED sheet): the Release dates section -- one fixed 44px line per date, a line whose date moved opens to 56px change rows (72px on phones), each carrying a move track on its second line (A72.3a, the map of A72.4 being retired). */
.rel-note { margin: 10px 0 0; font-size: var(--fs-12); color: var(--ink-3); }
.rel-list, .rel-moves { list-style: none; margin: 0; padding: 0; }
.rel-list > li { border-bottom: 1px solid var(--line-2); }
.rel-row { display: grid; grid-template-columns: 184px minmax(0,1fr) 96px 150px; gap: 12px; height: 44px; align-items: center; font-size: var(--fs-14); }
summary.rel-row { cursor: pointer; list-style: none; }
summary.rel-row::-webkit-details-marker { display: none; }
summary.rel-row:hover { background: var(--tint); }
.rel-date { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.rel-what { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rel-what b { font-weight: 600; margin-right: 8px; }
.rel-pf { color: var(--ink-2); }
.rel-state { color: var(--ink-3); font-size: var(--fs-13); }
.rel-state--due { color: var(--ink); }
.rel-moved { grid-column: 4; justify-self: end; display: inline-flex; gap: 4px; align-items: center; font-size: var(--fs-13); color: var(--ink-2); text-decoration: underline; text-decoration-color: var(--edge); text-underline-offset: 3px; }
.rel-chev { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.5; }
.rel-more[open] .rel-chev { transform: rotate(180deg); }
.rel-moves { margin: 0 0 10px 196px; border-left: 2px solid var(--line); }
.rel-moves li { display: grid; grid-template-columns: 92px minmax(0,1fr) 150px; grid-template-rows: 22px 22px; column-gap: 12px; row-gap: 0; height: 56px; align-content: center; align-items: center; padding-left: 12px; font-size: var(--fs-13); }
.rel-moves .rel-d { grid-row: 1; grid-column: 1; }
.rel-moves .rel-c { grid-row: 1; grid-column: 2; }
.rel-moves .rel-m { grid-row: 1; grid-column: 3; }
.rel-moves .rel-track { grid-row: 2; grid-column: 2; }
.rel-d { color: var(--ink-3); font-variant-numeric: tabular-nums; font-size: var(--fs-13); white-space: nowrap; }
.rel-c { font-variant-numeric: tabular-nums; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rel-m { justify-self: start; display: inline-flex; gap: 4px; align-items: center; white-space: nowrap; font-size: var(--fs-13); color: var(--ink-2); }
.rel-g { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.rel-m--down .rel-g { color: var(--down); }
.rel-m--up .rel-g { color: var(--up); }
.rel-track { display: block; min-width: 0; line-height: 0; }
.rel-track svg { display: block; max-width: 100%; height: auto; }
.rel-track .ax { stroke: var(--line); }
.rel-track .was { fill: var(--bg); stroke: var(--ink-3); stroke-width: 1.5; }
.rel-track .was-band { fill: none; stroke: var(--ink-3); stroke-dasharray: 2 2; }
.rel-track .now { fill: var(--ink); }
.rel-track .now-band { fill: var(--line); stroke: var(--ink); }
.rel-track .rel-mv { stroke: var(--ink-2); stroke-width: 1.5; }
.rel-track .rel-hd { fill: var(--ink-2); }


@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}

@media (max-width: 640px) {
  /* A67.1: the header is one fixed row -- brand, then .tools (search, settings, the nav menu). The strip is hidden and its links live in the menu's panel, which spans .site (the containing block; the details stays static) under the row. */
  .site { padding: 0 16px; gap: 16px; height: 60px; position: relative; }
  .site > nav { display: none; }
  .nav-menu { display: block; }
  .nav-menu > summary { padding: 12px; margin: -12px; }
  .nav-menu-panel { position: absolute; left: 0; right: 0; top: 100%; z-index: 20; background: var(--bg); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); box-shadow: 0 14px 28px rgba(0,0,0,.10); padding: 4px 0; }
  .site .nav-menu-panel a, .tab-menu-panel a { display: flex; align-items: center; gap: 6px; height: 48px; padding: 0 16px; border: 0; color: var(--ink-2); font-size: var(--fs-16); font-weight: 400; white-space: nowrap; }
  .site .nav-menu-panel a[aria-current], .tab-menu-panel a[aria-current] { color: var(--ink); font-weight: 600; box-shadow: inset 3px 0 0 var(--ink); }
  .tab-menu-panel a:hover { text-decoration: none; color: var(--ink); }
  /* A67.2: the chart kinds and the calendar views are a menu, not a strip; the panel sits under its own summary and bleeds the page's 16px side padding to the screen edges */
  .tabs--menu { display: none; }
  .tab-menu { display: block; position: relative; margin: 20px 0 16px; border-bottom: 1px solid var(--line); }
  .tab-menu > summary { gap: 6px; padding: 0 0 12px; color: var(--ink); font-size: var(--fs-18); font-weight: 600; }
  .tab-menu .chev { width: 14px; height: 14px; color: var(--ink-2); flex: none; }
  .tab-menu[open] .chev { transform: rotate(180deg); }
  .tab-menu-panel { position: absolute; left: -16px; right: -16px; top: 100%; z-index: 20; background: var(--bg); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); box-shadow: 0 14px 28px rgba(0,0,0,.10); padding: 4px 0; }
  .page { padding: 20px 16px 48px; }
  .panel, .section, .verdict-strip, .cal, .lists > *, .article { margin-left: -16px; margin-right: -16px; padding: 16px; border-radius: 0; border-left: 0; border-right: 0; box-shadow: none; }
  .section { margin-top: 16px; }
  .lineup { grid-auto-flow: row; grid-auto-columns: auto; grid-template-columns: 1fr; padding: 0; }
  .lu-col + .lu-col { border-left: 0; border-top: 1px solid var(--line); }
  .tabs + .panel, .tab-menu + .panel, .tabs + .cal, .tab-menu + .cal, .muted + .panel, .verdict-strip + .panel, .lead-note + .panel, .lead-note + .article { margin-top: 16px; }
  /* A67.9: the first sentence stays, the rest folds under Read more */
  .lead-full { display: none; }
  .lead-first { display: block; }
  .lead-more { display: block; margin-top: 6px; }
  .lead-more > summary { color: var(--ink); cursor: pointer; font-size: var(--fs-15); }
  .lead-more > .lead-note { margin-top: 6px; }
  .lead-more + .tabs { margin-top: 16px; }
  .lead { font-size: var(--fs-28); }
  .row { grid-template-columns: 34px 36px minmax(0,1fr) 96px 48px; height: 64px; gap: 10px; }
  .row .cover { width: 36px; height: 48px; }
  /* A39/A40: a phone track has no room for two slots, so the pair stacks and centres there, the arrow still hugging its number */
  .row-standing { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; }
  .row-standing .row-rank { text-align: center; }
  .row .move { font-size: var(--fs-13); }
  .row-standing .move { display: inline-flex; gap: 2px; }
  .row-standing .move > .icon { width: 11px; height: 11px; }
  .row-standing .move--new > span { border: 0; padding: 0; text-transform: none; font-weight: 400; color: var(--ink-3); }
  .row-hype { font-size: var(--fs-18); }
  /* A76.6: the Tile -- every `charts/_entry` row on a phone is lead, cover, a two-line name, and a 64px tile holding the figure over its own trace. The lead is 40px (the stacked "new" chip of es/it fits); the desktop Move and dated variants outrank the base selector (a media query adds no specificity, A43.3) so both are restated here, with their `.rows-head` twins. */
  .rows > .row:has(> .row-standing) { grid-template-columns: 40px 36px minmax(0,1fr) 64px; grid-template-rows: 1fr 1fr; column-gap: 10px; row-gap: 3px; height: 72px; }
  .rows > .row:has(> .row-standing > .move), .rows-head:has(> .rows-head-standing > span + span) { grid-template-columns: 40px 36px minmax(0,1fr) 64px; }
  /* A76.6: the dated lead is right-aligned in the 84px track the build measured (owner, 2026-11-04: the short month); a window lead keeps its top-level 12px (A76.4) */
  .rows > .row:has(> .row-standing--date), .rows-head:has(> .rows-head-standing--date) { grid-template-columns: 84px 36px minmax(0,1fr) 64px; }
  .row-standing--date { display: block; text-align: right; }
  .date-full { display: none; }
  .date-short { display: inline; }
  .row:has(> .row-spark) > .row-standing { grid-column: 1; grid-row: 1 / span 2; }
  .row:has(> .row-spark) > .cover { grid-column: 2; grid-row: 1 / span 2; }
  .row:has(> .row-spark) > .row-name { grid-column: 3; grid-row: 1 / span 2; }
  .row:has(> .row-spark) > .row-hype { grid-column: 4; grid-row: 1; align-self: end; font-size: var(--fs-20); line-height: 1.05; }
  .row:has(> .row-spark) > .row-spark { grid-column: 4; grid-row: 2; align-self: start; justify-self: end; }
  .row:has(> .row-spark) > .row-name a { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; line-height: 1.2; overflow-wrap: anywhere; }
  .row:has(> .row-spark) > .row-name small { margin-top: 2px; }
  /* A76.6: the tile's trace, 64x18 under the figure, unlabelled; a phone shows no compact range, no trend and no range, so the rank's are the only arrows on the row */
  .row-spark .mini { width: 64px; height: 18px; margin: 0; overflow: visible; }
  .trace-range, .row-trend, .row-range, .rows-head-trend, .rows-head-range { display: none; }
  .row-spark polyline { stroke-width: 1.25px; }
  .row-spark .mini-ref { stroke-dasharray: 1 2; }
  .row-spark .mini-ring { stroke-width: 7px; }
  .row-spark .mini-tip { stroke-width: 5px; }
  /* A76.7: a figure that is not hype gets no trace under it -- an awaited row's series cell hides its svg and shows the game's hype in reviewed's cell shape (a word and a banded figure); desktop hides the aside */
  .row-spark--series .mini { display: none; }
  .row-aside-hype { display: flex; align-items: center; justify-content: flex-end; gap: 4px; color: var(--ink-3); font-size: var(--fs-12); white-space: nowrap; }
  .row-aside-hype .hype { font-size: var(--fs-13); }
  /* the launch hype's phone cell is a word and a figure under the critic score; the 64px trace has no room beside them */
  .launch-hype { gap: 4px; }
  .launch-hype .mini { display: none; }
  .launch-hype-word { display: inline; color: var(--ink-3); font-size: var(--fs-12); }
  .launch-hype .hype { font-size: var(--fs-13); min-width: 0; }
  .row-spark:not(:has(svg)) { display: none; }
  .row > .row-spark:not(:has(svg)) + .row-hype { grid-row: 1 / span 2; align-self: center; }
  /* B28(b): a page whose launch-hype column speaks keeps Critics on line one for every row, so a row without a frozen launch hype shows its dash cell ("Hype —", the word inside it) under the figure instead of hiding it and centring the figure alone. Overrides the two rules above for exactly the rows holding a .launch-hype (a silent page has none and keeps today's hide and centre); each selector out-specifies the rule it overrides, so source order is not what decides it. */
  .row-spark:has(.launch-hype) { display: block; }
  .row > .row-spark:has(.launch-hype) + .row-hype { grid-row: 1; align-self: end; }
  .row-platforms { display: none; }
  /* launch-guess P4: at phone width the trace's fixed-size scale labels cover the 8-in-10 bracket, so it leaves; the band and the readout still carry the range. */
  .trace .trace-bracket { display: none; }
  /* A67.5: search results have no rank and no trace, so their two empty tracks leave and the name takes them -- cover, name, figure at a fixed 64px. Hidden by class, never :empty, so a coverless game's span.cover.cover--none keeps its track. */
  .rows--search > .row { grid-template-columns: 36px minmax(0,1fr) 48px; height: 64px; }
  .rows--search > .row > .row-rank { display: none; }
  .rows--search > .row > .row-blank { display: none; }
  .rows--search > .row .row-name a { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; overflow: hidden; line-height: 1.2; overflow-wrap: anywhere; }
  .rows--search > .row .row-name small { margin-top: 2px; }
  .rows-head { display: none; }
  /* A33.9: one column, explicit placement throughout -- title, cover, plot,
     readout, change list -- and the readout becomes a borderless row under the
     axis (A20.6's known stack gap: the trace itself still scales uniformly
     with its width and stays unreadable here). */
  .trace-hero { grid-template-columns: 1fr; }
  /* the lead's cover sits beside the title, as the game page's does (A67.8): name and date in the second column, centred on a 64px cover, the plot and readout spanning both columns under them */
  .trace-hero--lead { grid-template-columns: 64px minmax(0,1fr); column-gap: 16px; }
  .trace-hero-title { grid-column: 1; grid-row: 1; }
  .trace-hero--lead .cover { grid-column: 1; grid-row: 1; width: 64px; height: auto; margin-bottom: 14px; }
  .trace-plot { grid-column: 1; grid-row: 3; }
  /* A media query adds no specificity: the desktop `.trace-hero--lead .trace-plot`
     (0,2,0) outranks the bare `.trace-plot` above, so the lead's plot needs its
     own phone rule or it is placed in a column the one-column grid lacks -- and
     its desktop margin-left must go with it. */
  .trace-hero--lead .trace-plot { grid-column: 1 / -1; margin-left: 0; }
  .trace-hero--lead .trace-hero-title { grid-column: 2; align-self: center; margin-bottom: 14px; }
  .trace-hero--lead .trace-readout { grid-column: 1 / -1; }
  .trace-readout { grid-column: 1; grid-row: 4; border-left: 0; padding-left: 0; flex-direction: row; align-items: baseline; gap: 10px; flex-wrap: wrap; }
  .trace-readout .facts { display: none; }
  /* launch-guess P6: the guess's range stays, one inline row under the figure. Its selector outranks the bare facts rule above, whose display it overrides. */
  .trace-readout .facts.facts--guess { display: flex; flex-wrap: wrap; flex-basis: 100%; gap: 6px; margin: 0; padding: 0; border: 0; }
  .trace-readout .facts--guess b { text-align: left; }
  /* launch-guess V7: the period note keeps a line of its own under the range. */
  .trace-readout .facts-note { flex-basis: 100%; margin-top: 0; }
  .axis-split { display: none; }
  .trace-readout .word { margin-top: 0; }
  .trace-hero .changes { grid-column: 1; grid-row: 5; }
  .trace-hero .why-more { grid-column: 1; grid-row: 6; }
  .trace-hero--lead .trace-hero-title .muted { display: block; }
  .trace-hero--lead .trace-hero-title .sep { display: none; }
  .changes-head { display: none; }
  .changes li { grid-template-columns: 18px minmax(0,1fr) 76px; grid-template-rows: auto auto auto; height: 76px; gap: 0 10px; align-content: center; }
  .changes .n { grid-row: 1 / 4; align-self: start; padding-top: 2px; font-size: var(--fs-13); }
  .changes .d { grid-column: 2; grid-row: 1; font-size: var(--fs-13); }
  .changes .c { grid-column: 2; grid-row: 2; }
  .changes .c b { font-size: var(--fs-14); }
  .changes .c small { display: none; }
  .changes .x { grid-column: 2; grid-row: 3; font-size: var(--fs-13); }
  .changes .m, .changes .m--none { grid-column: 3; grid-row: 1 / 4; }
  .changes .m .q { display: block; }
  .seat-list { grid-template-columns: 1fr; }
  .seat { grid-template-columns: minmax(0,1fr) 64px 64px; }
  .film { grid-auto-columns: 150px; margin-right: -16px; padding-right: 16px; }
  .stills { grid-template-columns: repeat(2, minmax(0,1fr)); }
  /* A76.4: a rail group's head is drawn nowhere on a phone, so its label keeps the one rule and the list draws none above its first row */
  .g-label:has(+ .rows-head) { border-bottom: 1px solid var(--line); padding-bottom: 8px; }
  .g > .rows { border-top: 0; }
  .feed li { grid-template-columns: 30px minmax(0,1fr) 36px; gap: 10px; height: 76px; }
  .feed .cover { width: 30px; height: 40px; }
  .feed .s { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal; overflow: hidden; font-size: var(--fs-14); }
  .feed .t small { font-size: var(--fs-13); }
  .feed .hype { font-size: var(--fs-15); }
  .game-head { grid-template-columns: 64px minmax(0,1fr); gap: 0 16px; align-items: center; }
  .game-head img { width: 64px; height: auto; }
  .game-head h1 { font-size: var(--fs-28); }
  /* A67.8: the text column's wrapper dissolves so the status line, the summary and the links become grid items of their own and span the header's full width; the cover keeps its 64px beside the h1 and the meta line (the wrapper is the markup's last child -- a coverless header's first child is the placeholder) */
  .game-head > div:last-child { display: contents; }
  .game-head img { grid-column: 1; grid-row: 1 / span 2; }
  .game-head h1 { grid-column: 2; grid-row: 1; align-self: end; }
  .game-meta { grid-column: 2; grid-row: 2; align-self: start; margin-top: 4px; font-size: var(--fs-14); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .game-head .status-line, .game-head .about-text, .game-head .links { grid-column: 1 / -1; }
  .step { grid-template-columns: 20px minmax(0,1fr); column-gap: 10px; }
  .step::before { left: 9.5px; }
  .step-node .node { width: 16px; height: 16px; }
  .step-row { grid-template-columns: minmax(0,1fr) 120px; grid-template-rows: auto auto; height: 76px; gap: 2px 12px; }
  .step-when { grid-column: 1; grid-row: 2; font-size: var(--fs-13); white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3; }
  .step-row .mini { display: none; }
  .step-row .fig { grid-column: 2; grid-row: 1 / 3; font-size: var(--fs-18); }
  .step-row .fig small { white-space: normal; line-height: 1.2; font-size: var(--fs-13); }
  .sub-row { grid-template-columns: 94px minmax(0,1fr) 76px; gap: 8px; font-size: var(--fs-14); }
  .sub-name small { display: none; }
  .m small { font-size: var(--fs-13); }
  .verdict-strip { grid-template-columns: repeat(2, auto); gap: 20px; }
  .cal { display: block; padding: 0 16px; }
  .cell:last-child { border-bottom: 0; }
  .cal-dow { display: none; }
  .cell { min-height: 0; border: 0; border-bottom: 1px solid var(--line); padding: 10px 0; display: grid; grid-template-columns: 52px minmax(0,1fr); }
  .cell > * { grid-column: 2; }
  .cell > .dn { grid-column: 1; grid-row: 1 / span 8; }
  .cell--pad, .cell--empty { display: none; }
  .cell .dn { display: block; margin: 0; font-weight: 600; color: var(--ink); }
  .cell a.ent--head { margin: 0; }
  .cell .dn .dc { display: block; margin: 0; }
  .cell .dn small { display: inline; color: var(--ink-3); font-weight: 400; margin-left: 4px; }
  /* A67.4: a pair row on a phone is A59's trailing stack -- the lead figure over a labelled lower one, the tier word heading the meta line, the name on two lines, a fixed 72px. /reception leads with .crit; ol.pairs--attention leads with .hype. */
  .pair { grid-template-columns: 24px 36px minmax(0,1fr) 80px; grid-template-rows: 1fr 1fr; column-gap: 10px; row-gap: 2px; height: 72px; }
  .pair > .row-rank { grid-column: 1; grid-row: 1 / span 2; text-align: center; }
  .pair > .cover { grid-column: 2; grid-row: 1 / span 2; }
  .pair > .row-name { grid-column: 3; grid-row: 1 / span 2; }
  .pair > .crit { grid-column: 4; grid-row: 1; align-self: end; font-size: var(--fs-18); line-height: 1.1; }
  .pair > .hype { grid-column: 4; grid-row: 2; align-self: start; font-size: var(--fs-13); line-height: 1.3; white-space: nowrap; }
  .pairs--attention .pair > .hype { grid-row: 1; align-self: end; font-size: var(--fs-18); line-height: 1.1; }
  .pairs--attention .pair > .crit { grid-row: 2; align-self: start; font-size: var(--fs-13); font-weight: 400; line-height: 1.3; white-space: nowrap; }
  .pair .row-name a { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; line-height: 1.2; overflow-wrap: anywhere; }
  .pair .row-name small { margin-top: 2px; }
  .pair .v { display: none; }
  .pair .lbl { display: inline; color: var(--ink-3); font-weight: 400; }
  .pair .tier { display: inline; color: var(--ink); font-weight: 550; }
  .pairs-key { display: block; text-align: right; font-size: var(--fs-13); color: var(--ink-3); padding-bottom: 6px; border-bottom: 1px solid var(--line); }
  .pairs-head { display: none; }
  /* A57.5: the changelog row is a fixed 64px grid on phones -- day over month, the headline on two lines; count, version and the long date move into the opened body */
  .cl-latest { padding: 20px 16px 22px; }
  .cl-title { font-size: var(--fs-20); }
  .cl-latest + .cl-index { margin-top: 16px; }
  .cl-index { padding: 16px 0 4px; }
  .cl-index > h2 { padding: 0 16px; }
  .cl-month { padding: 16px 16px 6px; }
  .cl-row > summary { grid-template-columns: 36px minmax(0,1fr) 12px; gap: 12px; height: 64px; padding: 0 16px; }
  .cl-row[open] > summary { min-height: 64px; padding-top: 8px; padding-bottom: 8px; }
  .cl-date { display: grid; justify-items: center; line-height: 1.1; font-size: var(--fs-13); color: var(--ink-3); }
  .cl-stack { display: grid; justify-items: center; }
  .cl-stack b { font-size: var(--fs-18); font-weight: 600; color: var(--ink-2); }
  .cl-day-month, .cl-count, .cl-row > summary .cl-version { display: none; }
  .cl-headline { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.35; font-size: var(--fs-15); }
  .cl-body { padding: 4px 16px 20px; }
  .cl-meta { display: block; }
  /* A45.1 retired the rail's whole phone block (its one-column collapse,
     the Filters fold, and the trace column's own phone-width restatement)
     along with the rail itself -- /calendar was its last emitter. */
  .band { margin: -16px -16px 14px; padding: 12px 16px; }
  .cal > .band { padding: 12px 0; }
  .horizon > .band > .stamp { padding: 7px 0; }
  /* A45.6/A45.9/A67.3 "phones without JavaScript": below 640px the bar
     applies in a batch through the phone sheet. A ready bar (the capability
     flag filter_sheet_controller.js sets on connect) hides its own menus
     and toggle, opens with one Filters button and shows one tag per applied
     cut, wrapping onto as many lines as they need (owner: wrap rather than
     scroll; this retires A45.9's one-row scroll). Clear and the calendar's
     own side link leave the bar. Without the flag (no JS) the bar is the
     desktop wrap, its menus open unclipped, and neither button nor tags
     display.

     A45.9 second review considered replacing the flag with a nested
     `@media (scripting: enabled)`. Reverted: nesting an `@media` inside this
     block breaks RankStandingTest#rules_for's phone/desktop split, which
     then misclassifies every other phone-only rule in this same 640px
     block. The flag stays. */
  .fbar[data-sheet="ready"] > .fmenu, .fbar[data-sheet="ready"] > .ftoggle { display: none; }
  .fbar[data-sheet="ready"] > .fopen { display: inline-flex; }
  .fbar[data-sheet="ready"] > .ftag { display: inline-flex; }
  .fbar[data-sheet="ready"] > .fclear, .fbar[data-sheet="ready"] > .fside { display: none; }
  /* A45.9 "what leaves the phone row": only Sort's OWN menu leaves -- its
     direction arrow (`a.dir`, .fsort's other child) stays beside the
     search, so the row keeps a quick reverse even with Sort itself moved
     into the sheet. `.fsort` sits beside `.fbar` in the band, not inside
     it (A45.5), so reaching it needs the containing `.band`. */
  .band:has(> .fbar[data-sheet="ready"]) .fsort > .fmenu { display: none; }
  /* A28: the phone panel pads 16px, so the rows bleed 16px -- the same
     number `.band` restates one line above. */
  .panel .rows, .panel .rows-head { margin-left: -16px; margin-right: -16px; }
  .panel .row, .panel .rows-head { padding-left: 16px; padding-right: 16px; }
  /* A32: two posters across in the browse; the related panels become a
     snapping rail that bleeds the section's 16px padding, the third poster
     peeking so the rail reads as one. The scroll-padding matches the bleed:
     without it the mandatory snap lands the first poster on the scroller's
     edge, scrolling the 16px away on load and the card flush to the screen. */
  .posters { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 12px; }
  .section > .posters { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: 16px; gap: 12px; margin: 0 -16px; padding: 0 16px 6px; scrollbar-width: none; }
  .section > .posters > .poster { flex: 0 0 42%; scroll-snap-align: start; }
  /* A56.2: the showcase rows on a phone -- narrower columns, the games-tracked half of the note yields to the changes after it (when it is the whole note it stays), and the links past the ellipsis leave the tab order */
  /* A67.6: the showcase rows are 68px and the name wraps to two lines; the note under it stays one (its links keep their single line) */
  .sc-list li { grid-template-columns: 52px 48px minmax(0,1fr); gap: 10px; height: 68px; }
  .sc-list .n > a { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; overflow: hidden; line-height: 1.2; overflow-wrap: anywhere; }
  .sc-thumb { width: 48px; height: 27px; }
  .sc-list .sc-g:not(:last-child) { display: none; }
  .sc-list .d { font-size: var(--fs-14); }
  .sc-list .d .tz { display: none; } /* A68.1: 52px holds the time, not its zone */
  .sc-list .n small a { display: none; }
  /* A56.4: the band on a phone -- one show stacks; many become 84px rows, a 112px thumb beside the three lines */
  .scb--one { grid-template-columns: minmax(0,1fr); gap: 12px; }
  .scb-body h3 { font-size: var(--fs-20); }
  .scb-rel { font-size: var(--fs-18); }
  .scb--many, .scb--n2 { grid-template-columns: minmax(0,1fr); gap: 0; border-top: 1px solid var(--line); }
  .scb--many li { grid-template-columns: 112px minmax(0,1fr); grid-template-rows: none; gap: 12px; height: 84px; align-items: center; border-bottom: 1px solid var(--line); }
  .scb--many .scb-img { border-radius: 4px; }
  .scb--many .scb-t { padding-top: 0; }
  .scb--many .scb-flag { top: 4px; left: 4px; padding: 0 5px; font-size: var(--fs-12); }
  /* A56.3: the show page on a phone -- the band edge to edge with no padding, the strip in two columns with
     the start spanning both, the line-up's narrower cover and figure */
  .sct { margin: 16px -16px 0; padding: 0; }
  .sct .playbox { border-radius: 0; }
  .sc-stage .sc-count { padding: 28px 16px 12px; }
  .sc-stage .sc-count b { font-size: var(--fs-24); }
  .sc-strip { display: grid; grid-template-columns: 1fr 1fr; }
  .sc-strip > div { margin: 0; padding: 10px 0; border-right: 0; border-top: 1px solid var(--line); }
  .sc-strip > div:nth-child(-n+2) { border-top: 0; }
  .sc-strip > .sc-wide { grid-column: 1 / -1; }
  .sc-strip > .sc-wide + div { border-top: 1px solid var(--line); }
  .sc-strip dd { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-16); }
  .sc-lineup li { grid-template-columns: 36px minmax(0,1fr) 40px; gap: 12px; }
  .sc-lineup .cover { width: 36px; height: 48px; }
  .sc-lineup .hype { font-size: var(--fs-18); }
  .sc-rise { font-size: var(--fs-18); }
  .sc-lineup li:has(.sc-rise) { grid-template-columns: 36px minmax(0,1fr) 48px; }
  /* A72.2/A72.3: every release row a fixed two-line stack -- date, state word and the change count over the stage word and platforms */
  .rel-row { grid-template-columns: auto minmax(0,1fr) auto; grid-template-rows: 22px 20px; height: 56px; column-gap: 8px; row-gap: 0; align-content: center; }
  .rel-date { grid-row: 1; grid-column: 1; }
  .rel-state { grid-row: 1; grid-column: 2; }
  .rel-what { grid-row: 2; grid-column: 1 / -1; font-size: var(--fs-13); }
  .rel-moved { grid-row: 1; grid-column: 3; }
  .rel-moves { margin-left: 4px; }
  /* A72.3a: a move is a fixed three-line stack on phones -- the change text, the track on its own line (240px or the row's width if narrower), the noticed day and the move word */
  .rel-moves li { grid-template-columns: minmax(0,1fr) 140px; grid-template-rows: 20px 22px 18px; height: 72px; row-gap: 0; align-content: center; }
  .rel-moves .rel-c { grid-row: 1; grid-column: 1 / -1; }
  .rel-moves .rel-track { grid-row: 2; grid-column: 1 / -1; }
  .rel-moves .rel-d { grid-row: 3; grid-column: 1; }
  .rel-moves .rel-m { grid-row: 3; grid-column: 2; }
}
