/* SMHTV viewer — token-driven, RTL-safe (logical properties only). */
/* Display face — Montserrat, self-hosted (no third-party calls), latin subset, ~56KB total.
   SIL OFL — see fonts/OFL.txt. Headlines/section labels only; body stays system-ui. */
@font-face{font-family:"Montserrat";src:url("fonts/montserrat-600.woff2") format("woff2");font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:"Montserrat";src:url("fonts/montserrat-700.woff2") format("woff2");font-weight:700;font-style:normal;font-display:swap}
/* 800 (extrabold) — the display face's heaviest cut, used by 36 headline/label sites
   (.hs-title, .af-name, .dr-name, .ec-h, section labels…). The prior 400 cut was dead
   weight — body text resolves to the 600 cut (the lightest shipped), never Montserrat 400. */
@font-face{font-family:"Montserrat";src:url("fonts/montserrat-800.woff2") format("woff2");font-weight:800;font-style:normal;font-display:swap}
/* Cyrillic (Russian pages): ONE variable file (Google Fonts' cyrillic subset, OFL, 21KB), declared
   once per weight with the SAME descriptors as the Latin cuts above, so each weight is one face
   split by unicode-range (a "600 800" range would form a separate face and knock the Latin 800 cut
   out of matching). Only Cyrillic text downloads it; the browser fetches the file once. */
@font-face{font-family:"Montserrat";src:url("fonts/montserrat-cyrillic-var.woff2") format("woff2");font-weight:600;font-style:normal;font-display:swap;unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:"Montserrat";src:url("fonts/montserrat-cyrillic-var.woff2") format("woff2");font-weight:700;font-style:normal;font-display:swap;unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:"Montserrat";src:url("fonts/montserrat-cyrillic-var.woff2") format("woff2");font-weight:800;font-style:normal;font-display:swap;unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
/* ==========================================================================
   THEME TOKENS — rotterdam2026.com palette (B5, 2026-10-12). Values and sources:
   docs/reference/rotterdam2026-recon/TOKENS.md. LIGHT is the :root default (content
   surfaces); the near-black player set survives under `.theme-dark` (watch/live only).
   rotterdam.css layers the full skin on top; these tokens are the base it starts from.
   Orange #ff6315 is a FILL colour carrying navy ink #000735 (6.51:1; white on it is 2.98:1,
   fails AA). As TEXT on white/cream use --accent-ink #b83b00; orange text is legal only on navy.
   Retired-brand hexes may only appear inside `.theme-dark`.
   ========================================================================== */
:root{
  --bg:#ffffff;
  --bg-raised:#f5f5f5;
  --surface:#ffffff;
  --surface-2:#F0F2F4;
  --border:#e3e6ea;
  --border-card:#d7dbe0;
  --border-btn:#c9ced6;
  --text:#101242;
  --text-muted:#5c6270;
  --text-soft:#3b4151;
  --text-dim:#8a8f9c;
  /* Medal INK on light surfaces. The literal metal tints (#e9c463 gold, #cfd2d6 silver,
     #cd9b6a bronze) are correct as FILLS — .badge-gold and friends put dark text on them and
     pass easily. As TEXT on a white/#f5f5f5 chip they were 1.39-2.47:1, so the medal counts
     (the entire point of the medal table) were close to unreadable. These are the same three
     metals darkened until they pass AA on both chip backgrounds, so a viewer still reads
     "gold / silver / bronze" — the semantics the do-not-redesign rule protects — while the
     numbers are legible. Light metals are kept where the chip is dark (.mp-lead below). */
  --metal-gold-ink:#836200;    /* 5.66:1 on #fff, 5.19:1 on #f5f5f5 */
  --metal-silver-ink:#5c6270;  /* 6.11:1 / 5.61:1 */
  --metal-bronze-ink:#8f5a28;  /* 5.74:1 / 5.26:1 */
  --primary:var(--brand-primary,#101242);
  --accent:var(--brand-accent,#ff6315);
  --on-accent:#000735;  /* navy ink ON orange: 6.51:1 (white on #ff6315 is 2.98:1, fails AA) */
  --accent-ink:#b83b00; /* orange as TEXT on white/cream: 5.73:1 */
  --live:#ff6315;      /* orange — LIVE moments */
  --band:#101242;      /* the rotterdam2026.com navy band surface */
  --support:#ffb08a;
  --nav-active:#ff6315;
  --on-nav:#000735;    /* navy ink on the orange active nav pill */
  --shadow-card:0 2px 12px rgba(16,18,66,.08);
  --glow-cta:0 14px 40px -14px rgba(255,99,21,.42);
  --glow-card:0 18px 44px -18px rgba(16,18,66,.4);
  --font:"Montserrat",system-ui,sans-serif;  /* self-hosted; NOT --brand-font (Inter is not shipped, so inner pages fell back to system-ui while the home used Montserrat) */
  --display:"Montserrat", var(--font);
}
/* CJK pages: Montserrat has no CJK glyphs, so name the system CJK faces before system-ui (which
   picks Japanese forms for Chinese Han characters on some systems). Scoped by page language so
   other languages keep the stack above untouched. */
html:lang(ja){--font:"Montserrat","Hiragino Sans","Yu Gothic","PingFang SC","Noto Sans CJK SC","Microsoft YaHei",system-ui,sans-serif}
html:lang(zh){--font:"Montserrat","PingFang SC","Noto Sans CJK SC","Microsoft YaHei","Hiragino Sans","Yu Gothic",system-ui,sans-serif}
.theme-dark{ /* the current dark set, verbatim — watch/live only */
  --bg:#0a0a0c;
  --bg-raised:#0d0d11;
  --surface:#14141a;
  --surface-2:#12121a;
  --border:#1c1c24;
  --border-card:#24242e;
  --border-btn:#2a2a34;
  --text:#f5f5f3;
  --text-muted:#9a9aa4;
  --text-soft:#c0c0c8;
  --text-dim:#5f5f69;
  --primary:#3438ff;   /* prior --accent-2 (electric blue) — restores live hero-art stripe */
  --accent:#e8ff2d;    /* prior accent (Kinetic yellow) — header wordmark, skip-link */
  --on-accent:#0a0a0c;
  --accent-ink:#e8ff2d; /* same as --accent — the light-side text-accent split is a no-op here */
  --live:#ff2f6d;      /* Kinetic hot-pink, preserved */
  --support:#38B9CC;
  --nav-active:var(--accent);
  --on-nav:#0a0a0c;    /* near-black on the yellow active pill — unchanged dark look */
  --glow-cta:0 14px 40px -14px rgba(232,255,45,.4);
  --glow-card:0 18px 44px -18px rgba(52,56,255,.55);
  --shadow-card:0 18px 44px -18px rgba(0,0,0,.6);
}
*{box-sizing:border-box}
/* Clip horizontal overflow (off-canvas mobile drawer, marquees) without making a scroll
   container — `clip` preserves position:sticky, unlike `hidden`. Kills the mobile sideways
   scroll/jiggle the off-canvas nav was causing on every page. */
html{overflow-x:clip}
body{margin:0;overflow-x:clip;background:var(--bg);color:var(--text);font-family:var(--font);line-height:1.5}
/* Ambient depth — fixed brand-tinted glows + a soft vignette so the dark reads as a
   graded broadcast backdrop, never flat black. Pure CSS (no image dependency): an
   EG-blue wash top-left, a faint lime glow top-right, a base lift from below, and a
   vignette that pulls the corners down for cinematic focus. */
body.theme-dark::before{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(140% 140% at 50% 24%, rgba(8,9,14,.5) 26%, rgba(8,9,14,.92) 100%),
    linear-gradient(180deg, rgba(8,9,14,.66), rgba(8,9,14,.8) 62%, rgba(8,9,14,.9)),
    /* EG-blue unifying wash: pulls the montage's clashing magenta/green toward brand royal-blue */
    linear-gradient(180deg, rgba(27,35,179,.30), rgba(27,35,179,.20)),
    #08090e;
  /* The generated chevron montage that sat under these veils is gone (Alex 18 Oct: no AI images):
     plain brand gradient. */
  filter:saturate(.42)}
/* Fine film grain — kills gradient banding on the dark and adds a premium textured
   depth. One static fixed paint (no animation), GPU-cheap — safe on the player path. */
body.theme-dark::after{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;opacity:.045;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:180px 180px}
/* World Gymnastics LIGHT canvas (fidelity pass 2026-07-16) — the original keeps its content on
   plain white/#F0F2F4 and concentrates ALL colour into deep-indigo BAND sections carrying one
   vivid ribbon (their own wg_news.jpg asset, imported as bg/band-ribbon.webp). The previous
   veiled full-page ribbon field read "washed out / way off" to the client and is gone — one
   less fetch per page, too. */
.site-header,main,.site-footer{position:relative;z-index:1}

/* Scrollbars — thumb only, no track chrome. The default light track reads cheap on a
   dark broadcast theme; here the track is transparent and the bar is a soft floating
   pill (padding-box border insets it). Page + every horizontal scroller (shelves,
   day-nav, filter rows) inherit this. */
html{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.22) transparent}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track,::-webkit-scrollbar-corner{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.2);border-radius:99px;
  border:3px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.34);background-clip:padding-box}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}

/* Visually-hidden utility (screen-reader only) — templates already use it (e.g. the videos
   filter's implicit submit); it was never defined, so those buttons rendered visible. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

.skip-link{position:absolute;inset-block-start:-3rem;inset-inline-start:.75rem;z-index:50;
  background:var(--accent);color:var(--on-accent);padding:.5rem .9rem;border-radius:.4rem;font-weight:700;transition:inset-block-start .15s}
.skip-link:focus{inset-block-start:.75rem}

.site-header{position:sticky;inset-block-start:0;z-index:20;
  /* Header chrome: static near-black wash (var(--bg)). */
  background:color-mix(in srgb,var(--bg) 92%,transparent);backdrop-filter:blur(10px);border-block-end:1px solid var(--border)}
.header-inner{max-width:78rem;margin-inline:auto;display:flex;align-items:center;gap:1.25rem;
  padding-block:.85rem;padding-inline:1.25rem}
.site-header .brand{font-weight:800;font-size:1.15rem;letter-spacing:.02em;line-height:1.05;flex-shrink:0}
.site-header .brand img{height:38px;width:auto}
.event-mark{display:flex;align-items:center;gap:.45rem;color:var(--text-muted);min-width:0;flex-shrink:1}
.event-mark:hover{color:var(--text)}
/* Was var(--border) on the white header — 1.07:1, an invisible separator. --text-muted
   keeps it quiet without erasing it. (.theme-dark has its own rule below.) */
.event-mark .sep{color:var(--text-muted)}
.event-mark .mark-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;font-weight:700}
.event-mark img{height:24px;width:auto}

.nav{display:flex;align-items:center;gap:.2rem;margin-inline-end:auto}
/* Creative nav: links live in pills — a soft pill on hover, a solid lime pill on the
   active section. Distinct, branded, visible at rest (not just on hover). */
.nav a{color:var(--text-muted);font-family:var(--display);font-weight:600;font-size:.82rem;position:relative;padding:.42rem .56rem;border-radius:.55rem;white-space:nowrap;transition:background .15s,color .15s}
.nav a:hover{color:var(--primary);background:color-mix(in srgb,var(--primary) 12%,transparent)}
.nav a.active{color:var(--on-nav);background:var(--nav-active);font-weight:700}
.nav a.active .live-dot{background:var(--on-nav)}
/* Watch/live share this header — restore the dark nav treatment there (light-first base above). */
.theme-dark .nav a{color:rgba(255,255,255,.74)}
.theme-dark .nav a:hover{color:#fff;background:rgba(255,255,255,.10)}
/* …but not over the active pill: `.theme-dark .nav a` ties `.nav a.active` on specificity and
   wins on source order, which repainted the current page's label pale-white on the yellow pill
   (watch/live only — the light pages resolve --on-nav to white on FIG blue and always read). */
.theme-dark .nav a.active{color:var(--on-nav)}
/* The header separator was set to --border, which on dark is all but the header's own colour. */
.theme-dark .event-mark .sep{color:rgba(255,255,255,.28)}
/* Participating-nation flags: rendered flat, like every other flag on the site. The earlier
   "stacked cards" pseudo-element depth cue was unique to the home and read differently from the
   plain flags everywhere else — dropped. Flags are static (a "waving in the wind" ripple was
   trialled and pulled — it needs animated SVG displacement, deferred). The link still lifts +
   scales on hover. */
.reel-flags .flag-link{position:relative;display:inline-flex;
  transition:transform .15s ease}
.reel-flags .flag-link:hover{transform:translateY(-3px) scale(1.18)}
.live-dot{display:inline-block;width:.45rem;height:.45rem;border-radius:50%;background:#e5484d;margin-inline-start:.35rem;vertical-align:middle;animation:livepulse 1.6s ease-in-out infinite}
@keyframes livepulse{0%,100%{opacity:1}50%{opacity:.35}}

.header-actions{display:flex;align-items:center;gap:.75rem;flex-shrink:0}
.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:2.1rem;height:2.1rem;border-radius:50%;color:var(--text-muted);transition:background .15s,color .15s}
.icon-btn:hover{background:var(--surface);color:var(--text)}

.lang-menu{position:relative}
.lang-menu summary{list-style:none;cursor:pointer;color:var(--text-muted);font-size:.8rem;font-weight:700;
  padding:.35rem .55rem;border:1px solid var(--border);border-radius:.45rem;display:flex;align-items:center;gap:.25rem}
.lang-menu summary::-webkit-details-marker{display:none}
.lang-menu summary::after{content:"▾";font-size:.7rem;opacity:.7}
.lang-menu summary:hover{color:var(--text);border-color:var(--text-muted)}
.lang-menu[open] summary{color:var(--text);border-color:var(--accent)}
.lang-list{position:absolute;inset-block-start:calc(100% + .4rem);inset-inline-end:0;min-width:9rem;
  background:var(--surface);border:1px solid var(--border);border-radius:.55rem;padding:.35rem;
  display:flex;flex-direction:column;box-shadow:0 12px 30px rgba(0,0,0,.45);z-index:30}
.lang-list a{padding:.45rem .6rem;border-radius:.35rem;color:var(--text-muted);font-size:.88rem}
.lang-list a:hover{background:var(--bg);color:var(--text)}
.lang-list a.active{color:var(--accent-ink);font-weight:600}

.signin-link{color:var(--text);font-weight:600;font-size:.9rem;white-space:nowrap}
.signin-link:hover{color:var(--accent-ink)}
.account-menu{position:relative}
.account-menu summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;width:2.1rem;height:2.1rem;border-radius:50%;color:var(--text-muted);transition:background .15s,color .15s}
.account-menu summary::-webkit-details-marker{display:none}
.account-menu summary:hover,.account-menu[open] summary{background:var(--surface);color:var(--text)}
.account-list .account-email{padding:.5rem .6rem;font-size:.78rem;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border-block-end:1px solid var(--border);margin-block-end:.2rem;max-inline-size:13rem}
.account-list{position:absolute;inset-inline-end:0;margin-block-start:.5rem;min-width:10rem;background:var(--surface);border:1px solid var(--border);border-radius:.6rem;padding:.4rem;display:flex;flex-direction:column;gap:.2rem;z-index:50;box-shadow:0 10px 30px rgba(0,0,0,.4)}
.account-list a,.account-list button{text-align:start;background:none;border:0;color:var(--text);font:inherit;padding:.5rem .6rem;border-radius:.4rem;cursor:pointer}
.account-list a:hover,.account-list button:hover{background:var(--bg);color:var(--accent-ink)}
/* auth forms (signup / login / settings) */
.auth-form{max-width:26rem;margin-block:1rem 2rem;display:flex;flex-direction:column;gap:.9rem}
.auth-form p{margin:0;display:flex;flex-direction:column;gap:.3rem}
.auth-form label{font-size:.85rem;color:var(--text-muted)}
.auth-form input[type=email],.auth-form input[type=text],.auth-form input[type=password],.auth-form input[type=date],.auth-form textarea{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:.5rem;padding:.55rem .7rem;font:inherit}
.auth-form textarea{min-height:4.5rem;resize:vertical}
.auth-form input:focus-visible,.auth-form textarea:focus-visible{outline:2px solid var(--accent-ink);outline-offset:1px;border-color:var(--accent-ink)}
.auth-form input[type=checkbox]{margin-inline-end:.4rem}
.auth-form .helptext{font-size:.78rem;color:var(--text-muted)}
/* Password Show/Hide toggle (account/forms/_pw_toggle.html + app.js). The input keeps its look;
   the 40x40 button sits inside its right end and the padding keeps typed text out from under it.
   [hidden] wins until app.js reveals the button, so a no-JS visitor sees a plain field. */
.pw-field{position:relative;display:flex;flex-direction:column}
.auth-form .pw-field input{padding-inline-end:2.9rem}
.pw-toggle{position:absolute;inset-inline-end:0;top:50%;transform:translateY(-50%);
  inline-size:40px;block-size:40px;display:inline-flex;align-items:center;justify-content:center;
  padding:0;margin:0;border:0;border-radius:.5rem;background:transparent;color:var(--text-muted);cursor:pointer}
.pw-toggle[hidden]{display:none}
.pw-toggle:hover{color:var(--text)}
.pw-toggle:focus-visible{outline:2px solid var(--accent-ink);outline-offset:-2px;color:var(--text)}
.pw-toggle .pw-eye-off,.pw-toggle[aria-pressed="true"] .pw-eye{display:none}
.pw-toggle[aria-pressed="true"] .pw-eye-off{display:block}
/* #e5484d was 3.91:1 on the white card; #a32500 (7.44:1) is the field-error red. */
.auth-error{color:#a32500;font-weight:600;font-size:.88rem;display:block;text-align:center}
/* Prose paragraphs must NOT inherit the label-over-input flex column from `.auth-form p`,
   or their inline links stack one-per-line (the rushed look). Force normal block flow. */
.auth-form .auth-alt,.auth-form .auth-note{display:block;text-align:center;line-height:1.5;font-size:.85rem;color:var(--text-muted)}
.auth-alt{margin-block-start:.35rem}
.auth-note{margin-block-start:1rem;padding-block-start:1rem;border-block-start:1px solid var(--border)}
.auth-note a,.auth-alt a{color:var(--accent-ink);font-weight:600}

/* Auth screens (login / signup): a centered card so the form reads as intentional. */
.auth-screen{display:flex;justify-content:center;padding-block:clamp(1.5rem,5vh,3.5rem) 4rem}
.auth-card{width:100%;max-width:27rem;background:var(--surface);border:1px solid var(--border);
  border-radius:1rem;padding:2rem 1.75rem 1.75rem;box-shadow:0 24px 60px -32px rgba(0,0,0,.75)}
.auth-title{font-family:var(--display);font-weight:800;letter-spacing:-.01em;line-height:1.05;
  font-size:clamp(1.5rem,3.5vw,2.1rem);text-align:center;margin:0 0 1.4rem}
.auth-card .auth-form{max-width:none;margin:0}
/* Card bg is --surface, so recess the inputs to --bg for contrast. */
.auth-card .auth-form input[type=email],.auth-card .auth-form input[type=text],
.auth-card .auth-form input[type=password],.auth-card .auth-form input[type=date]{background:var(--bg)}
/* Consent checkboxes sit inline beside their label, not stacked under it. */
.auth-card .auth-form p:has(input[type=checkbox]){flex-direction:row;align-items:center;gap:.5rem}
.auth-card .auth-form p:has(input[type=checkbox]) input[type=checkbox]{order:0;margin:0}
.auth-card .auth-form p:has(input[type=checkbox]) label{order:1;margin:0;color:var(--text)}
/* Sign-in is the primary action; "Create an account" is a clear secondary (ghost) button
   below a divider — present but not competing with Sign in. */
.auth-card .auth-form .btn{inline-size:100%;text-align:center}
.auth-secondary{display:block;inline-size:100%;text-align:center;box-sizing:border-box}
.auth-or{display:flex;align-items:center;gap:.75rem;color:var(--text-muted);font-size:.8rem;margin-block:1.1rem .85rem}
.auth-or::before,.auth-or::after{content:"";flex:1;block-size:1px;background:var(--border)}
/* Flash messages (success/info banners above page content) */
.messages{display:flex;flex-direction:column;gap:.5rem;margin-block-end:1.25rem}
.msg{margin:0;padding:.6rem .9rem;border-radius:.5rem;background:var(--surface);border:1px solid var(--border);border-inline-start:3px solid var(--accent);font-size:.9rem;color:var(--text);font-weight:600}
.msg-success{border-inline-start-color:#3fb950}
.msg-warning{border-inline-start-color:#d29922}
.msg-error{border-inline-start-color:#e5484d}
/* Profile — social-handle chips + favourite-sport pills (reuse the chrome's surface/line/accent vocabulary) */
.social-links{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.5rem}
.social-links a{display:inline-block;padding:.4rem .8rem;background:var(--surface);border:1px solid var(--border);border-radius:999px;color:var(--text);font-size:.85rem;font-weight:600;transition:border-color .15s,color .15s}
.social-links a:hover{border-color:var(--accent);color:var(--accent-ink)}
.fave-sports{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.5rem}
.fave-sports li{display:inline-flex;align-items:center;gap:.4rem;padding:.35rem .75rem;background:var(--surface);border:1px solid var(--border);border-radius:999px;font-size:.85rem}
.fave-sports .muted{color:var(--text-muted);font-size:.78rem;font-weight:600}
/* Profile identity hero — gives the fan a face + their fandom at a glance */
.profile-hero{display:flex;align-items:center;gap:1.25rem;margin-block:.5rem 2.25rem}
.monogram{flex-shrink:0;width:4.5rem;height:4.5rem;border-radius:50%;display:grid;place-items:center;font-size:1.9rem;font-weight:800;color:var(--accent-ink);background:var(--surface);border:2px solid var(--accent)}
.profile-id h1{margin:0;font-size:1.9rem;line-height:1.1}
.profile-sub{margin:.35rem 0 0;color:var(--text-muted);font-size:.9rem}
.profile-stats{display:flex;flex-wrap:wrap;gap:1.25rem;margin-block-start:.65rem}
.profile-stats span{font-size:.72rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em}
.profile-stats strong{color:var(--text);font-size:1.05rem;font-weight:800;margin-inline-end:.2rem}
.profile-section{margin-block:1.75rem;max-width:42rem}
.profile-section .rail-h{margin-block:0 .8rem}

.nav-toggle{display:none}
.burger{display:none;flex-direction:column;gap:.28rem;cursor:pointer;padding:.35rem;margin-inline-start:auto}
.burger span{width:1.4rem;height:2px;background:var(--text);border-radius:2px;transition:transform .2s,opacity .2s}

main{max-width:78rem;margin-inline:auto;padding-inline:1.25rem;padding-block:1.5rem}

.hero{padding-block:2.5rem 1.5rem;border-block-end:1px solid var(--border);margin-block-end:1.5rem}
.hero .eyebrow{color:var(--accent-ink);text-transform:uppercase;letter-spacing:.12em;
  font-size:.78rem;margin:0 0 .4rem}
.hero h1{font-size:clamp(1.7rem,4vw,3rem);margin:0;line-height:1.1;overflow-wrap:break-word;text-wrap:balance}
.hero .dates{color:var(--text-muted);margin-block-start:.5rem}

/* marquee hero */
.marquee{position:relative;border-radius:.9rem;overflow:hidden;min-height:clamp(16rem,42vw,26rem);display:flex;align-items:flex-end;margin-block-end:2rem;background-size:cover;background-position:center;
  box-shadow:0 24px 70px -34px rgba(0,0,0,.9), 0 0 90px -26px var(--accent)}
.marquee::after{content:"";position:absolute;inset:0;background:linear-gradient(to top, rgba(8,8,10,.94), rgba(8,8,10,.4) 55%, transparent)}

.rail{margin-block-end:2.25rem}
.rail h2{font-size:1.15rem;margin:0 0 .9rem}
.cards{list-style:none;margin:0;padding:0;display:grid;gap:1rem;
  grid-template-columns:repeat(auto-fill,minmax(15rem,1fr))}
.card{background:linear-gradient(180deg,color-mix(in srgb,var(--surface) 91%,#fff 9%),var(--surface) 60%);
  border:1px solid var(--border);border-radius:.8rem;overflow:hidden;
  box-shadow:0 10px 26px -20px rgba(0,0,0,.85);
  transition:transform .18s ease, border-color .18s ease, box-shadow .18s ease}
.card:hover{transform:translateY(-4px);border-color:color-mix(in srgb,var(--accent) 70%,var(--border));
  box-shadow:0 22px 46px -24px rgba(0,0,0,.95), 0 0 0 1px color-mix(in srgb,var(--accent) 35%,transparent)}
.card-link{display:block}
.poster{position:relative;display:block;aspect-ratio:16/9;background-size:cover;background-position:center}
.poster-img{width:100%;height:100%;object-fit:cover;display:block}
.poster .badge{position:absolute;inset-block-start:.5rem;inset-inline-start:.5rem;z-index:2}
.poster-play{position:absolute;inset:0;margin:auto;width:3rem;height:3rem;border-radius:50%;background:rgba(0,0,0,.5);opacity:0;transition:opacity .15s ease}
.poster-play::before{content:"";position:absolute;inset:0;margin:auto;width:0;height:0;border-style:solid;border-width:.5rem 0 .5rem .85rem;border-color:transparent transparent transparent #fff}
.card:hover .poster-play{opacity:1}
.card h3{margin:.6rem .85rem .2rem;font-size:1rem;line-height:1.25}
.card .meta,.card .time,.card .excerpt{color:var(--text-muted);font-size:.85rem;margin:.1rem .85rem}
.card .excerpt{margin-block:.3rem .85rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

.badge{display:inline-block;font-size:.68rem;font-weight:700;text-transform:uppercase;
  letter-spacing:.08em;padding:.18rem .5rem;border-radius:.4rem}
.badge-live{background:#e5484d;color:#fff}
.badge-upcoming{background:#2a2a32;color:var(--accent)}
/* #c9ccd4, not --text-muted (#5c6270): that scored 2.27:1 on this badge's own dark fill —
   a WCAG AA failure in all seven places the badge renders, the player included. 8.86:1. */
.badge-replay{background:#2a2a32;color:#c9ccd4}
.empty{color:var(--text-muted);padding:2.25rem 1.25rem;text-align:center;border:1px dashed var(--border);
  border-radius:.8rem;background:color-mix(in srgb,var(--surface) 55%,transparent)}
/* Reset affordance in a zero-match state — a real pill control matching the filter bar's
   button vocabulary (bordered, accent on hover), not loose inline text. */
.clear-filters{display:inline-flex;align-items:center;gap:.35rem;margin-inline-start:.6rem;
  padding:.34rem .8rem;border:1px solid var(--border-btn);border-radius:.5rem;
  color:var(--accent-ink);font-weight:700;font-size:.85rem;line-height:1;
  transition:border-color .15s,background-color .15s}
.clear-filters:hover{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent)}
/* Pooled nation detail (root /nations/<code>/) + cross-edition career — each championship is
   its own raised panel, matching the medals page's .medals-panel grammar so a long stack reads
   as grouped blocks, not one undifferentiated list of rows. World Gymnastics light (Task 3):
   white card + soft --shadow-card (was --bg-raised grey + a dark-era heavy black shadow —
   plan calls these out by name as "white raised cards"). */
.ned-edition,.career-edition{background:var(--surface);border:1px solid var(--border-card);
  border-radius:1.1rem;padding:1rem 1.15rem 1.15rem;margin-block:0 1.1rem;
  box-shadow:var(--shadow-card)}
.ned-edition .rail-h,.career-edition .rail-h{margin-block:0 .7rem}
.ned-edition .rail-h a,.career-edition .rail-h a{color:inherit}
.ned-edition .rail-h a:hover,.career-edition .rail-h a:hover{color:var(--accent-ink)}
.ned-tally{color:var(--text-soft);font-size:.9rem;margin-block:0 .65rem;display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;font-variant-numeric:tabular-nums}
.empty-sm{color:var(--text-muted);font-size:.9rem;margin-block:.15rem 0}

.card-link,.row-link{color:inherit;display:block}
.hero-sm{padding-block:1.5rem .75rem}
.hero-lead{color:var(--text-muted);max-inline-size:46rem;margin-block-start:.5rem;font-size:1.02rem}

/* schedule */
.filters{display:flex;gap:1rem;flex-wrap:wrap;align-items:end;margin-block-end:1.5rem;
  padding:.85rem 1rem;background:color-mix(in srgb,var(--surface) 70%,transparent);
  border:1px solid var(--border);border-radius:.7rem}
.filters label{display:flex;flex-direction:column;gap:.3rem;font-size:.78rem;color:var(--text-muted);flex:0 1 13rem;min-inline-size:0}
.filters select{background:var(--surface);color:var(--text);border:1px solid var(--border-btn);border-radius:.4rem;padding:.4rem .55rem;font:inherit;inline-size:100%;max-inline-size:100%}
@media (max-width:34rem){.filters label{flex-basis:100%}}
.day-nav{position:sticky;inset-block-start:0;z-index:5;display:flex;gap:.4rem;overflow-x:auto;
  padding-block:.6rem;margin-block-end:1.25rem;background:var(--bg);border-block-end:1px solid var(--border);
  scrollbar-width:thin}
.day-nav a{flex:0 0 auto;display:flex;flex-direction:column;align-items:center;gap:.1rem;
  padding:.35rem .6rem;border:1px solid var(--border);border-radius:.5rem;color:var(--text-muted);min-width:3.4rem;text-align:center}
.day-nav a:hover{border-color:var(--accent);color:var(--text)}
.day-nav a .d{font-size:.82rem;font-weight:600;color:var(--text);white-space:nowrap}
.day-nav a .dow{font-size:.66rem;text-transform:uppercase;letter-spacing:.04em}
.day{margin-block-end:1.75rem;scroll-margin-block-start:5rem}
.day-h{font-size:1rem;color:var(--text);margin:0 0 .6rem;letter-spacing:.02em;display:flex;align-items:center;gap:.6rem}
.day-h::before{content:"";flex:0 0 auto;inline-size:.34rem;block-size:1.15rem;background:var(--accent);border-radius:2px}
.day-count{font-size:.72rem;font-weight:700;color:var(--text-muted);background:var(--surface);border:1px solid var(--border);border-radius:1rem;padding:.05rem .5rem}
.rows{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}
/* A schedule row is the session link PLUS, for anything not yet finished, a sibling
   add-to-calendar link. Sibling and not child: .row-link wraps the whole row and an anchor
   cannot nest in an anchor. The row link takes the free space; the calendar link keeps its
   natural width at the end. */
.row{display:flex;align-items:stretch;gap:.4rem}
.row>.row-link{flex:1 1 auto;min-inline-size:0}
.row-link{display:grid;grid-template-columns:4rem 1fr auto auto;gap:.8rem;align-items:center;background:var(--surface);border:1px solid var(--border);border-radius:.6rem;padding:.7rem .9rem}
.row-link:hover{border-color:var(--accent)}
.row-time{color:var(--text-muted);font-variant-numeric:tabular-nums}
.row-venue{color:var(--text-muted);font-size:.85rem}
.row-cal{flex:0 0 auto;display:flex;align-items:center;background:var(--surface);
  border:1px solid var(--border);border-radius:.6rem;padding-inline:.9rem;
  font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  font-size:.68rem;color:var(--text-muted);white-space:nowrap;
  transition:border-color .15s ease,color .15s ease}
.row-cal:hover{border-color:var(--accent);color:var(--accent-ink)}
@media (max-width:38rem){
  .row-link{grid-template-columns:3.2rem 1fr auto}
  .row-venue{display:none}
  /* Stacked on a phone: side by side the label squeezes the session title to nothing. */
  .row{flex-direction:column;gap:.25rem}
  .row-cal{align-self:flex-start;padding-block:.4rem}
}
/* schedule row: end time + channel -> apparatus strip (client ask Z-01). The strip spans the
   whole row under the title; channel numbers are real stream numbers, not decoration. */
.row-time{display:flex;flex-direction:column;line-height:1.2}
.row-time .t-start{color:var(--text);font-weight:700}
.row-time .t-end{font-size:.78rem}
.row-ch{grid-column:1/-1;list-style:none;margin:.25rem 0 0;padding:.6rem 0 0;border-block-start:1px dashed var(--border);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(9.5rem,1fr));gap:.35rem .6rem;font-size:.82rem}
.row-ch li{display:flex;align-items:center;gap:.45rem;min-inline-size:0}
.ch-n{flex:0 0 auto;display:grid;place-items:center;inline-size:1.35rem;block-size:1.35rem;border-radius:50%;
  background:var(--primary);color:#fff;font-size:.7rem;font-weight:700;font-variant-numeric:tabular-nums}
.ch-name{color:var(--text-soft)}
.ch-name small{color:var(--text-muted);font-size:.68rem;font-weight:700;margin-inline-start:.15rem}
.row-ch--one{display:block;color:var(--text-muted);font-style:normal}
@media (max-width:38rem){.row-ch{grid-template-columns:1fr 1fr}}
.apply-btn{align-self:end;background:var(--accent);color:var(--on-accent);font-weight:700;border:0;border-radius:.4rem;padding:.5rem .9rem;font:inherit;cursor:pointer}

/* schedule — day cards (cold-start overview) */
.day-cards{list-style:none;margin:0;padding:0;display:grid;gap:.7rem;grid-template-columns:repeat(2,1fr)}
@media (min-width:34rem){.day-cards{grid-template-columns:repeat(auto-fill,minmax(9.5rem,1fr))}}
.day-cards li{display:flex}
.day-card{display:flex;flex-direction:column;gap:.45rem;inline-size:100%;
  background:var(--surface);border:1px solid var(--border);border-radius:.7rem;padding:.8rem .85rem;color:inherit}
a.day-card:hover{border-color:var(--accent)}
.day-card-tba{opacity:.7}
.dc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:.4rem}
.dc-date{display:flex;align-items:baseline;gap:.3rem;line-height:1}
.dc-dow{font-size:.72rem;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted)}
.dc-day{font-size:1.5rem;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums}
.dc-mon{font-size:.78rem;color:var(--text-muted)}
/* World Gymnastics light (Task 4): was a second, slightly-off "live red" (#ff4d4d) alongside
   the site's established one (#e5484d — .badge-live/.live-dot/.event-card/.mp-lead etc.).
   Not a theme bug (both work on light or dark), but an inconsistency this sweep normalizes to
   the existing literal rather than inventing a third. */
.dc-live{font-size:.6rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:#e5484d;display:inline-flex;align-items:center;gap:.3rem}
.dc-live::before{content:"";inline-size:.45rem;block-size:.45rem;border-radius:50%;background:#e5484d;box-shadow:0 0 0 0 rgba(229,72,77,.6);animation:dc-pulse 1.6s infinite}
@keyframes dc-pulse{70%{box-shadow:0 0 0 .35rem rgba(229,72,77,0)}100%{box-shadow:0 0 0 0 rgba(229,72,77,0)}}
@media (prefers-reduced-motion:reduce){.dc-live::before{animation:none}}
.dc-count{font-size:.82rem;font-weight:700;color:var(--text)}
.dc-sports{font-size:.74rem;color:var(--text-muted);line-height:1.3}
.dc-more{color:var(--accent-ink)}

/* schedule — list header (active filters) */
.sched-head{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin-block-end:1rem}
.all-days{color:var(--text-muted);font-size:.82rem;font-weight:600;white-space:nowrap}
.all-days:hover{color:var(--accent-ink)}
.pills{display:flex;gap:.4rem;flex-wrap:wrap}
.pill{display:inline-flex;align-items:center;gap:.4rem;background:var(--surface);border:1px solid var(--accent);color:var(--text);border-radius:2rem;padding:.25rem .7rem;font-size:.78rem}
.pill .x{color:var(--text-muted);font-size:.7rem}
.pill:hover .x{color:var(--accent-ink)}

/* schedule — active day chip */
.day-nav a.active{border-color:var(--accent-ink);color:var(--text)}
.day-nav a.active .d{color:var(--accent-ink)}

/* watch */
.watch{display:grid;gap:1.5rem}
.player{width:100%;aspect-ratio:16/9;background:#000;border-radius:.6rem;display:flex;align-items:center;justify-content:center;color:var(--text-muted);overflow:hidden}
mux-player.player{--media-object-fit:contain}
.player-gated,.player-empty{border:1px solid var(--border);flex-direction:column;gap:.8rem;text-align:center;padding:1rem}
.player-state{margin-block:.6rem 0;color:var(--text-muted)}
.pl-title{font-weight:700;color:var(--text)}
.pl-note{max-width:46ch;color:var(--text-muted)}
.picker{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-block-start:.9rem}
.picker-label{color:var(--text-muted);font-size:.74rem;text-transform:uppercase;letter-spacing:.1em;margin-inline-end:.3rem}
.chip{background:var(--surface);color:var(--text);border:1px solid var(--border-btn);border-radius:2rem;padding:.35rem .8rem;font:inherit;font-size:.85rem;cursor:pointer}
.chip-on{border-color:var(--accent-ink);color:var(--accent-ink)}
.btn{display:inline-block;background:var(--accent);color:var(--on-accent);font-weight:700;padding:.5rem 1rem;border-radius:.5rem}
.back{margin-block-start:1.2rem}
.back a{color:var(--text-muted)}

/* HTMX loading indicator (G3-lite): visible only while a request is in flight */
.htmx-indicator{opacity:0;transition:opacity .15s;color:var(--accent-ink);font-size:.8rem;align-self:center}
.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{opacity:1}

/* ---- footer ---- */
/* Fidelity pass 2026-07-16: the reference footer IS a deep-indigo band (their wg_footer.jpg
   tonal curves → bg/band-footer.webp) with white ink — not a grey strip. The footer is dark in
   BOTH themes now, so the inks below are hardcoded whites; .theme-dark only swaps the backdrop
   back to its own near-black (the `background:` shorthand also drops the band image there). */
.site-footer{margin-block-start:4rem;color:rgba(255,255,255,.72);
  background:var(--band) url("bg/band-footer.webp") center/cover no-repeat}
.theme-dark .site-footer{background:rgba(8,8,10,.55)}
/* Footer "broadcast end-card": the indigo ribbon band (reference news-band language), statement + lime pill CTA. */
.footer-hero{position:relative;overflow:hidden;min-block-size:15rem;display:flex;align-items:center;
  border-block-end:1px solid rgba(255,255,255,.12);
  background:#171230 url("bg/band-ribbon.webp") center/cover no-repeat}
/* Light hides the photo (lazy + display:none = never fetched); watch/live keep the prior
   photo-band footer verbatim — img + near-black duotone wash, dark-scope preserved. */
.footer-hero>img{display:none}
.theme-dark .footer-hero{background:none;border-block-end:1px solid var(--border)}
.theme-dark .footer-hero>img{display:block;position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover;object-position:center 28%}
.theme-dark .footer-hero::after{content:"";position:absolute;inset:0;background:
  linear-gradient(90deg, color-mix(in srgb,var(--bg) 82%,transparent) 0%, color-mix(in srgb,var(--bg) 30%,transparent) 58%, transparent 100%),
  linear-gradient(0deg, rgba(5,6,10,.9), rgba(5,6,10,.2))}
.footer-hero-body{position:relative;z-index:1;inline-size:100%;max-inline-size:78rem;margin-inline:auto;padding:2.5rem 1.25rem}
.footer-eyebrow{font-family:var(--display);text-transform:uppercase;letter-spacing:.2em;font-size:.72rem;color:var(--accent);margin:0 0 .65rem}
.footer-statement{font-family:var(--display);font-weight:800;font-size:clamp(1.9rem,4.2vw,3.1rem);line-height:1.02;letter-spacing:-.01em;color:#fff;margin:0 0 1.2rem;max-inline-size:16ch}
.footer-cta{display:inline-flex;align-items:center;gap:.4rem}
.footer-cols{max-width:78rem;margin-inline:auto;padding-block:2.75rem 2rem;padding-inline:1.25rem;
  display:grid;gap:2rem;grid-template-columns:1.5fr repeat(4, 1fr)}
.footer-brand .brand{font-weight:800;font-size:1.2rem;color:#fff}
.footer-brand .brand img{height:42px}
.footer-brand .tagline{margin-block:.75rem 0;max-width:24rem;font-size:.9rem;line-height:1.55}
/* The wordmark chip already carries ink-on-lime; GYM flips to white via the .brand color above. */
.site-footer .wm{color:#fff}
.footer-col{display:flex;flex-direction:column;gap:.6rem}
.footer-col h3{font-size:.74rem;text-transform:uppercase;letter-spacing:.1em;color:#fff;margin:0 0 .55rem;font-weight:700;position:relative;padding-block-end:.5rem}
.footer-col h3::after{content:"";position:absolute;inset-block-end:0;inset-inline-start:0;width:1.6rem;height:2px;background:var(--accent);border-radius:2px}
.footer-col a{color:rgba(255,255,255,.75);font-size:.9rem;text-transform:capitalize;width:fit-content}
.footer-col a:hover{color:var(--accent)}
/* The watch/live (dark) footer uses the same white-grey links as every other page: it once kept a
   "prior yellow-link footer" here, which rendered orange under the Rotterdam accent. */
.site-footer .sponsors{max-width:78rem;margin-inline:auto;padding-block:1.5rem;padding-inline:1.25rem;
  border-block-start:1px solid rgba(255,255,255,.12);display:flex;flex-wrap:wrap;gap:1.5rem;align-items:center}
.site-footer .sponsors-label{font-size:.72rem;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.6)}
.site-footer .sponsors img{height:30px;opacity:.75;filter:grayscale(1);transition:opacity .15s,filter .15s}
.site-footer .sponsors a:hover img{opacity:1;filter:none}
.site-footer .sponsor-name{font-weight:600;color:#fff}
.footer-bottom{max-width:78rem;margin-inline:auto;padding-block:1.25rem 1.75rem;padding-inline:1.25rem;
  border-block-start:1px solid rgba(255,255,255,.12);display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap}
.footer-bottom .copyright{font-size:.82rem;margin:0;color:rgba(255,255,255,.6)}
.footer-legal{display:flex;align-items:center;gap:1.1rem}
.footer-legal a{position:relative;font-size:.82rem;color:rgba(255,255,255,.6)}
.footer-legal a:hover{color:var(--accent)}
.footer-legal a:not(:last-child)::after{content:"·";position:absolute;inset-inline-end:-.65rem;color:rgba(255,255,255,.25)}
/* Footer social icon links */
.footer-social .social-links{display:flex;gap:.55rem;flex-wrap:wrap}
.footer-social .social-link{display:inline-flex;align-items:center;justify-content:center;padding:0;inline-size:2.1rem;block-size:2.1rem;border-radius:50%;background:transparent;border:1px solid rgba(255,255,255,.25);color:rgba(255,255,255,.75);transition:color .15s,border-color .15s,background .15s}
.footer-social .social-link:hover{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}
/* Sponsor wall + section label inside the indigo footer: the light-band label ink is invisible
   here — lift it; the white tiles keep working on indigo. */
.site-footer .reel{border-block-color:rgba(255,255,255,.12)}
.site-footer .reel-h{color:rgba(255,255,255,.65)}
/* Header nav divider (watch | explore) + sticky condense-on-scroll */
.nav-div{inline-size:1px;block-size:1.1rem;background:var(--border);margin-inline:.45rem;flex-shrink:0}
.theme-dark .nav-div{background:rgba(255,255,255,.20)}
.site-header .header-inner{transition:padding-block .2s ease}
.site-header .brand img{transition:height .2s ease}
.site-header.scrolled{background:color-mix(in srgb,var(--bg) 97%,transparent)}
.site-header.scrolled .header-inner{padding-block:.5rem}
.site-header.scrolled .brand img{height:30px}
/* Hide the secondary event-mark on medium widths to give the 11-item nav room. */
@media (max-width:80rem){.event-mark{display:none}}
@media (max-width:64rem){.nav-div{display:none}}
/* Static pages live in the footer and the drawer, never the desktop header — see base.html.
   Measured: brand 98 + nav 653 + actions 222 + gaps/padding 80 = 1053px needed at <=80rem, versus
   984px available at 1024. "About GymTV" is 112px of that, so removing it is what buys the fit. */
.nav-page-link{display:none}

/* Drawer scrim + drawer-only action links: hidden on desktop; shown in the drawer breakpoint below. */
.nav-scrim,.nav-actions{display:none}

/* ---- responsive: collapse nav into a drawer. ----
   Was max-width:75rem (1200px), which was far too early for a DESKTOP site: a 1152px window — or
   a 1440px screen at 125% browser zoom, which reports a 1152px layout viewport — lost the entire
   navigation to a burger and read as "the nav bar is broken". Measured, the seven-tab event nav
   needs ~941px once .event-mark and the static-page link are out, so 64rem (1024px) is the honest
   line. Below it the drawer is genuinely necessary, and the static-page links rejoin it here. */
@media (max-width:64rem){
  .nav-page-link{display:block}
  .burger{display:flex;position:relative;z-index:16}
  /* Keyboard-operable drawer toggle (zero-JS): the checkbox is visually hidden but
     focusable + operable by Space; focus shows a ring on the visible burger. */
  .nav-toggle{display:block;position:absolute;inline-size:1px;block-size:1px;opacity:0;margin:0}
  .nav-toggle:focus-visible ~ .burger{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}
  .event-mark{display:none}  /* keep the mobile header tight; identity carries via accent + hero */
  .nav{position:fixed;inset-block-start:0;inset-inline-end:0;block-size:100dvh;inline-size:min(78vw,18rem);
    flex-direction:column;align-items:flex-start;gap:.25rem;margin:0;padding:4.5rem 1.5rem 1.5rem;
    background:var(--surface);border-inline-start:1px solid var(--border);
    transform:translateX(100%);transition:transform .25s ease,visibility 0s linear .25s;z-index:15;overflow-y:auto;
    visibility:hidden}
  html[dir=rtl] .nav{transform:translateX(-100%)}
  .nav a{font-size:1.05rem;padding-block:.6rem;inline-size:100%;border-block-end:1px solid var(--border)}
  /* The desktop active-pill (::after) is removed in the drawer; give the current page a clear
     accent bar instead, or it's indistinguishable from the other links. */
  .nav a.active::after{display:none}
  /* `background` must be unset too: the desktop rule paints the pill var(--nav-active) and this
     rule only recoloured the ink to the SAME token — the current page's label was FIG blue on a
     FIG-blue bar, i.e. invisible. The bar here is the inset box-shadow, not a filled pill. */
  .nav a.active{color:var(--nav-active);background:none;
    box-shadow:inset 3px 0 0 var(--nav-active);padding-inline-start:.5rem}
  /* Re-assert the accent ink for the dark theme: `.theme-dark .nav a.active` outranks the rule
     above, and its --on-nav is near-black — correct on the desktop pill it was written for, but
     in the drawer there is no pill, so it would sit near-black on the near-black surface. */
  .theme-dark .nav a.active{color:var(--nav-active)}
  /* Closed, the drawer is hidden (not only slid off): its shadow no longer greys the right edge
     of every page, and Tab / screen readers skip its links. Visibility flips after the slide-out
     and at once on open, so the transition still plays both ways. */
  .nav-toggle:checked ~ .nav{transform:translateX(0);visibility:visible;transition:transform .25s ease,visibility 0s;
    box-shadow:-12px 0 40px rgba(0,0,0,.5)}
  .nav-toggle:checked ~ .burger span:nth-child(1){transform:translateY(.5rem) rotate(45deg)}
  .nav-toggle:checked ~ .burger span:nth-child(2){opacity:0}
  .nav-toggle:checked ~ .burger span:nth-child(3){transform:translateY(-.5rem) rotate(-45deg)}
  /* Tap-to-close scrim behind the open drawer — a <label for=nav-toggle> so a click anywhere
     outside the drawer unchecks the toggle and slides it away (zero-JS, matches the drawer). */
  /* NB: .site-header has backdrop-filter → it's the containing block for these position:fixed
     children, so `inset:0` would only cover the header strip. Size to the full viewport (like
     .nav's block-size:100dvh) so the scrim actually covers the page and catches outside clicks. */
  .nav-scrim{display:block;position:fixed;inset-block-start:0;inset-inline:0;block-size:100dvh;
    z-index:14;border:0;margin:0;background:rgba(0,0,0,.5);opacity:0;pointer-events:none;
    transition:opacity .25s ease}
  .nav-toggle:checked ~ .nav-scrim{opacity:1;pointer-events:auto}
  /* Stop a swipe over the scrim from scrolling the page behind the open drawer — you'd close the
     menu to find yourself somewhere you never navigated to. Done by making the scrim and the
     drawer their own scroll containers that refuse to chain, NOT by locking overflow on <html>:
     that clamps the document's scroll offset to 0, so closing the drawer would jump you to the
     top of the page (measured — worse than the problem it fixes). */
  .nav-scrim{overflow-y:scroll;overscroll-behavior:contain}
  .nav{overscroll-behavior:contain}
  /* The header's text actions overflow a phone and get clipped off-screen — hide them and surface
     their copies inside the drawer (.nav-actions). Search + account icons stay and now fit. */
  .header-actions .purchase-link,.header-actions .signin-link{display:none}
  .nav-actions{display:flex;flex-direction:column;gap:.35rem;inline-size:100%;
    margin-block-start:.5rem;padding-block-start:.5rem;border-block-start:1px solid var(--border)}
  /* Both `.nav a` (0,1,1) and `.theme-dark .nav a` (0,2,1) outranked a bare `.nav-action-cta`
     (0,1,0), so the ink-on-accent colour never applied — the CTA read as pale grey on lime (and
     on yellow in the dark theme). Qualifying it to (0,2,1) + later source order wins both. */
  .nav a.nav-action-cta{margin-block-start:.35rem;background:var(--accent);color:var(--on-accent);
    text-align:center;border-radius:.5rem;font-weight:700;border-block-end:0}
  .footer-cols{grid-template-columns:1fr 1fr;gap:1.75rem}
  .footer-brand{grid-column:1 / -1}
}
@media (max-width:30rem){
  .footer-cols{grid-template-columns:1fr}
}

/* ---- prose (pages + article detail) ---- */
.prose{max-width:42rem;margin-inline:auto;line-height:1.7}
/* Static pages (About / legal) — sit the copy on a surface card so the page reads as a
   designed block with depth, not bare text floating on the dark. */
.prose-card{background:color-mix(in srgb,var(--surface) 72%,transparent);border:1px solid var(--border);
  border-radius:1rem;padding:clamp(1.5rem,4vw,2.75rem);margin-block:1.5rem 2.5rem;
  box-shadow:0 26px 64px -42px rgba(0,0,0,.85)}
.prose-card>:first-child{margin-block-start:0}
.prose-card h2{font-family:var(--display);letter-spacing:-.005em;margin-block:1.6rem .5rem}
.prose-card .lead{font-size:1.12rem;color:var(--text)}
.prose h1{font-size:clamp(1.6rem,3.5vw,2.4rem)}
.prose img{border-radius:.6rem;margin-block:1rem;max-width:100%}
/* Wide tables (legal / cookie pages) scroll within the card on phones instead of overflowing it. */
.prose table,.prose-card table{display:block;overflow-x:auto;max-width:100%}
.article-detail .eyebrow{color:var(--accent-ink);text-transform:uppercase;letter-spacing:.1em;font-size:.78rem;margin:0 0 .3rem}
.article-hero{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:.6rem;margin-block:1rem}
.article-card .article-img{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:.5rem;margin-block-end:.6rem}
.article-card .excerpt{color:var(--text-muted);font-size:.9rem}
.rail-h{font-size:1.05rem;margin:1.5rem 0 .8rem;color:var(--accent-ink)}

/* ---- news teasers (fidelity pass 2026-07-16) — the reference list rows: image left, cut by
   the S-curve wave divider (bg/wave-news.svg, fill #F0F2F4 = the row surface, alternating
   direction per row), content on the grey row, cyan date, indigo chevron circle. ---- */
/* Full-bleed contiguous rows, reference proportions: the images form one tall left column cut
   by the alternating S-wave; text sits on the grey row and ends at the content column edge. */
.news-teasers{list-style:none;margin:1.25rem 0 0;padding:0;display:flex;flex-direction:column;
  width:100vw;margin-inline:calc(50% - 50vw)}
.news-teaser{background:var(--surface-2);overflow:hidden}
.nt-link{display:flex;align-items:stretch;color:inherit;
  padding-inline-end:max(1.25rem,calc(50vw - 39rem))}
.nt-media{position:relative;flex:0 0 clamp(15rem,30vw,32rem);min-block-size:13.5rem;overflow:hidden;
  background:var(--band)}
.nt-media img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover}
/* the wave overlay spans the WHOLE media box (like the reference's :before) — a narrow strip
   crops the S once `auto 100%` scales the 42x250 svg past the strip width on tall rows */
.nt-media::after{content:"";position:absolute;inset:-3px -1px;
  background:url("bg/wave-news.svg") right center/auto 100% no-repeat}
.news-teaser--inverse .nt-media::after{background-image:url("bg/wave-news-inverse.svg")}
.nt-body{flex:1;min-inline-size:0;display:flex;flex-direction:column;justify-content:center;gap:.35rem;
  padding:1.75rem 2rem}
.nt-title{font-family:var(--display);font-weight:700;font-size:clamp(1.1rem,2.4vw,1.55rem);
  line-height:1.22;color:var(--text);transition:color .15s ease}
.nt-link:hover .nt-title{color:var(--accent-ink)}
.nt-date{color:var(--support);font-weight:700;font-size:.92rem;font-variant-numeric:tabular-nums}
.nt-excerpt{color:var(--text-soft);font-size:.97rem;line-height:1.55;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.nt-more{align-self:center;flex:0 0 auto;margin-inline-start:1rem;inline-size:2.8rem;block-size:2.8rem;
  border-radius:50%;background:var(--band);color:#fff;display:grid;place-items:center;
  font-size:1.6rem;line-height:1;padding-block-end:.15rem;transition:transform .15s ease}
.nt-link:hover .nt-more{transform:translateX(3px)}
@media (max-width:34rem){
  .nt-media{flex-basis:8rem;min-block-size:8.5rem}
  .nt-excerpt,.nt-more{display:none}
  .nt-body{padding:1rem 1.1rem}
}

/* ---- search ---- */
.searchbar{display:flex;gap:.5rem;margin-block-end:1.5rem;max-width:36rem}
.searchbar input{flex:1;min-width:0;background:var(--surface);color:var(--text);border:1px solid var(--border-btn);border-radius:.5rem;padding:.6rem .8rem;font:inherit}
.searchbar button{background:var(--accent);color:var(--on-accent);border:0;border-radius:.5rem;padding:.6rem 1rem;font:inherit;font-weight:700;cursor:pointer}

/* ---- medal table ---- */
.medals{width:100%;border-collapse:collapse;margin-block-start:.5rem}
.medals th,.medals td{padding:.6rem .7rem;text-align:center;border-block-end:1px solid var(--border)}
.medals th{color:var(--text-muted);font-size:.78rem;text-transform:uppercase;letter-spacing:.06em;font-weight:600}
.medals th.nation,.medals td.nation{text-align:start}
.medals td.nation{font-weight:600}
.medals td.nation .code{color:var(--text-muted);font-weight:400;font-size:.8rem;margin-inline-start:.35rem}
.medals td.rank,.medals th.rank{color:var(--text-muted);width:2.5rem}
/* Gold totals stay gold — medal semantics, not the brand accent. Under the old Kinetic
   theme --accent WAS a yellow/gold, so this read correctly by coincidence; now --accent
   is coral, so the Total column is pinned to the same gold hex used everywhere else on
   this page (#e9c463 — .mp-num, .col-gold, .badge-gold) rather than the token. */
.medals td.total,.medals th.total{font-weight:700;color:var(--metal-gold-ink)}
.medals tbody tr:hover{background:var(--surface)}
.medals td.nation a{color:var(--text);text-decoration:none}
.medals td.nation a:hover{color:var(--accent-ink)}
/* premium medal table — top-3 tints, per-medal bars, mobile scroll */
.table-wrap{overflow-x:auto;scrollbar-width:thin}
.medals .flag-img{width:1.8em}
.medals tr.r-gold{background:linear-gradient(90deg,rgba(233,196,99,.14),transparent 60%)}
.medals tr.r-silver{background:linear-gradient(90deg,rgba(207,210,214,.12),transparent 60%)}
.medals tr.r-bronze{background:linear-gradient(90deg,rgba(205,155,106,.13),transparent 60%)}
.medals td.mc{vertical-align:middle}
.medals td.mc .num{display:block;font-variant-numeric:tabular-nums;font-weight:700}
.medals td.mc .bar{display:block;height:3px;inline-size:var(--w);margin:.25rem auto 0;border-radius:2px;max-inline-size:2.4rem}
.medals td.mc .bar.g{background:#e9c463}.medals td.mc .bar.s{background:#cfd2d6}.medals td.mc .bar.b{background:#cd9b6a}

/* (the old .nation-podium/.np-* top-3 strip was replaced by the Task 9 .medal-podium hero;
   its rules are gone — .np-group/.np-h/.np-athletes further down are nation_detail's, unrelated) */

/* sticky sport jump-nav reuses .day-nav; only spacing here */
.medal-jump{margin-block:1.5rem 1rem}
.medal-jump a.active{border-color:var(--accent-ink);background:color-mix(in srgb,var(--accent) 16%,var(--surface))}
.medal-jump a.active .d{color:var(--accent-ink)}

/* medals by sport — per-event Gold/Silver/Bronze podiums */
.medal-sport{margin-block-end:2rem;scroll-margin-block-start:4rem}
.sport-h{font-family:var(--display);text-transform:uppercase;letter-spacing:.04em;font-size:1.1rem;color:var(--text);
  display:flex;align-items:center;gap:.6rem;margin:0 0 .9rem;padding-block-end:.4rem;border-block-end:1px solid var(--border)}
.sport-count{font-size:.72rem;font-weight:700;color:var(--text-muted);background:var(--surface);border:1px solid var(--border);border-radius:1rem;padding:.05rem .55rem}
.event-podium{background:var(--surface);border:1px solid var(--border);border-radius:.8rem;padding:.9rem;margin-block-end:.8rem}
.ep-title{font-size:.92rem;font-weight:600;margin:0 0 .8rem;color:var(--text)}
/* pooled medals: which championship this final belongs to (two same-named finals differ) */
.ep-edition{margin:-.6rem 0 .8rem;font-size:.72rem;color:var(--text-muted)}
.ep-cols{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem;align-items:start}
.podium-col{display:flex;flex-direction:column;align-items:center;gap:.5rem}
.col-label{font-size:.66rem;text-transform:uppercase;letter-spacing:.08em;font-weight:800}
.col-gold .col-label{color:#e9c463}.col-silver .col-label{color:#cfd2d6}.col-bronze .col-label{color:#cd9b6a}
.col-empty{color:var(--text-muted);opacity:.5}
.medal-card{display:flex;flex-direction:column;align-items:center;gap:.25rem;text-align:center;color:inherit;inline-size:100%}
.medal-card:hover .mc-name{color:var(--accent-ink)}
.mc-face{inline-size:5.75rem;aspect-ratio:4/5;border-radius:.9rem;overflow:hidden;display:grid;place-items:center;background:var(--bg);border:2px solid var(--border)}
.mc-face img{inline-size:100%;block-size:100%;object-fit:cover}
.mc-mono{font-family:var(--display);font-weight:800;font-size:1.9rem;color:var(--accent-ink)}
.mc-gold .mc-face{border-color:#e9c463}.mc-silver .mc-face{border-color:#cfd2d6}.mc-bronze .mc-face{border-color:#cd9b6a}
/* team medal: render the nation flag as a clean flag chip at its true 4:3 aspect
   (a flag forced into the square avatar box looked cropped/cramped) */
.mc-face-team{inline-size:auto;block-size:auto;aspect-ratio:auto;border:none;background:none;border-radius:0;overflow:visible;padding:0}
.mc-face-team .flag-img{width:5.5rem;height:auto;border-radius:.4rem;box-shadow:0 2px 9px rgba(0,0,0,.5),0 0 0 2px var(--border)}
.mc-gold .mc-face-team .flag-img{box-shadow:0 2px 9px rgba(0,0,0,.5),0 0 0 2px #e9c463}
.mc-silver .mc-face-team .flag-img{box-shadow:0 2px 9px rgba(0,0,0,.5),0 0 0 2px #cfd2d6}
.mc-bronze .mc-face-team .flag-img{box-shadow:0 2px 9px rgba(0,0,0,.5),0 0 0 2px #cd9b6a}
.mc-name{font-size:.82rem;font-weight:600;line-height:1.2}
.mc-nat{font-size:.72rem;color:var(--text-muted)}
@media (max-width:30rem){.event-podium{padding:.7rem .5rem}.ep-cols{gap:.3rem}.mc-face{inline-size:4.4rem}.mc-face-team .flag-img{width:4.4rem}.mc-name{font-size:.74rem}}

/* ============================================================================
   Task 9 — Medals reimagine. Client verdict on the old page: "too dark and empty."
   Fix: podium-first, brighter surfaces, fuller grid — same Kinetic language as home.
   ALL brightening is scoped to `body.page-medals` because the medallist partials
   (_event_podium.html / _medal_card.html) are shared by sport/athletes/nations —
   those pages MUST stay unchanged. Tokens only; medal-metal hexes reuse the existing
   podium palette (#e9c463 gold / #cfd2d6 silver / #cd9b6a bronze) already in this file.
   NOTE (World Gymnastics light, Task 3): the `body.page-medals::before` arena-backdrop
   lift that used to live here is gone — T1 scoped the ONLY rule that puts `content`
   on `body::before` to `body.theme-dark::before` (line ~73), so a light page's
   `body.page-medals::before` never generated a box to begin with (background-only,
   no content). Verified dead before deleting; nothing to replace it with.
   ============================================================================ */

/* Filters as pills (chip/pill vocabulary) on a raised strip. */
.medal-filters{display:flex;flex-wrap:wrap;gap:.7rem;align-items:end;margin-block:0 1.75rem;
  padding:.8rem .9rem;background:var(--bg-raised);border:1px solid var(--border-card);border-radius:1rem}
/* `.mdf-*` — NOT venues' `.mf-field` (its later `.mf-field select` rule would override the pill). */
.mdf-field{display:flex;flex-direction:column;gap:.3rem}
.mdf-label{font-family:var(--display);font-size:.64rem;text-transform:uppercase;letter-spacing:.11em;font-weight:700;color:var(--text-muted)}
.medal-filters select{appearance:none;-webkit-appearance:none;background:var(--surface);color:var(--text);
  border:1px solid var(--border-btn);border-radius:2rem;padding:.45rem 2rem .45rem 1rem;font:inherit;font-size:.86rem;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' stroke='%239a9aa4' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .8rem center}
.medal-filters select:hover,.medal-filters select:focus-visible{border-color:var(--accent)}
.medal-filters button{align-self:end;background:var(--accent);color:var(--on-accent);border:0;border-radius:2rem;
  padding:.5rem 1.3rem;font-family:var(--display);font-weight:800;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;cursor:pointer;transition:filter .15s ease,transform .15s ease}
.medal-filters button:hover{filter:brightness(1.08);transform:translateY(-1px)}

/* Podium hero — three raised cards; #1 on the FIG-blue color-block (already correct via
   tokens — --primary/--on-accent flip automatically). #2/#3 get the T2 white-card grammar
   (surface + soft --shadow-card) instead of the old dark-era heavy black drop shadow. */
.medal-podium{display:grid;grid-template-columns:1fr 1.22fr 1fr;gap:1rem;align-items:end;margin-block:0 2.25rem}
.mp-card{position:relative;display:flex;flex-direction:column;align-items:center;gap:.45rem;text-align:center;
  padding:1.6rem 1rem 1.25rem;border-radius:1.1rem;color:var(--text);
  background:linear-gradient(180deg,color-mix(in srgb,var(--surface) 86%,#fff 14%),var(--surface) 72%);
  border:1px solid var(--border-card);box-shadow:var(--shadow-card);
  transition:transform .18s ease,box-shadow .18s ease}
.mp-1{order:2}.mp-2{order:1}.mp-3{order:3}
.mp-2,.mp-3{padding-block:1.15rem 1.1rem}
.mp-card:hover{transform:translateY(-5px);box-shadow:var(--glow-card)}
.mp-lead{background:linear-gradient(180deg,color-mix(in srgb,var(--primary) 90%,#fff 10%),var(--primary));
  border-color:color-mix(in srgb,var(--primary) 45%,#fff 55%);color:var(--on-accent);
  box-shadow:0 26px 62px -22px color-mix(in srgb,var(--primary) 72%,transparent)}
.mp-lead:hover{box-shadow:0 32px 70px -22px color-mix(in srgb,var(--primary) 80%,transparent)}
.mp-pos{position:absolute;inset-block-start:-.85rem;inline-size:1.85rem;block-size:1.85rem;border-radius:50%;
  display:grid;place-items:center;font-family:var(--display);font-weight:800;font-size:.92rem;color:var(--on-accent);
  background:var(--text-muted);box-shadow:0 4px 12px rgba(0,0,0,.4)}
.mp-1 .mp-pos{background:#e9c463;color:#1a1400;box-shadow:0 0 0 4px color-mix(in srgb,var(--primary) 100%,transparent),0 4px 12px rgba(0,0,0,.4)}
.mp-2 .mp-pos{background:#cfd2d6;color:#1a1a1e}.mp-3 .mp-pos{background:#cd9b6a;color:#241505}
.mp-flag .flag-img{width:3.1rem;border-radius:.35rem;box-shadow:0 3px 12px rgba(0,0,0,.5)}
.mp-1 .mp-flag .flag-img{width:4rem}
.mp-name{font-family:var(--display);font-weight:800;font-size:1rem;line-height:1.15}
.mp-lead .mp-name{font-size:1.2rem}
.mp-code{font-family:ui-monospace,monospace;font-size:.72rem;font-weight:700;letter-spacing:.06em;color:var(--text-muted)}
.mp-lead .mp-code{color:color-mix(in srgb,var(--on-accent) 72%,transparent)}
.mp-gold{display:flex;flex-direction:column;align-items:center;line-height:1;margin-block-start:.25rem}
.mp-num{font-family:var(--display);font-weight:800;font-variant-numeric:tabular-nums;font-size:2.7rem;color:#e9c463}
.mp-lead .mp-num{font-size:3.3rem}
.mp-glabel{font-family:var(--display);text-transform:uppercase;letter-spacing:.13em;font-size:.62rem;font-weight:700;color:var(--text-muted);margin-block-start:.32rem}
.mp-lead .mp-glabel{color:color-mix(in srgb,var(--on-accent) 80%,transparent)}
.mp-chips{display:flex;gap:.4rem;margin-block-start:.55rem;flex-wrap:wrap;justify-content:center}
.mp-chip{display:inline-flex;flex-direction:column;align-items:center;gap:.05rem;min-inline-size:2.6rem;
  padding:.28rem .5rem;border-radius:.7rem;background:var(--bg-raised);border:1px solid var(--border-card)}
.mp-chip b{font-variant-numeric:tabular-nums;font-weight:800;font-size:.98rem;line-height:1}
.mp-chip i{font-style:normal;font-size:.56rem;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text)}
.mp-chip.s b{color:var(--metal-silver-ink)}.mp-chip.b b{color:var(--metal-bronze-ink)}
.mp-chip.t b{color:var(--text)}
/* The leader's chip is a DARK fill, so there the original light metals are the readable
   ones — darkening them there would repeat the bug in reverse. */
.mp-lead .mp-chip.s b{color:#cfd2d6}   /* 4.81:1 — already fine on the dark chip */
.mp-lead .mp-chip{background:color-mix(in srgb,#000 22%,var(--primary));border-color:color-mix(in srgb,#fff 24%,transparent)}
/* The leader chip is a DARK fill (the primary mixed with 22% black), so everything on it
   must be LIGHT. The label was --on-accent (deep indigo) at 70% — dark ink on a dark chip,
   1.87:1 — and the literal bronze scored 2.95:1 against it. These are the same three
   metals lightened until they pass on THIS background, mirroring what the darkened
   --metal-*-ink tokens do on the white chips. */
.mp-lead .mp-chip i{color:rgba(255,255,255,.88)}
.mp-lead .mp-chip.t b{color:#fff}
.mp-lead .mp-chip.b b{color:#f0cfae}   /* 4.95:1 */
@media (prefers-reduced-motion:no-preference){
  .medal-podium .mp-card{animation:mpRise .55s cubic-bezier(.2,.8,.2,1) both}
  .mp-2{animation-delay:.05s}.mp-1{animation-delay:.16s}.mp-3{animation-delay:.27s}
  @keyframes mpRise{from{opacity:0;transform:translateY(22px) scale(.96)}to{opacity:1;transform:none}}
}
@media (max-width:46rem){
  .medal-podium{grid-template-columns:1fr;gap:.8rem}
  .mp-1,.mp-2,.mp-3{order:0}
  .mp-card{flex-direction:row;flex-wrap:wrap;text-align:start;align-items:center;gap:.65rem .95rem;padding:1rem 1.1rem}
  .mp-pos{position:static;flex:0 0 auto}
  .mp-flag{flex:0 0 auto}
  .mp-flag .flag-img,.mp-1 .mp-flag .flag-img{width:2.7rem}
  .mp-name{font-size:1rem}.mp-lead .mp-name{font-size:1.05rem}
  .mp-gold{flex-direction:row;align-items:baseline;gap:.35rem;margin-inline-start:auto;margin-block-start:0}
  .mp-num,.mp-lead .mp-num{font-size:1.9rem}
  .mp-glabel{margin-block-start:0}
  .mp-chips{flex-basis:100%;justify-content:flex-start;margin-block-start:.2rem}
}

/* Raised panel wrapping the ranked table — white panel (spec §4: "white panel, grey zebra"),
   soft --shadow-card instead of the dark-era heavy black drop shadow. Zebra rows now read
   AGAINST the white panel as light-grey --bg-raised stripes (was color-mix(surface,transparent)
   on a grey panel — that read backwards once the panel itself went white). Hover gets its own
   subtle FIG-blue wash so it's visible over both plain and zebra rows. */
.medals-panel{background:var(--surface);border:1px solid var(--border-card);border-radius:1.1rem;
  padding:.3rem .7rem;margin-block:0 2.5rem;box-shadow:var(--shadow-card)}
.page-medals .medals{margin-block-start:0}
.page-medals .medals th,.page-medals .medals td{border-block-end:1px solid var(--border-card);padding:.72rem .8rem}
.page-medals .medals thead th{color:var(--text-soft)}
.page-medals .medals tbody tr:nth-child(even){background:var(--bg-raised)}
.page-medals .medals tbody tr:hover{background:color-mix(in srgb,var(--primary) 8%,transparent)}
.page-medals .medals tr.r-gold{background:linear-gradient(90deg,rgba(233,196,99,.24),color-mix(in srgb,var(--surface) 55%,transparent) 62%)}
.page-medals .medals tr.r-silver{background:linear-gradient(90deg,rgba(207,210,214,.2),color-mix(in srgb,var(--surface) 55%,transparent) 62%)}
.page-medals .medals tr.r-bronze{background:linear-gradient(90deg,rgba(205,155,106,.22),color-mix(in srgb,var(--surface) 55%,transparent) 62%)}
.page-medals .medals td.mc .num{font-size:1.02rem}

/* Per-discipline medallist sections — denser grid, brighter cards. */
.page-medals .medal-sport{margin-block-end:2.75rem}
.page-medals .sport-h{border-block-end-color:var(--border-card)}
.page-medals .sport-count{background:var(--bg-raised);border-color:var(--border-card)}
.page-medals .ep-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(20rem,1fr));gap:1rem;align-items:start}
.page-medals .event-podium{margin-block-end:0;border-color:var(--border-card);
  background:linear-gradient(180deg,color-mix(in srgb,var(--surface) 90%,#fff 10%),var(--surface) 66%);
  box-shadow:var(--shadow-card);transition:border-color .18s ease,transform .18s ease}
.page-medals .event-podium:hover{border-color:color-mix(in srgb,var(--accent) 42%,var(--border-card))}
.page-medals .mc-face{inline-size:5rem;background:var(--bg-raised);border-color:var(--border-btn)}
@media (max-width:30rem){.page-medals .mc-face{inline-size:4.4rem}}

/* ---- flags (self-hosted SVG; cross-platform — Windows ships no flag emoji) ---- */
.flag-img{display:inline-block;width:1.5em;aspect-ratio:4/3;height:auto;object-fit:cover;border-radius:2px;vertical-align:-.18em;box-shadow:0 0 0 1px rgba(255,255,255,.14)}
.flag-emoji{display:inline-block;line-height:1}
.flag-none{display:inline-block;width:1.5em;aspect-ratio:4/3;border-radius:2px;background:rgba(255,255,255,.08);vertical-align:-.18em}

/* ---- nations + athletes ---- */
.nation-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(11rem,1fr));gap:1.1rem;margin-block-start:.5rem}
/* White card + soft --shadow-card at rest (T2's wall-tile grammar); hover swaps to the
   FIG-blue-tinted --glow-card instead of a flat black drop shadow. */
.nation-card{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-block-size:9rem;padding:1.8rem 1rem;background:var(--surface);border:1px solid var(--border);border-radius:1rem;text-decoration:none;color:var(--text);text-align:center;box-shadow:var(--shadow-card);transition:border-color .15s,transform .15s,box-shadow .15s}
.nation-card:hover{border-color:var(--accent);transform:translateY(-3px);box-shadow:var(--glow-card)}
.nation-card .flag{width:4rem;height:auto;border-radius:5px;filter:drop-shadow(0 4px 10px rgba(0,0,0,.4))}
.nation-card .name{font-weight:700;font-size:1.08rem;line-height:1.2}
.nation-card .code{color:var(--accent-ink);font-size:.82rem;font-weight:700;letter-spacing:.1em}
.nation-card .tally{color:var(--text-muted);font-size:.84rem}
.nation-head,.athlete-head{display:flex;align-items:center;gap:1rem}
.nation-head .flag-lg{width:4.5rem;height:auto;border-radius:4px}
.nation-head .code,.athlete-head .code{color:var(--text-muted);font-size:1rem;font-weight:400}
.tally-lg{color:var(--text-muted);margin-block-start:.3rem}
/* Career page. The hero is a photo band with no photo (a career rollup has no single
   edition portrait), so keep it compact rather than letting a tall empty veil dominate,
   and set the facts line + tally on it explicitly — it is dark, so the light page ink
   would vanish. */
.career-head{padding-block:1.25rem 1.1rem}
.career-head h1{margin:0}
.career-facts{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem .8rem;margin:.35rem 0 0}
.career-facts .career-nation{color:#fff;font-weight:600}
.career-facts .career-nation:hover{color:var(--accent)}
.career-facts .career-editions{color:rgba(255,255,255,.72);font-size:.85rem}
.career-head .tally-lg{display:flex;flex-wrap:wrap;gap:.9rem;margin-block-start:.6rem}
.tally-one{display:inline-flex;align-items:center;gap:.3rem;color:#fff}
.tally-one b{font-weight:800;font-variant-numeric:tabular-nums}
.tally-one i{font-style:normal;font-size:.62rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:rgba(255,255,255,.66)}
/* The merged results table: the medal badge now sits inline with the session it was won
   at, so a podium row reads as one thing instead of two duplicate rows. */
.career-results td.what{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.career-results tr.is-podium td{background:color-mix(in srgb,var(--accent) 8%,var(--surface))}
.athlete-photo{width:8.5rem;height:auto;aspect-ratio:4/5;border-radius:1.2rem;object-fit:cover;object-position:50% 20%}
.photo-credit{margin:0 0 .35rem;font-size:.72rem;color:var(--text-muted)}
.medal-list{list-style:none;padding:0;margin:.5rem 0;display:flex;flex-direction:column;gap:.5rem}
.medal-list li{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;
  padding:.5rem .7rem;background:var(--surface);border:1px solid var(--border);border-radius:.6rem}
.medal-list .who{display:block;color:var(--text-muted);font-size:.9rem}
.medal-list .ml-ath{display:flex;flex-direction:column;gap:.1rem}
.badge-gold{background:#e9c463;color:#111}
.badge-silver{background:#cfd2d6;color:#111}
.badge-bronze{background:#cd9b6a;color:#111}
.athlete-list{list-style:none;padding:0;margin:.5rem 0;display:flex;flex-wrap:wrap;gap:.4rem}
.athlete-list li a{display:inline-block;padding:.35rem .65rem;background:var(--surface);
  border:1px solid var(--border);border-radius:.5rem;color:var(--text-muted)}
.athlete-list li a:hover{border-color:var(--accent);color:var(--text)}
.results{width:100%;border-collapse:collapse;margin-block-start:.5rem}
.results td{padding:.6rem .8rem;border-block-end:1px solid var(--border)}
.results tr:hover{background:color-mix(in srgb,var(--accent) 6%,transparent)}
.results td.rank{color:var(--text-muted);width:2.5rem;text-align:center}
.results td.mark{color:var(--text-muted);text-align:end}
/* judged component breakdown (D/E/PEN… summary from ScoreComponent) — live standings on the
   watch page + the sport-hub standings tab. Sits as a quiet line above the bold total. */
.score-breakdown{display:block;font-size:.72rem;color:var(--text-dim);
  font-variant-numeric:tabular-nums;letter-spacing:.02em}
#live-scores .results td.mark{font-variant-numeric:tabular-nums;font-weight:700;color:var(--text)}
#live-scores .results .results-group th{padding:.9rem .8rem .4rem;text-align:start;font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;color:var(--text-muted);border-block-end:1px solid var(--border)}
#live-scores .results .tag{font-size:.7rem;margin-inline-start:.35rem}
#live-scores .results .who{display:block;color:var(--text-muted);font-size:.8rem;margin-block-start:.15rem}
#live-scores .rail-h .live-dot{margin-inline-start:.5rem}
.results .status{font-size:.75rem;text-transform:uppercase}
/* The championship name above the player's title. .theme-dark scopes the whole watch page,
   so set ink explicitly rather than inheriting the light --text. */
.watch-edition{margin:0 0 .15rem;font-size:.82rem;letter-spacing:.06em;text-transform:uppercase}
.watch-edition a{color:rgba(255,255,255,.72)}
.watch-edition a:hover{color:var(--accent)}
.tag{font-size:.7rem;background:var(--border);color:var(--text-muted);padding:.1rem .4rem;border-radius:.3rem;text-transform:uppercase;letter-spacing:.04em}

/* ---- bout-list (the Match layer: A-vs-B contest cards, broadcast scoreboard) ---- */
.bouts{list-style:none;padding:0;margin:.5rem 0 0;display:flex;flex-direction:column;gap:.55rem}
/* bout-order group headers (Live now / Upcoming / Completed) on the watch page */
.bout-group-h{display:flex;align-items:center;gap:.5rem;margin:1.1rem 0 .2rem;font-family:var(--display);
  text-transform:uppercase;letter-spacing:.06em;font-size:.74rem;color:var(--text-muted)}
.bout-group-h .dot-live{width:.5rem;height:.5rem;border-radius:50%;background:var(--accent);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--accent) 70%,transparent);animation:pulse-live 1.8s ease-out infinite}
@keyframes pulse-live{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--accent) 60%,transparent)}70%{box-shadow:0 0 0 .5rem transparent}100%{box-shadow:0 0 0 0 transparent}}
@media (prefers-reduced-motion:reduce){.bout-group-h .dot-live{animation:none}}
.bout{background:var(--surface);border:1px solid var(--border);border-radius:.7rem;padding:.7rem .85rem;
  display:grid;grid-template-columns:1fr auto;grid-template-areas:"meta meta" "sides actions";
  column-gap:.85rem;row-gap:.5rem;align-items:center}
.bout-live{border-color:color-mix(in srgb,var(--accent) 32%,var(--border))}
.bout-meta{grid-area:meta;display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;min-width:0}
.bout-round{font-size:.72rem;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}
/* event label on cards shown outside their own session (athlete history, sport-code hub) */
.bout-event{font-family:var(--display);font-size:.72rem;text-transform:uppercase;letter-spacing:.05em;color:var(--accent-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:16rem}
.bout-event:hover{text-decoration:underline}
/* piste/court/lane label (the feed) on a bout — FencingTV labels every bout with its piste */
.bout-piste{font-size:.68rem;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);
  border:1px solid var(--border);border-radius:.35rem;padding:.05rem .35rem;white-space:nowrap}
.bout-time{font-size:.72rem;color:var(--text-muted);font-variant-numeric:tabular-nums}
.bout-sides{grid-area:sides;list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.32rem;min-width:0}
.bout-side{display:flex;align-items:center;gap:.6rem;min-width:0}
.bout-who{display:flex;align-items:center;gap:.5rem;flex:1;min-width:0}
.bout-who a{color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bout-flag{width:1.3rem;height:auto;flex:0 0 auto}
.bout-score{font-variant-numeric:tabular-nums;font-weight:700;color:var(--text-muted);min-width:2.5ch;text-align:end}
.bout-side-win .bout-who a{color:var(--accent-ink);font-weight:700}
.bout-side-win .bout-score{color:var(--text)}
.bout-actions{grid-area:actions;justify-self:end}
.bout-watch{display:inline-block;font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;
  font-size:.78rem;font-weight:700;color:var(--accent-ink);white-space:nowrap}
.bout-watch:hover{text-decoration:underline}
@media (max-width:480px){
  .bout{grid-template-columns:1fr;grid-template-areas:"meta" "sides" "actions"}
  .bout-actions{justify-self:start}
}

/* ---- draw: bracket (elimination) + pools/heats — the Tableau+Pools, generalised ---- */
.bracket{display:flex;gap:1.1rem;overflow-x:auto;padding-bottom:.6rem;scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch}
.bracket-col{flex:0 0 clamp(15rem,80vw,19rem);display:flex;flex-direction:column;scroll-snap-align:start}
.bracket-round{font-family:var(--display);text-transform:uppercase;letter-spacing:.07em;font-size:.74rem;
  color:var(--accent-ink);margin:0 0 .5rem;padding-bottom:.4rem;border-bottom:1px solid var(--border)}
/* bracket bouts space out so later (smaller) rounds read as "deeper" in the draw */
.bouts-bracket{flex:1;justify-content:space-around;gap:.7rem}

/* connected single-elim TREE — columns joined by connector lines (the real tableau).
   Per-column space-around means a round of N/2 aligns to the pair-midpoints of N; a vertical
   rail per round + horizontal feed-stubs join them (robust for any number of rounds). */
.bracket-tree{display:flex;overflow-x:auto;padding-bottom:1rem;align-items:stretch;-webkit-overflow-scrolling:touch}
.bt-round{position:relative;display:flex;flex-direction:column;flex:0 0 clamp(15rem,80vw,17.5rem);padding-inline:.9rem}
.bt-round .bracket-round{margin-bottom:.6rem}
.bt-slots{list-style:none;margin:0;padding:0;flex:1;display:flex;flex-direction:column;justify-content:space-around}
/* a bracket slot stacks (meta / sides / action) so the competitor names get the full width */
.bt-slots .bout{position:relative;margin:.4rem 0;grid-template-columns:1fr;
  grid-template-areas:"meta" "sides" "actions"}
.bt-slots .bout-actions{justify-self:start}
/* the round's vertical rail (between this column and the next) */
.bt-round:not(.bt-final)::after{content:"";position:absolute;inset-inline-end:.2rem;top:12%;bottom:12%;
  width:2px;background:var(--border)}
/* feed-stub out of each bout to the rail */
.bt-round:not(.bt-final) .bt-slots .bout::after{content:"";position:absolute;top:50%;inset-inline-start:100%;
  width:.7rem;height:2px;background:var(--border)}
/* feed-stub into each bout from the previous round's rail */
.bt-round:not(:first-child) .bt-slots .bout::before{content:"";position:absolute;top:50%;inset-inline-end:100%;
  width:.7rem;height:2px;background:var(--border)}
.bt-final{justify-content:center}
.bracket-medal-h{margin-top:1.4rem}
/* seed + bye inside a bracket slot */
.bout-seed{display:inline-flex;align-items:center;justify-content:center;min-width:1.35rem;height:1.25rem;
  font-size:.66rem;font-weight:700;font-variant-numeric:tabular-nums;color:var(--text-muted);background:var(--bg);
  border:1px solid var(--border);border-radius:.3rem;flex:0 0 auto}
.bye{color:var(--text-muted);font-style:italic}
@media (max-width:600px){.bt-round{flex-basis:80vw}}
.pool{margin-top:1.6rem}
.pool-h{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;font-size:.95rem;
  margin:0 0 .6rem;color:var(--text)}
.pool-standings{width:100%;border-collapse:collapse;margin-bottom:.7rem;font-size:.9rem;
  background:var(--surface);border:1px solid var(--border);border-radius:.6rem;overflow:hidden}
.pool-standings th,.pool-standings td{padding:.45rem .7rem;text-align:start;border-bottom:1px solid var(--border)}
.pool-standings thead th{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;
  font-size:.68rem;color:var(--text-muted);background:var(--bg)}
.pool-standings tr:last-child td{border-bottom:0}
.pool-standings .rank{width:2rem;color:var(--text-muted);font-variant-numeric:tabular-nums}
.pool-standings .num{text-align:end;font-variant-numeric:tabular-nums;width:3ch}
.pool-standings .num.win{color:var(--accent-ink);font-weight:700}
.pool-standings .who a{color:var(--text)}
.pool-standings tr:first-child .who a{color:var(--accent-ink);font-weight:700}

/* ---- heats / races (athletics, swimming) — ranked lane tables, Heats→Semis→Final ---- */
.race-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(18rem,1fr));gap:1rem}
.race{background:var(--surface);border:1px solid var(--border);border-radius:.7rem;padding:.7rem .85rem}
.race-h{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;
  margin:0 0 .5rem;color:var(--text)}
.race-table{width:100%;border-collapse:collapse;font-size:.9rem}
.race-table th,.race-table td{padding:.4rem .5rem;text-align:start;border-bottom:1px solid var(--border)}
.race-table thead th{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;
  font-size:.66rem;color:var(--text-muted)}
.race-table tr:last-child td{border-bottom:0}
.race-table .lane{width:2.2rem;color:var(--text-muted);font-variant-numeric:tabular-nums;text-align:center}
.race-table .time{text-align:end;font-variant-numeric:tabular-nums;white-space:nowrap}
.race-table .pl{width:2.4rem;text-align:end;font-variant-numeric:tabular-nums;color:var(--text-muted)}
.race-table .who a{color:var(--text)}
.race-table tr.lead .who a,.race-table tr.lead .pl{color:var(--accent-ink);font-weight:700}
.race-table .qual{margin-inline-start:.4rem;font-size:.66rem;font-weight:700;color:var(--accent-ink);
  border:1px solid color-mix(in srgb,var(--accent) 35%,var(--border));border-radius:.3rem;padding:0 .3rem}

/* ---- nation pyramid (the country roll-up per sport code) ---- */
.nation-pyramid{display:grid;grid-template-columns:1fr;gap:.8rem}
.np-group{background:var(--surface);border:1px solid var(--border);border-radius:.7rem;padding:.8rem .9rem}
.np-h{display:flex;align-items:baseline;justify-content:space-between;gap:.6rem;margin:0 0 .55rem;
  font-size:.95rem;font-family:var(--display)}
.np-h>a{display:inline-flex;align-items:baseline;gap:.45rem;color:var(--text)}
.np-h>a:hover{color:var(--accent-ink)}
.np-h .code{font-family:ui-monospace,monospace;font-size:.72rem;font-weight:700;color:var(--accent-ink)}
.np-record{font-family:var(--display);font-size:.7rem;letter-spacing:.04em;color:var(--text-muted);
  white-space:nowrap;font-weight:600}
.np-athletes{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.3rem}
.np-athletes a{color:var(--text-muted)}
.np-athletes a:hover{color:var(--accent-ink)}

/* ---- events index (the channel timeline) ---- */
/* World Gymnastics light (Task 4): .event-spotlight/.event-spotlight-body verified DEAD —
   grep across every template finds zero references (events.html renders .event-grid/.event-card
   directly, no spotlight lead). Removed rather than left to bit-rot (T3 precedent on
   body.page-medals::before); it would also have carried the same "ink pinned to var(--text),
   coincidentally light-on-dark-scrim only under the old dark theme" bug .live-feature just hit,
   had it ever rendered. */
.event-grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fill,minmax(15rem,1fr));margin-block:.5rem 2rem}
.event-card{position:relative;display:block;
  background:linear-gradient(180deg,color-mix(in srgb,var(--surface) 91%,#fff 9%),var(--surface) 60%);
  border:1px solid var(--border);border-radius:.7rem;padding:1.05rem 1.1rem 1.05rem 1.35rem;
  box-shadow:0 10px 26px -20px rgba(0,0,0,.85);
  transition:border-color .18s,transform .18s,box-shadow .18s}
/* Status-coded accent strip — scannable at a glance (live=red, upcoming=lime, ended=muted). */
.event-card::before{content:"";position:absolute;inset-block:0;inset-inline-start:0;inline-size:3px;
  background:var(--accent);opacity:.55;border-start-start-radius:.7rem;border-end-start-radius:.7rem;transition:opacity .18s}
.event-card:has(.badge-live)::before{background:#e5484d;opacity:.9}
.event-card:has(.badge-upcoming)::before{background:var(--accent);opacity:.8}
.event-card:has(.badge-replay)::before{background:var(--text-muted);opacity:.4}
.event-card:hover{border-color:color-mix(in srgb,var(--accent) 70%,var(--border));transform:translateY(-4px);
  box-shadow:0 22px 46px -24px rgba(0,0,0,.95), 0 0 0 1px color-mix(in srgb,var(--accent) 30%,transparent)}
.event-card:hover::before{opacity:1}
.event-card h3{margin:.5rem 0 .25rem;font-size:1.05rem;line-height:1.2;font-family:var(--display);font-weight:700;min-block-size:2.4em}
.event-card .meta{color:var(--text-muted);font-size:.85rem;margin:0;font-variant-numeric:tabular-nums}
.archive-banner{display:flex;flex-wrap:wrap;gap:.5rem 1rem;align-items:center;justify-content:space-between;
  background:var(--surface);border:1px solid var(--border);border-radius:.6rem;padding:.7rem 1rem;margin-block-end:1.5rem;font-size:.92rem}
.archive-banner a{color:var(--accent-ink);font-weight:600;white-space:nowrap}
.all-events-link{margin-block:1rem 0}
.all-events-link a{color:var(--accent-ink);font-weight:600}

/* ===== /vl flare ===== */

/* Image-backed hero (sport hubs, section headers) — reuses the marquee overlay token.
   World Gymnastics light (Task 4): LIVE bug, not dead code — sport.html sets `hero` to the
   sport's first session thumbnail whenever one exists (views.py sport()), so most disciplines
   (verified: rhythmic) render this, not the plain --page-hero poster band. h1 had no explicit
   ink, inheriting var(--text) — indigo-on-near-black over ::after's fixed dark scrim, illegible
   (screenshot: "Rhythmic" unreadable). Same fixed-dark-scrim-regardless-of-theme case as
   .live-feature just above; hardcoded to #fff for the same reason. */
.hero-img{position:relative;overflow:hidden;border-radius:.9rem;padding:2.25rem 1.5rem;
  margin-block:.5rem 1.75rem;background-size:cover;background-position:center;min-height:9rem;
  display:flex;flex-direction:column;justify-content:flex-end;color:#fff}
.hero-img::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(16,18,66,.94),rgba(16,18,66,.45) 60%,rgba(16,18,66,.25))}
.hero-img>*{position:relative;z-index:1}
.hero-img.hero-sm{border-block-end:0}

/* Nations mosaic + sponsor wall — static bands, no motion (client round 1: the rotating
   marquee read as "spinning" and was disliked; with 40+ sponsors a rotation also means "many
   will lose out"). .reel is just the shared bordered-band shell; each band lays out its own
   grid further down (search "Nations mosaic" / "Sponsor wall"). */
.reel{margin:0;border-block:1px solid var(--border);padding-block:1.6rem}
.reel-h{text-align:center;color:var(--accent-ink);font-size:.72rem;text-transform:uppercase;
  letter-spacing:.18em;font-weight:700;margin:0 0 1.15rem;opacity:.85}

/* ===== Premium broadcaster pass (/vl — luxury 80 / esports 20) ===== */
/* Wow from type + art direction + precise motion. No JS, no gradients-as-colour,
   no glass. Everything below is CSS-only and degrades on weak devices. */

/* Display typography — confident broadcast headlines, system-ui body unchanged. */
.eyebrow{font-family:var(--display);color:var(--accent-ink);text-transform:uppercase;
  letter-spacing:.16em;font-size:.78rem;font-weight:700;margin:0 0 .6rem}
.site-header .brand,.footer-brand .brand{font-family:var(--display);font-weight:800;letter-spacing:.01em}
.hero h1{font-family:var(--display);font-weight:800;letter-spacing:-.01em;line-height:1;
  font-size:clamp(2.2rem,5vw,3.6rem)}
.card h3{font-family:var(--display);font-weight:700;letter-spacing:.005em}
.card .meta,.row-time{font-variant-numeric:tabular-nums}

/* Section labels — display caps with a short accent rule (reuses the footer accent-bar idiom). */
.rail h2{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;font-weight:800;
  font-size:1.08rem;color:var(--text);display:flex;align-items:center;gap:.6rem}
.rail h2::before{content:"";flex:0 0 auto;inline-size:.34rem;block-size:1.15rem;
  background:var(--accent);border-radius:2px}

/* Cinematic hero — filmic (drop the gold glow), taller, heavy uppercase display title. */
.marquee{min-height:clamp(20rem,52vw,32rem);border:1px solid var(--border);
  box-shadow:0 30px 80px -42px rgba(0,0,0,.95)}
.marquee::after{background:linear-gradient(to top,rgba(16,18,66,.96),rgba(16,18,66,.45) 58%,rgba(16,18,66,.12))}

/* Interior page headers — photo band in the end-card language (brand hero + static near-black
   var(--bg) duotone) so Sports / Schedule / Athletes / Nations / Medals / Videos / News / Venues
   match the home + footer energy. Pure CSS on the shared .hero-sm header — no per-template markup needed. */
.hero-sm:not(.hero-img){position:relative;overflow:hidden;isolation:isolate;border-block-end:0;
  border-radius:.9rem;margin-block-end:1.75rem;padding:2.9rem 1.9rem;min-block-size:11rem;
  display:flex;flex-direction:column;justify-content:center;color:#fff}
.hero-sm:not(.hero-img)::before{content:"";position:absolute;inset:0;z-index:-1;
  background-image:var(--page-hero, none);background-position:center 26%;background-size:cover}
/* Fidelity pass 2026-07-16: the wash is the reference's deep-indigo photo veil (their home hero,
   image #1) — NOT a white/--bg mix, which read washed-out. Heavier at the text edge, always
   indigo-family, so every interior header is a dark band with white ink like the original. */
.hero-sm:not(.hero-img)::after{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(90deg, rgba(16,18,66,.92), rgba(16,18,66,.62) 55%, rgba(16,18,66,.32) 100%),
  linear-gradient(0deg, rgba(16,18,66,.5), rgba(16,18,66,.05))}
.hero-sm:not(.hero-img) h1{color:#fff}
.hero-sm:not(.hero-img) .hero-lead{color:rgba(255,255,255,.86)}
.hero-sm:not(.hero-img) .eyebrow{color:var(--support)}   /* cyan label on the indigo veil */
/* Ghost watermark word (the reference band's giant translucent "NEWS") — opt-in per page via
   <h1 data-ghost="...">. Sits over the veil, under the real title. */
.hero-sm:not(.hero-img)>*{position:relative;z-index:1}
.hero-sm:not(.hero-img) h1[data-ghost]::before{content:attr(data-ghost);position:absolute;
  inset-inline-start:-.06em;inset-block-end:-.18em;z-index:0;pointer-events:none;
  font-size:clamp(4rem,11vw,8.5rem);font-weight:800;line-height:1;text-transform:uppercase;
  letter-spacing:.01em;color:rgba(255,255,255,.08);white-space:nowrap}
/* World Gymnastics light (Task 3): --text-muted reads invisible in patches of this photo
   band — it's a mid grey, wrong for BOTH the light-washed left zone and the raw photo's
   bright highlights (verified via screenshot on nation/athlete hero — "BUL"/"4 championships"
   were nearly unreadable). .nation-head/.athlete-head only ever render inside this photo-band
   hero (grep-verified — nation_detail.html, athlete_detail.html, athlete_career.html), so it's
   safe to force their muted sub-text to the same light ink .hero-lead already uses, rather
   than the token. h1/.meta (plain --text) and .rank-disc (--accent) stay — already legible.
   Selectors are compounded as `.hero-sm.athlete-head` (NO space — .hero-sm and .athlete-head
   land on the SAME <section>, not nested) purely to out-specificity `.athlete-rank .rank-pts`
   further down the file; `.hero-sm .athlete-head` (with a space) silently never matches. */
.hero-sm.nation-head .code,.hero-sm.athlete-head .code,
.hero-sm.athlete-head .rank-pts,.hero-sm.nation-head .tally-lg,.hero-sm.athlete-head .tally-lg{color:rgba(255,255,255,.86)}
/* .rank-no was missing from the list above, so the big "#4" kept var(--text) on the dark
   photo veil — 1.00:1, i.e. genuinely invisible. Same family as the canvas-ink trap. */
.hero-sm.athlete-head .rank-no{color:#fff}
/* .hero-art (the old IESFTV accent-stripe variant) now renders identically to the base indigo
   band — the raked lime/blue stripes fought the reference's clean veil and are retired. The
   class stays in templates as a harmless no-op. */

/* Consistent image grade — slightly graded by default, wakes to full on hover. */
.poster-img{filter:saturate(.88) contrast(1.05) brightness(.97);transition:filter .3s ease}
.card:hover .poster-img{filter:saturate(1.05) contrast(1.04) brightness(1.02)}

/* Broadcast CTA. */
.btn{font-family:var(--display);text-transform:uppercase;letter-spacing:.06em;font-size:.92rem;
  padding:.62rem 1.3rem;transition:transform .15s ease,filter .15s ease}
.btn:hover{filter:brightness(1.08);transform:translateY(-1px)}
/* World Gymnastics buttons are PILLS (the reference "ALL NEWS" lime pill) — light only;
   .theme-dark keeps the Kinetic .5rem radius so watch/live stay pixel-faithful. */
body:not(.theme-dark) .btn,body:not(.theme-dark) .btn-outline,
body:not(.theme-dark) .apply-btn,body:not(.theme-dark) .searchbar button{border-radius:999px}
/* Secondary/ghost button (e.g. "Create an account" under Sign in) — defined after .btn so
   it wins the cascade. Outlined, not filled, so it reads as the secondary action. */
.btn-ghost{background:transparent;color:var(--accent-ink);border:1px solid var(--accent-ink)}
.btn-ghost:hover{background:color-mix(in srgb,var(--accent) 14%,transparent);filter:none}

/* Brand focus ring everywhere (a11y + identity). */
a:focus-visible,button:focus-visible,summary:focus-visible,input:focus-visible,select:focus-visible{
  outline:2px solid var(--accent-ink);outline-offset:2px;border-radius:.25rem}

/* No scroll-driven fade on rails or grids (Alex, 16 Oct): a tall grid stayed half-transparent
   until scrolled ("cover 16%" of a 2000px grid), so the Nations page opened looking tinted. */
@keyframes vl-rise{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:none}}

/* ===== Rollout: extend the broadcaster identity to every viewer surface ===== */
/* Every page title in the display face (covers watch + any title not in a .hero). */
main h1{font-family:var(--display);font-weight:800;letter-spacing:-.01em}
.prose h1,.prose h2{font-family:var(--display);letter-spacing:-.005em}
/* One section-label vocabulary site-wide: display caps (replaces the all-gold .rail-h text).
   No accent rule in front: it read as an em dash (Alex, 18 Oct). */
.rail-h{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;font-weight:700;
  font-size:1rem;color:var(--text);display:flex;align-items:center;gap:.6rem;margin:1.75rem 0 .9rem}
/* Event heading on a sport mini-site — one per (weapon × gender), e.g. "Women's Foil". A
   higher-order divider than the .rail-h sub-labels inside it, so a multi-event sport (fencing)
   reads as distinct events rather than one jumbled draw. */
.event-h{font-family:var(--display);font-size:1.3rem;font-weight:700;letter-spacing:-.01em;
  line-height:1.2;color:var(--text);margin:2rem 0 1rem;padding-inline-start:.7rem;
  border-inline-start:4px solid var(--accent)}
.stab-panel>.event-h:first-of-type{margin-block-start:.6rem}
@media (max-width:30rem){.event-h{font-size:1.12rem;margin:1.5rem 0 .85rem}}
/* Schedule day headers + small labels in the display face for cohesion. */
.day-h{font-family:var(--display);text-transform:uppercase;letter-spacing:.03em}
.medals th,.picker-label,.tag,.sponsors-label,.reel-h,.footer-col h3{font-family:var(--display)}

/* Bespoke medal icons (generated, transparent) — replace the 🥇🥈🥉 emoji. */
.medal-ico{height:1.15em;width:auto;vertical-align:-.2em;display:inline-block}
.medals th .medal-ico{height:1.5rem;vertical-align:middle}
.tally .medal-ico{height:1em;vertical-align:-.15em}
@media (prefers-reduced-motion:no-preference){
  .medal-ico{animation:medalGleam 3.4s ease-in-out infinite}
  @keyframes medalGleam{0%,70%,100%{filter:brightness(1)}82%{filter:brightness(1.5) saturate(1.15) drop-shadow(0 0 3px rgba(255,255,255,.6))}}
}

/* Email-verify banner + deletion-pending notice */
.verify-banner{display:flex;flex-wrap:wrap;gap:.5rem 1rem;align-items:center;justify-content:space-between;
  background:var(--surface);border:1px solid var(--border);border-inline-start:3px solid var(--accent);
  border-radius:.5rem;padding:.6rem .9rem;margin-block-end:1.25rem;font-size:.9rem;color:var(--text)}
.verify-banner form{margin:0}
.verify-banner a{color:var(--accent-ink);font-weight:600;white-space:nowrap}
.delete-pending{border:1px solid #d29922;border-radius:.6rem;padding:1rem 1.1rem}
.delete-pending h2{margin-block-start:0}

/* Live: per-sport category shelves — swipeable rows, broadcast 'shelf' pattern. */
.shelf{margin-block-end:1.75rem}
.shelf-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
  border-block-end:1px solid var(--border);padding-block-end:.5rem;margin-block-end:.9rem}
.shelf-title{font-family:var(--display);text-transform:uppercase;letter-spacing:.03em;font-weight:700;
  font-size:1.1rem;margin:0}
.shelf-more{color:var(--accent-ink);font-weight:600;font-size:.82rem;white-space:nowrap;flex:0 0 auto}
.shelf-more:hover{text-decoration:underline}
/* overflow-x:auto forces overflow-y:auto, which clips the card hover-lift at the top.
   The -.5rem margin / +.5rem padding pair adds internal top clip-room with zero net
   layout shift (cards stay put; the box just extends up into the header's margin gap). */
.shelf-row{list-style:none;margin:-.5rem 0 0;padding:.5rem 0 .6rem;display:flex;gap:1rem;overflow-x:auto;
  scroll-snap-type:x proximity;scrollbar-width:thin}
.shelf-row .card{flex:0 0 15rem;scroll-snap-align:start}
.card-time{color:var(--text);font-variant-numeric:tabular-nums}
/* the live matchup line on a /live hub card (the current contest, not just the sport) */
.card-bout{display:flex;align-items:center;flex-wrap:wrap;gap:.4rem;margin:.1rem .85rem .85rem;
  font-size:.82rem;color:var(--text)}
.card-bout .cb-side{display:inline-flex;align-items:center;gap:.3rem;min-width:0}
.card-bout .cb-side b{font-variant-numeric:tabular-nums;color:var(--accent-ink)}
.card-bout .vs{color:var(--text-muted);font-size:.7rem;text-transform:uppercase}
@media (prefers-reduced-motion:no-preference){.shelf-row{scroll-behavior:smooth}}

/* Live hub — broadcast hierarchy. One featured field-of-play (cinematic, like a mini
   marquee), then a compact "also live" shelf, then an "up next" timeline list.
   World Gymnastics light (Task 4): this card is SHARED across live.html (.theme-dark,
   sacred) and videos.html/news_list.html (light) — always sits on the fixed dark photo
   scrim below (::after, not theme-dependent), so its ink was pinned to var(--text) which
   read fine by coincidence while --text was near-white (dark theme) but goes illegible
   (indigo-on-near-black) now --text is indigo on light. Hardcoded to #fff, same convention
   already used for text-on-photo elsewhere (.footer-statement, .sport-card-link) — always
   correct regardless of theme, imperceptible change on .theme-dark (was #f5f5f3). */
.live-feature{position:relative;display:flex;align-items:flex-end;text-decoration:none;color:#fff;
  min-block-size:clamp(15rem,34vw,22rem);border-radius:.9rem;overflow:hidden;border:1px solid var(--border);
  background:var(--surface) center/cover no-repeat;margin-block-end:1.75rem;
  box-shadow:0 30px 80px -42px rgba(0,0,0,.95);transition:transform .18s ease,border-color .18s ease}
.live-feature:hover{transform:translateY(-3px);border-color:color-mix(in srgb,var(--accent) 70%,var(--border));
  box-shadow:0 30px 80px -42px rgba(0,0,0,.95), 0 0 0 1px color-mix(in srgb,var(--accent) 45%,transparent), 0 0 38px -10px color-mix(in srgb,var(--accent) 38%,transparent)}
.live-feature::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(16,18,66,.95),rgba(16,18,66,.35) 58%,rgba(16,18,66,.05))}
.live-feature .lf-body{position:relative;z-index:1;padding:1.5rem 1.6rem 1.7rem;max-inline-size:40rem}
.lf-eyebrow{font-family:var(--display);text-transform:uppercase;letter-spacing:.08em;font-size:.76rem;
  color:rgba(255,255,255,.82);margin:.55rem 0 .2rem}
.lf-title{font-family:var(--display);font-weight:800;text-transform:uppercase;letter-spacing:-.01em;
  line-height:1;font-size:clamp(1.6rem,3.8vw,2.8rem);margin:0 0 .55rem}
.lf-bout{display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;margin:.1rem 0 .95rem;font-size:.98rem}
.lf-bout .cb-side{display:inline-flex;align-items:center;gap:.3rem}
.lf-bout .cb-side b{color:var(--accent);font-variant-numeric:tabular-nums}
.lf-bout .vs{color:rgba(255,255,255,.65);font-size:.72rem;text-transform:uppercase}
.lf-meta{color:rgba(255,255,255,.82);margin:.1rem 0 .95rem;font-variant-numeric:tabular-nums}
.live-feature .btn{align-self:flex-start}

/* Up next (/live page) — a tight timeline, deliberately NOT cards (cards here read as
   filler). Shared base classes also feed the home Up-next card below, which scopes its
   own layout under .un-card so the two components' differing row shapes don't collide. */
.up-next{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}
.un-row{display:flex;align-items:center;gap:1rem;padding:.7rem .9rem;border-radius:.6rem;color:var(--text);
  background:color-mix(in srgb,var(--surface) 70%,transparent);border:1px solid var(--border);
  border-inline-start:3px solid color-mix(in srgb,var(--accent) 50%,var(--border));
  transition:border-inline-start-color .15s,background .15s}
.un-row:hover{border-inline-start-color:var(--accent);background:var(--surface)}
.un-time{font-family:var(--display);font-weight:700;font-variant-numeric:tabular-nums;color:var(--accent-ink);
  min-inline-size:3.1rem}
.un-main{display:flex;flex-direction:column;gap:.1rem;min-inline-size:0;flex:1}
.un-title{font-weight:600;line-height:1.2}
.un-meta{color:var(--text-muted);font-size:.82rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.un-date{color:var(--text-muted);font-size:.82rem;font-variant-numeric:tabular-nums;white-space:nowrap}
@media (max-width:34rem){.un-date{display:none}}

/* Home Up-next card (Task 10) — a divided list inside one panel, distinct row shape
   (time / title+sub / add-to-calendar) from the /live timeline above,
   so everything is scoped under .un-card rather than overriding the shared .un-row bases. */
.un-card{background:color-mix(in srgb,var(--surface) 70%,transparent);border:1px solid var(--border);
  border-radius:.7rem;overflow:hidden}
.un-card .un-row{display:grid;grid-template-columns:88px 1fr auto;align-items:center;gap:1rem;
  padding:.85rem 1rem;border-radius:0;border:0;border-block-end:1px solid var(--border);
  transition:background .15s}
.un-card .un-row:last-child{border-block-end:0}
.un-card .un-row:hover{background:color-mix(in srgb,var(--surface) 92%,transparent)}
.un-card .un-time{font-weight:800;font-size:22px;min-inline-size:0}
.un-card .un-meta{display:flex;flex-direction:column;gap:.15rem;min-inline-size:0;
  color:inherit;font-size:inherit;white-space:normal;overflow:visible;text-overflow:clip}
.un-card .un-title{font-weight:600;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.un-card .un-sub{color:var(--text-muted);font-size:.82rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.un-cal{font-size:.72rem;padding-inline:.9rem;padding-block:.42rem;white-space:nowrap}
@media (max-width:34rem){
  .un-card .un-row{grid-template-columns:56px 1fr;row-gap:.5rem}
  .un-cal{grid-column:1/-1;justify-self:start}
}

/* Today's schedule strip (client round 1 item 4) — sits right after the Rewatch rail, above
   the athlete band, and carries its own FIG-blue var(--primary) header so it can't be
   mistaken for athlete detail (which uses the gold --accent + a portrait layout). The .un-card
   row list underneath is untouched; only the header + outer wrapper are new.
   World Gymnastics light (Task 4): this bare `.sched-head` selector collided with the UNRELATED
   `.sched-head` at the top of the file (the "← All days"/pills row in _schedule_grid.html,
   included on /schedule/'s list view AND sport.html's Schedule tab) — same specificity, this
   rule (declared later) won every shared property, so the schedule list's nav row rendered as a
   solid FIG-blue bar with near-invisible text (screenshot: "Rhythmic" sport detail page). Scoped
   to `.sched .sched-head` (this component's real DOM — .sched-head is always inside `<section
   class="sched">` per _up_next.html) so it only ever matches the home/up-next strip again. */
.sched{margin-block-end:clamp(1.75rem,4.5vh,2.75rem)}
.sched .sched-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  background:var(--primary);color:var(--on-accent);
  border-start-start-radius:.7rem;border-start-end-radius:.7rem;padding:.9rem 1.1rem}
.sched-eyebrow{display:block;font-family:var(--display);text-transform:uppercase;letter-spacing:.14em;
  font-size:.68rem;opacity:.8;margin:0 0 .15rem}
.sched-date{font-family:var(--display);font-weight:700;font-variant-numeric:tabular-nums;
  text-transform:uppercase;letter-spacing:.03em;font-size:.85rem;white-space:nowrap}
.sched .un-card{border-start-start-radius:0;border-start-end-radius:0}

/* Athletes — face-card grid (ODF) */
.athlete-filters{display:flex;gap:.6rem;flex-wrap:wrap;align-items:end;margin-block:1rem 1.5rem;
  padding:.85rem 1rem;background:color-mix(in srgb,var(--surface) 70%,transparent);
  border:1px solid var(--border);border-radius:.7rem}
.athlete-filters input,.athlete-filters select{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:.5rem;padding:.5rem .7rem;font:inherit}
.athlete-filters input{flex:1 1 14rem;max-inline-size:24rem}
/* FIG-blue active state (spec §4 nav/filter convention) — was --accent (coral, the CTA
   color); hover/focus on a filter FIELD is a selection state, not a call to action, so it
   takes --primary like the nav's own hover ink. The Filter button itself stays coral (CTA). */
.athlete-filters input:hover,.athlete-filters select:hover,
.athlete-filters input:focus-visible,.athlete-filters select:focus-visible{border-color:var(--primary)}
.athlete-filters button{background:var(--accent);color:var(--on-accent);border:0;border-radius:.5rem;padding:.5rem 1.1rem;font-weight:700;cursor:pointer;transition:box-shadow .15s}
.athlete-filters button:hover{box-shadow:var(--glow-cta)}
.athlete-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:1.25rem}
/* phones: force 2-up nation/athlete cards (placed AFTER the base grid rules so it wins —
   @media adds no specificity, only source order does). */
@media (max-width:30rem){
  .nation-grid{grid-template-columns:repeat(2,1fr);gap:.7rem}
  .nation-card{padding:1.1rem .6rem}
  .nation-card .flag{width:3rem}
  .athlete-grid{grid-template-columns:repeat(2,1fr);gap:.7rem}
}
/* White card + soft --shadow-card at rest, --glow-card on hover — same grammar as .nation-card. */
.athlete-card{position:relative;display:flex;flex-direction:column;align-items:stretch;gap:.55rem;padding:0 0 .9rem;overflow:hidden;background:var(--surface);border:1px solid var(--border);border-radius:.9rem;text-align:center;box-shadow:var(--shadow-card);transition:border-color .15s,transform .15s,box-shadow .15s}
.athlete-card:hover{border-color:var(--accent);transform:translateY(-2px);box-shadow:var(--glow-card)}
/* world-ranking chip on the face card */
.athlete-card .rank-badge{position:absolute;top:.5rem;inset-inline-start:.5rem;font-family:ui-monospace,monospace;
  font-size:.68rem;font-weight:700;color:var(--accent-ink);background:color-mix(in srgb,var(--accent) 14%,var(--surface));
  border:1px solid color-mix(in srgb,var(--accent) 30%,var(--border));border-radius:.4rem;padding:.08rem .35rem;line-height:1.3}
/* athlete page ranking strip — the visible top of the pyramid (FencingTV 'FD #1 · pts') */
.athlete-rank{display:flex;flex-wrap:wrap;align-items:baseline;gap:.6rem;margin:0 0 .35rem}
.athlete-rank .rank-disc{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;font-size:.74rem;color:var(--accent-ink)}
.athlete-rank .rank-disc:hover{text-decoration:underline}
.athlete-rank .rank-no{font-family:var(--display);font-size:1.5rem;font-weight:800;line-height:1;color:var(--text)}
.athlete-rank .rank-pts{font-variant-numeric:tabular-nums;color:var(--text-muted);font-size:.85rem}
/* Full-width square portrait flush to the card top (no circle). World Gymnastics light
   (Task 3): re-inked from color-mix(--bg 24%,--surface) — a near-white-on-white no-op once
   both tokens are white — to --bg-raised, a visible light-grey tile the monogram sits on. */
.athlete-card .face{width:100%;aspect-ratio:4/5;border-radius:0;overflow:hidden;display:grid;place-items:center;background:var(--bg-raised)}
.athlete-card .face img{width:100%;height:100%;object-fit:cover;object-position:50% 20%}
/* Monogram fallback: a flat full-bleed initial, NOT a circle (override the generic .monogram).
   Re-inked indigo-on-light-grey (was an accent-tinted mix that read as a coral wash on white). */
.athlete-card .monogram{width:100%;height:100%;border:0;border-radius:0;background:transparent;font-family:var(--display);font-weight:800;font-size:3.4rem;color:var(--text)}
.athlete-card .a-name{font-weight:600;font-size:1rem;line-height:1.2;padding-inline:.55rem;margin-top:.15rem}
.athlete-card .a-nation{font-size:.82rem;color:var(--text-muted);padding-inline:.55rem}
.result-count{color:var(--text-muted);font-size:.78rem;margin:.2rem 0 .8rem;
  font-family:var(--display);text-transform:uppercase;letter-spacing:.06em}
.pagination{display:flex;align-items:center;justify-content:center;gap:1rem;margin-block:1.6rem .5rem;flex-wrap:wrap}
.pagination .page-link{color:var(--accent-ink);font-weight:600;border:1px solid var(--border);border-radius:.5rem;padding:.45rem .9rem}
.pagination .page-link:hover{border-color:var(--accent)}
.pagination .page-link.is-disabled{color:var(--text-muted);opacity:.45;pointer-events:none}
/* aria-current="page" gets a visible FIG-blue treatment (was flat --text-muted grey — legible
   but didn't read as "the current state" among two link-colored neighbours). */
.pagination .page-cur{color:var(--primary);font-weight:700;font-size:.9rem;font-variant-numeric:tabular-nums}

/* Sports Codes — ODF Sport→Discipline→Event tree */
.code-tree{display:flex;flex-direction:column;gap:.5rem;max-width:60rem}
.code-sport,.code-disc{border:1px solid var(--border);border-radius:.6rem;background:var(--surface);overflow:hidden}
.code-disc{margin:.5rem .75rem;background:var(--bg)}
.code-tree summary{cursor:pointer;padding:.7rem 1rem;display:flex;align-items:center;gap:.7rem;font-weight:600}
.code-sport>summary{font-family:var(--display);text-transform:uppercase;letter-spacing:.02em}
.code-tree .code{display:inline-block;min-width:3.4rem;font-family:ui-monospace,monospace;font-size:.78rem;font-weight:700;color:var(--accent-ink);background:var(--bg);border:1px solid var(--border);border-radius:.35rem;padding:.1rem .4rem;text-align:center}
.code-events{list-style:none;margin:0;padding:.3rem .9rem .8rem 1.4rem;display:flex;flex-direction:column;gap:.4rem}
.code-events li{display:flex;align-items:center;gap:.7rem;font-size:.9rem;color:var(--text-muted)}
.code-name{color:var(--text)}
/* index → hub: each code row is a link into its mini-site, keeping the tree's chrome */
.code-link{display:flex;align-items:center;gap:.7rem;color:inherit;flex:1;min-width:0}
.code-link:hover .code-name{color:var(--accent-ink)}

/* ---- sport-code hub (each ODF code as a FencingTV-style competition hub) ---- */
/* Breadcrumb — shared vocabulary (sport-code hub + nation/athlete detail + career). A slim
   back-affordance above the page hero; logical spacing, RTL-safe. */
.crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;font-size:.8rem;color:var(--text-muted);margin-block-end:.5rem}
.crumbs a{color:var(--text-muted)}
.crumbs a:hover{color:var(--accent-ink)}
.crumbs .sep{opacity:.45}
.crumbs [aria-current]{color:var(--text-soft)}
.career-when{color:var(--text-muted);font-family:var(--display);font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
.sportcode-head h1 .code{display:inline-block;font-family:ui-monospace,monospace;font-size:.6em;font-weight:700;color:var(--accent-ink);background:var(--bg);border:1px solid var(--border);border-radius:.4rem;padding:.12rem .5rem;vertical-align:middle;margin-inline-end:.5rem}
.code-children{list-style:none;padding:0;margin:1rem 0 0;display:flex;flex-wrap:wrap;gap:.5rem}
.code-children a{display:inline-flex;align-items:center;gap:.5rem;background:var(--surface);border:1px solid var(--border);border-radius:.5rem;padding:.35rem .65rem;color:var(--text);font-size:.85rem}
.code-children a:hover{border-color:var(--accent)}
.code-children .code{font-family:ui-monospace,monospace;font-size:.72rem;font-weight:700;color:var(--accent-ink)}

/* Athlete page — bio strip (ODF) */
.athlete-bio{list-style:none;display:flex;flex-wrap:wrap;gap:1.6rem;margin:.8rem 0 0;padding:0}
.athlete-bio li{display:flex;flex-direction:column;gap:.1rem}
.athlete-bio .k{font-size:.72rem;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}
.athlete-bio .v{font-weight:600}
.athlete-bio .v.code{font-family:ui-monospace,monospace;color:var(--accent-ink)}

/* Sports index — big poster cards, 3 per row */
/* Capped track + centering so a lone discipline card doesn't strand left of a wide empty
   row (auto-fill would keep empty tracks); many cards still tile cleanly. */
.sport-cards{list-style:none;margin:1rem 0 0;padding:0;display:grid;gap:1.2rem;justify-content:center;
  grid-template-columns:repeat(auto-fill,minmax(15rem,18rem))}
@media (max-width:860px){.sport-cards{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.sport-cards{grid-template-columns:1fr}}
.sport-card{position:relative;aspect-ratio:3/4;border-radius:1rem;overflow:hidden;border:1px solid var(--border);background:var(--surface);transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease}
.sport-card:hover{transform:translateY(-5px);border-color:var(--accent);box-shadow:0 0 0 1px var(--accent),0 0 26px -2px color-mix(in srgb,var(--accent) 78%,transparent),0 0 60px -6px color-mix(in srgb,var(--accent) 48%,transparent),0 24px 52px -26px rgba(0,0,0,.82)}
.sport-card[hidden]{display:none}

/* Sports index — top filter (search + jump-to-a-sport name chips) */
.sports-filter{margin:1.3rem 0 1.5rem}
.sports-filter-input{inline-size:100%;max-inline-size:30rem;padding:.65rem .95rem;background:var(--surface);border:1px solid var(--border);border-radius:.6rem;color:var(--text);font-size:.95rem}
.sports-filter-input::placeholder{color:var(--text-muted)}
.sports-filter-input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 30%,transparent)}
.sport-facets{display:flex;flex-wrap:wrap;gap:.4rem;margin-block-start:.85rem}
.facet{font:inherit;font-size:.82rem;font-weight:600;color:var(--text-muted);background:var(--surface);border:1px solid var(--border);border-radius:999px;padding:.35rem .9rem;cursor:pointer;transition:color .12s ease,border-color .12s ease,background .12s ease}
.facet:hover{color:var(--text);border-color:var(--accent)}
.facet-on{color:var(--accent-ink);border-color:var(--accent-ink);background:color-mix(in srgb,var(--accent) 14%,var(--surface))}
/* search + custom themed sport dropdown (CSS-only <details>, not a native OS select) */
/* stacked: search on top, full-width Browse button below; panel opens big + page-wide */
.sports-controls{display:flex;flex-direction:column;gap:.6rem}
.sports-controls .sports-filter-input{inline-size:100%;max-inline-size:none}
.sport-dd{inline-size:100%}
.sport-dd>summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:.55rem;inline-size:100%;
  background:var(--surface);border:1px solid var(--border);border-radius:.6rem;padding:.7rem 1rem;color:var(--text);font-weight:600;font-size:.92rem}
.sport-dd>summary::-webkit-details-marker{display:none}
.sport-dd>summary::after{content:"";inline-size:.5rem;block-size:.5rem;border-right:2px solid var(--text-muted);border-bottom:2px solid var(--text-muted);transform:translateY(-2px) rotate(45deg);transition:transform .15s ease;flex:0 0 auto}
.sport-dd:hover>summary{border-color:var(--accent)}
.sport-dd[open]>summary{border-color:var(--accent-ink);color:var(--accent-ink)}
.sport-dd[open]>summary::after{transform:translateY(1px) rotate(-135deg);border-color:var(--accent)}
.sport-dd-panel{margin-block-start:.55rem;background:var(--surface);border:1px solid var(--border);border-radius:.7rem;padding:.6rem;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(10rem,1fr));gap:.2rem}
.sport-dd-panel a{display:flex;align-items:center;gap:.35rem;padding:.6rem .7rem;border-radius:.45rem;color:var(--text);font-size:.9rem}
.sport-dd-panel a:hover{background:color-mix(in srgb,var(--accent) 16%,var(--surface));color:var(--accent-ink)}
.dd-live{inline-size:.45rem;block-size:.45rem;border-radius:50%;background:#e5484d;flex:0 0 auto}

/* Watch page — session programme grouped by field-of-play feed */
.prog-intro{color:var(--text-muted);font-size:.88rem;margin:.2rem 0 1rem}
/* Watch — court switcher (each feed + its current matchup) + scoreboard, under the player */
.court-row{display:flex;gap:.6rem;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:thin;margin-block-start:.8rem;padding-block:.2rem}
.court-card{flex:0 0 auto;min-inline-size:13rem;max-inline-size:18rem;text-align:start;cursor:pointer;background:var(--surface);border:1px solid var(--border);border-radius:.6rem;padding:.6rem .75rem;color:var(--text);display:flex;flex-direction:column;gap:.35rem;transition:border-color .15s,background .15s}
.court-card:hover{border-color:var(--accent)}
.court-on{border-color:var(--accent-ink);background:color-mix(in srgb,var(--accent) 12%,var(--surface))}
.court-top{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.court-name{font-family:var(--display);text-transform:uppercase;letter-spacing:.03em;font-size:.82rem;font-weight:700}
.court-on .court-name{color:var(--accent-ink)}
.court-live{display:inline-flex;align-items:center;gap:.3rem;font-size:.66rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#e5484d}
.court-match{display:flex;align-items:center;gap:.4rem;font-size:.86rem;flex-wrap:wrap}
.court-match .vs{color:var(--text-muted);font-size:.74rem;font-style:italic}
.court-match .cm-side{display:inline-flex;align-items:center;gap:.25rem;min-inline-size:0}
.court-match .cm-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-inline-size:6.5rem}
.court-empty{color:var(--text-muted);font-size:.82rem}
.scoreboard{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:1.6rem;margin-block-start:.8rem;padding:1rem 1.6rem;background:var(--surface);border:1px solid var(--border);border-radius:.7rem}
.sb-team{display:flex;align-items:center;gap:.6rem;min-inline-size:0}
.sb-right{justify-content:flex-end;text-align:end}
.sb-name{font-weight:700;font-size:1.05rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sb-win .sb-name{color:var(--accent-ink)}
.sb-nums{display:flex;align-items:center;gap:.7rem;font-family:var(--display);font-weight:800;font-size:2.1rem;font-variant-numeric:tabular-nums;white-space:nowrap}
.sb-dash{color:var(--text-muted);font-weight:400}
.sb-meta{grid-column:1 / -1;text-align:center;color:var(--text-muted);font-size:.78rem;margin-block-start:.1rem}
.scoreboard .flag-lg{width:2.1rem;flex:0 0 auto}
/* Phones: stack the live-feed cards full-width instead of a horizontal-scroll row — a
   peeking half-card at the viewport edge read as "cut off". (Desktop already stacks them
   in the sidebar.) */
@media (max-width:34rem){.sb-nums{font-size:1.4rem}.sb-name{font-size:.84rem}.scoreboard{gap:.5rem;padding:.7rem .8rem}.scoreboard .flag-lg{width:1.6rem}
  .court-row{flex-direction:column;overflow-x:visible;-webkit-overflow-scrolling:auto}
  .court-card{min-inline-size:0;max-inline-size:none;inline-size:100%}
  .court-match .cm-name{max-inline-size:none}}
.court-h{display:flex;align-items:center;gap:.4rem;font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;font-size:.76rem;font-weight:700;color:var(--text-muted);margin:.9rem 0 .45rem}
/* The watch rail = main feeds (courts) + their sub-feeds, stacked. On mobile it flows under
   the video; on desktop it becomes the right-hand sidebar (below). */
.watch-rail{display:flex;flex-direction:column;gap:1.1rem;margin-block-start:1rem}
/* desktop: the watch grid (player | side rail) lives in rotterdam.css, "g5 Watch page, YouTube-style".
   In the rail the court cards stack. */
@media (min-width:64rem){
  .watch-rail #court-switcher .court-h{margin-block-start:0}
  .watch-rail #court-switcher .court-row{flex-direction:column;overflow:visible;margin-block-start:0;max-block-size:none}
  .watch-rail #court-switcher .court-card{min-inline-size:0;max-inline-size:none;inline-size:100%}
  .watch-rail #pickers .picker{margin-block-start:0}
}
.feed-prog{margin-block-end:1.4rem;border:1px solid var(--border);border-radius:.7rem;overflow:hidden;background:var(--surface)}
.feed-prog-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.7rem .9rem;background:var(--bg);border-block-end:1px solid var(--border)}
.feed-prog-name{font-family:var(--display);text-transform:uppercase;letter-spacing:.03em;font-size:.95rem;margin:0}
.feed-prog-watch{flex:0 0 auto}
.prog-list{list-style:none;margin:0;padding:0}
.prog-row{padding:.75rem .95rem;border-block-start:1px solid var(--border)}
.prog-row:first-child{border-block-start:0}
.prog-live{background:color-mix(in srgb,var(--accent) 8%,transparent)}
/* Match line as a mini-scoreboard: team 1 (left) · score · v · score · team 2 (right). */
.prog-match{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:.6rem}
.pm-side{display:flex;align-items:center;gap:.45rem;min-inline-size:0}
.pm-left .pm-name{flex:1;text-align:start}
.pm-right .pm-name{flex:1;text-align:end}
.pm-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pm-name a{color:inherit}
.pm-score{flex:0 0 auto;font-family:var(--display);font-weight:800;font-variant-numeric:tabular-nums;font-size:1.1rem}
.pm-v{flex:0 0 auto;color:var(--text-muted);font-style:italic;font-size:.78rem}
.pm-win .pm-name{color:var(--accent-ink)}
.pm-win .pm-score{color:var(--accent-ink)}
.pm-bye{color:var(--text-muted);font-size:.82rem}
.prog-match-multi{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}
.prog-match-multi .pm-win{font-weight:700;color:var(--accent-ink)}
.prog-foot{display:flex;align-items:center;justify-content:center;gap:.6rem;margin-block-start:.5rem;color:var(--text-muted);font-size:.76rem}
.prog-time{font-variant-numeric:tabular-nums}
.prog-round{border:1px solid var(--border);border-radius:.3rem;padding:.05rem .4rem}
.prog-go{white-space:nowrap}
@media (max-width:34rem){.prog-match{gap:.4rem}.pm-score{font-size:.98rem}.pm-name{font-size:.9rem}}

/* Page loader — a 3s splash that rotates the partner logos, then fades to reveal the page.
   Pure CSS: time-based, so it self-dismisses even with JS disabled. */
.page-loader{position:fixed;inset:0;z-index:1000;display:grid;place-items:center;background:var(--bg);animation:plOut .5s ease 2.25s forwards}
.pl-inner{display:flex;flex-direction:column;align-items:center;gap:1rem;padding:1.5rem;text-align:center}
.pl-spinner{inline-size:3rem;block-size:3rem;border-radius:50%;border:3px solid color-mix(in srgb,var(--text) 14%,transparent);border-block-start-color:var(--accent);animation:plSpin .8s linear infinite}
.pl-loading{font-family:var(--display);text-transform:uppercase;letter-spacing:.14em;font-size:.92rem;color:var(--text)}
.pl-loading::after{content:"";animation:plDots 1.4s steps(1,end) infinite}
.pl-sponsor{display:flex;flex-direction:column;align-items:center;gap:.55rem;margin-block-start:.5rem;opacity:0;animation:plFade .5s ease .25s forwards}
.pl-sponsor-label{font-size:.64rem;text-transform:uppercase;letter-spacing:.2em;color:var(--text-muted)}
.pl-sponsor-logo{font-family:var(--display);font-weight:800;font-size:1.3rem;color:var(--text)}
.pl-sponsor-logo img{max-block-size:2.6rem;max-inline-size:min(62vw,15rem);object-fit:contain;display:block}
@keyframes plSpin{to{transform:rotate(360deg)}}
@keyframes plDots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}
@keyframes plFade{to{opacity:1}}
@keyframes plOut{to{opacity:0;visibility:hidden}}
@media (prefers-reduced-motion:reduce){.page-loader{display:none}}
.sport-card-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.sport-card::after{content:"";position:absolute;inset:0;pointer-events:none;background:linear-gradient(to top,rgba(8,8,10,.92),rgba(8,8,10,.2) 55%,rgba(8,8,10,0))}
.sport-card-link{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:flex-end;text-decoration:none;color:#fff}
.sport-card-body{position:relative;z-index:1;padding:1rem 1.1rem}
.sport-card-name{display:block;font-family:var(--display);font-weight:800;text-transform:uppercase;letter-spacing:.02em;font-size:1.4rem;line-height:1.04}
.sport-card-meta{display:block;margin-block-start:.3rem;color:rgba(255,255,255,.74);font-size:.82rem}
.sport-card-live{position:absolute;inset-block-start:.7rem;inset-inline-end:.7rem;z-index:1}

/* Sport mini-site — section nav (the "links" bar) */
.sport-nav{display:flex;flex-wrap:wrap;gap:.4rem;padding:.55rem 0;margin-block-end:1.1rem;border-block-end:1px solid var(--border)}
.sport-nav a{font-family:var(--display);text-transform:uppercase;letter-spacing:.05em;font-size:.76rem;font-weight:700;color:var(--text-muted);padding:.35rem .75rem;border-radius:.5rem;text-decoration:none;transition:color .12s ease,background .12s ease}
.sport-nav a:hover{color:var(--accent-ink);background:var(--surface)}
/* Smooth, oriented in-page jumps: glide to a section and clear the sticky header. */
@media (prefers-reduced-motion: no-preference){html{scroll-behavior:smooth}}
.rail-h[id]{scroll-margin-block-start:5rem}
.sec-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;flex-wrap:wrap;scroll-margin-block-start:5rem}
.sec-h{font-family:var(--display);text-transform:uppercase;letter-spacing:.03em;font-weight:700;
  font-size:1.1rem;margin:0}
.sec-more{color:var(--accent-ink);font-weight:600;font-size:.85rem;white-space:nowrap}
.sec-more:hover{text-decoration:underline}
/* band reused mid-page, not just the footer */
main .reel{margin-block:1.8rem}

/* Nations mosaic (flags are data, not grayscaled) — a wrapped, centred row of every
   participating flag, once each. Flex-wrap is the simplest robust "centre regardless of count"
   layout for many same-size icons; hover-scale (top of file, .reel-flags .flag-link) is the
   only motion. */
.mosaic .reel-h{margin-block-end:.3rem}
.mosaic-count{text-align:center;color:var(--text-muted);font-size:.85rem;margin:0 0 1.35rem}
.mosaic-grid{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;
  gap:1.15rem 1.5rem;max-inline-size:64rem;margin-inline:auto;padding-inline:1.25rem}
.mosaic-grid .flag-img{filter:none;height:3.7rem;width:auto;border-radius:6px;
  box-shadow:0 5px 14px -2px rgba(16,18,66,.34),inset 0 0 0 1px rgba(0,0,0,.07);
  transition:box-shadow .15s ease}
.reel-flags .flag-link:hover .flag-img{box-shadow:0 10px 20px -6px rgba(16,18,66,.30),inset 0 0 0 1px rgba(0,0,0,.08)}
.mosaic-more{display:block;text-align:center;margin-block-start:1.25rem;color:var(--accent-ink);
  font-weight:600;font-size:.85rem}
.mosaic-more:hover{text-decoration:underline}

/* Sponsor wall — a self-centring grid: auto-fit + a bounded (not 1fr) track size collapses
   unused tracks, so today's 2 logos sit as a small centred pair instead of stretching across
   the row, while 40+ wrap into a proper multi-row wall. Capped + centred so it can't run
   edge-to-edge on a wide screen (this template also renders full-bleed in the footer slot). */
.wall-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,180px));
  justify-content:center;align-items:center;gap:1.5rem 2rem;
  max-inline-size:60rem;margin-inline:auto;padding-inline:1.25rem}
/* Light partners: both CURRENTLY wired logos ship as WHITE monochrome PNGs (invisible on the
   white band). On light they sit on a soft card tile (spec §4 card language); the invert-to-
   near-black fix is scoped to an explicit `.wall-tile--mono` modifier (Task 4, T2-review
   fold-forward) — NOT a blanket `.wall-tile img` rule — so a future colour-logo sponsor doesn't
   silently get its brand colours inverted. `_sponsor_reel.html` applies the class per-sponsor
   (name-matched against the two known white-mono partners); there's no `Sponsor.logo_is_mono`
   model field yet, so a real per-sponsor flag is the honest long-term fix if/when a third,
   differently-coloured logo is wired — flagging for review rather than adding a migration here.
   Hover lifts to full. The dark player pages restore the prior grayscale-on-transparent wall
   verbatim (applies to every tile, mono or not — grayscale desaturates but never corrupts a
   colour logo the way invert would), so watch/live chrome is unchanged. */
.wall-tile{display:flex;align-items:center;justify-content:center;min-block-size:4rem;
  padding-inline:1.15rem;padding-block:.9rem;border-radius:.7rem;
  background:var(--surface);border:1px solid var(--border);box-shadow:var(--shadow-card);
  color:var(--text-muted);font-weight:700;letter-spacing:.02em;font-size:1.05rem;
  text-align:center;transition:color .15s,box-shadow .2s ease,border-color .2s ease}
.wall-tile:hover{color:var(--text);border-color:var(--border-card);box-shadow:0 6px 18px rgba(16,18,66,.12)}
.wall-tile img{max-height:2.4rem;max-inline-size:100%;width:auto;opacity:.72;transition:opacity .15s}
.wall-tile--mono img{filter:invert(1)}
.wall-tile:hover img{opacity:1}
.theme-dark .wall-tile{padding:0;background:transparent;border:0;box-shadow:none}
.theme-dark .wall-tile img{filter:grayscale(1);opacity:.75;transition:filter .15s,opacity .15s}
.theme-dark .wall-tile:hover img{filter:none;opacity:1}

/* Sport mini-site — CSS-only tabbed sections (no jumping, no JS, mobile-first) */
.stabs{position:relative}
.stab-radio{position:absolute;inline-size:1px;block-size:1px;opacity:0;pointer-events:none}
.stab-bar{display:flex;gap:.15rem;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;border-block-end:1px solid var(--border);margin-block:.4rem 1.3rem}
.stab-bar::-webkit-scrollbar{display:none}
.stab{flex:0 0 auto;font-family:var(--display);text-transform:uppercase;letter-spacing:.04em;font-weight:700;font-size:.82rem;color:var(--text-muted);padding:.8rem 1rem;cursor:pointer;white-space:nowrap;border-block-end:2px solid transparent;transition:color .12s ease,border-color .12s ease}
.stab:hover{color:var(--text)}
.stab-panel{display:none}
.panel-more{margin-block-start:1.1rem}
.scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch}
#stab-schedule:checked ~ .stab-bar label[for="stab-schedule"],
#stab-bracket:checked ~ .stab-bar label[for="stab-bracket"],
#stab-results:checked ~ .stab-bar label[for="stab-results"],
#stab-squads:checked ~ .stab-bar label[for="stab-squads"],
#stab-athletes:checked ~ .stab-bar label[for="stab-athletes"],
#stab-nations:checked ~ .stab-bar label[for="stab-nations"],
#stab-standings:checked ~ .stab-bar label[for="stab-standings"],
#stab-medals:checked ~ .stab-bar label[for="stab-medals"]{color:var(--accent-ink);border-block-end-color:var(--accent-ink)}
#stab-schedule:checked ~ .stab-panels #schedule,
#stab-bracket:checked ~ .stab-panels #bracket,
#stab-results:checked ~ .stab-panels #results,
#stab-squads:checked ~ .stab-panels #squads,
#stab-athletes:checked ~ .stab-panels #athletes,
#stab-nations:checked ~ .stab-panels #nations,
#stab-standings:checked ~ .stab-panels #standings,
#stab-medals:checked ~ .stab-panels #medals{display:block;animation:stabIn .25s ease}
.stab-radio:focus-visible ~ .stab-bar{outline:2px solid var(--accent);outline-offset:3px;border-radius:.4rem}
@keyframes stabIn{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){#stab-schedule:checked ~ .stab-panels #schedule,#stab-bracket:checked ~ .stab-panels #bracket,#stab-results:checked ~ .stab-panels #results,#stab-squads:checked ~ .stab-panels #squads,#stab-athletes:checked ~ .stab-panels #athletes,#stab-nations:checked ~ .stab-panels #nations,#stab-standings:checked ~ .stab-panels #standings,#stab-medals:checked ~ .stab-panels #medals{animation:none}}

/* ---- discipline-filter (sport tab: All + per-discipline pill chips) ---- */
/* Scrollable on narrow screens; .chip already defined in the feed picker above.
   .chip-on gets accent fill so the active chip reads clearly (not just accent border). */
.discipline-filter{display:flex;gap:.45rem;overflow-x:auto;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;padding-block:.1rem .6rem;margin-block-end:1.1rem}
.discipline-filter::-webkit-scrollbar{display:none}
.discipline-filter .chip{flex:0 0 auto;white-space:nowrap}
.discipline-filter .chip-on{background:color-mix(in srgb,var(--accent) 18%,var(--surface));
  border-color:var(--accent);color:var(--accent-ink);font-weight:600}

/* ---- order-of-play (Schedule tab: COLLAPSED per session; expand for its bout-list) ---- */
.order-of-play{display:flex;flex-direction:column;gap:.7rem;margin-block-start:.5rem}
.oop-intro{color:var(--text-muted);font-size:.86rem;margin:.1rem 0 .2rem}
.oop-session{background:var(--surface);border:1px solid var(--border);border-radius:.8rem;overflow:hidden}
.oop-session[open]{border-color:color-mix(in srgb,var(--accent) 45%,var(--border))}
.oop-title{display:flex;align-items:center;gap:.65rem;cursor:pointer;list-style:none;padding:.85rem 1rem;
  font-family:var(--display);text-transform:uppercase;letter-spacing:.04em;font-size:.85rem;font-weight:700;color:var(--text)}
.oop-title::-webkit-details-marker{display:none}
.oop-title::before{content:"";flex:0 0 auto;inline-size:.5rem;block-size:.5rem;
  border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);transform:rotate(-45deg);transition:transform .18s}
.oop-session[open] .oop-title::before{transform:rotate(45deg)}
.oop-title:hover{color:var(--accent-ink)}
.oop-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.oop-day{font-size:.76rem;font-weight:400;text-transform:none;letter-spacing:0;color:var(--text-muted)}
.oop-count{flex:0 0 auto;min-inline-size:1.5rem;text-align:center;padding:.1rem .45rem;border-radius:1rem;
  background:rgba(255,255,255,.08);color:var(--text-muted);font-size:.74rem;font-weight:700}
.oop-session .bout-list{margin:0;padding:0 1rem 1rem;list-style:none}

/* ---- squads (team rosters: one collapsible per nation, players inside) ---- */
.squad{background:var(--surface);border:1px solid var(--border);border-radius:.8rem;overflow:hidden;
  margin-block-end:.7rem}
.squad[open]{border-color:color-mix(in srgb,var(--accent) 45%,var(--border))}
.squad-h{display:flex;align-items:center;gap:.6rem;cursor:pointer;list-style:none;padding:.85rem 1rem;
  font-family:var(--display);text-transform:uppercase;letter-spacing:.03em;font-size:.9rem;font-weight:700;color:var(--text)}
.squad-h::-webkit-details-marker{display:none}
.squad-h::before{content:"";flex:0 0 auto;inline-size:.5rem;block-size:.5rem;
  border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);transform:rotate(-45deg);transition:transform .18s}
.squad[open] .squad-h::before{transform:rotate(45deg)}
.squad-h:hover{color:var(--accent-ink)}
.squad-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.squad-count{flex:0 0 auto;min-inline-size:1.6rem;text-align:center;padding:.1rem .45rem;border-radius:1rem;
  background:rgba(255,255,255,.08);color:var(--text-muted);font-size:.74rem;font-weight:700}
.squad-list{margin:0;padding:.2rem 1rem 1rem;list-style:none;font-size:.92rem}
.squad-list li{padding:.4rem 0;border-block-start:1px solid var(--border)}
.squad-list li:first-child{border-block-start:0}
.squad-list a{color:var(--text);text-decoration:none}
.squad-list a:hover{color:var(--accent-ink)}
@media (min-width:48rem){.squad-list{columns:2;column-gap:2rem}
  .squad-list li{break-inside:avoid}}

/* ---- standings table (ranked results: Rank · Nation · [Athlete] · Result) ---- */
/* Mobile-first: make the table horizontally scrollable so columns never crush. */
.standings-wrap{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;
  border:1px solid var(--border);border-radius:.7rem;margin-block:.5rem 1.2rem}
.standings{width:100%;border-collapse:collapse;font-size:.92rem}
.standings th,.standings td{padding:.55rem .7rem;text-align:start;border-block-end:1px solid var(--border);white-space:nowrap}
.standings th{font-family:var(--display);text-transform:uppercase;letter-spacing:.06em;font-size:.72rem;
  font-weight:600;color:var(--text-muted);background:var(--bg)}
.standings tr:last-child td{border-block-end:0}
/* Zebra — matches .medals hover pattern but as every-other-row fill */
.standings tbody tr:nth-child(even){background:color-mix(in srgb,var(--surface) 60%,var(--bg))}
.standings tbody tr:hover{background:var(--surface)}
/* Podium rows — subtle medal-metal tint + left accent rule (non-distracting, readable).
   World Gymnastics light (Task 4, carried from T3's medals-table bug): rank-1 was pinned to
   var(--accent), gold by Kinetic coincidence — now coral. Pinned to the file's existing
   medal-gold literal (#e9c463 — .mp-num/.col-gold/.badge-gold/.medals td.total) instead,
   matching rank-2/3's own literal silver/bronze hexes. */
.standings tr.rank-1 td:first-child,.standings tr.rank-2 td:first-child,.standings tr.rank-3 td:first-child{
  border-inline-start:3px solid transparent}
.standings tr.rank-1 td:first-child{border-inline-start-color:#e9c463}
.standings tr.rank-2 td:first-child{border-inline-start-color:#cfd2d6}
.standings tr.rank-3 td:first-child{border-inline-start-color:#cd9b6a}
.standings tr.rank-1{background:color-mix(in srgb,#e9c463 7%,transparent)!important}
.standings tr.rank-2{background:color-mix(in srgb,#cfd2d6 5%,transparent)!important}
.standings tr.rank-3{background:color-mix(in srgb,#cd9b6a 5%,transparent)!important}
/* Tabular numerals on rank + result columns */
.standings td.rank,.standings th.rank{color:var(--text-muted);width:2.5rem;text-align:center;
  font-variant-numeric:tabular-nums}
.standings td.mark,.standings th.mark{text-align:end;font-variant-numeric:tabular-nums;color:var(--text-muted)}
.standings td.mark b{color:var(--text)}
/* Medal icons in the rank cell — same sizing as the medals table */
.standings td.rank .medal-ico{height:1.15em;vertical-align:-.2em}
/* Nation + athlete name columns */
.standings td.nation{font-weight:600}
.standings td.nation .code{color:var(--text-muted);font-weight:400;font-size:.8rem;margin-inline-start:.35rem}
.standings td.who a{color:var(--text)}
.standings td.who a:hover{color:var(--accent-ink)}

/* ---- medals page: sport filter select + medallists section ---- */
.medal-filter{display:flex;align-items:center;flex-wrap:wrap;gap:.55rem .9rem;margin-block:.6rem 1.4rem}
.medal-filter label{font-family:var(--display);font-size:.72rem;text-transform:uppercase;
  letter-spacing:.07em;color:var(--text-muted);font-weight:600}
.medal-filter select{background:var(--surface);color:var(--text);border:1px solid var(--border);
  border-radius:.5rem;padding:.45rem .65rem;font:inherit;font-size:.88rem;cursor:pointer;
  transition:border-color .12s}
.medal-filter select:focus-visible{outline:2px solid var(--accent-ink);outline-offset:1px;border-color:var(--accent-ink)}
.medal-filter select:hover{border-color:var(--accent)}
/* Medallists section — reuses .medal-list + adds a section wrapper */
.medallists{margin-block-start:1.25rem}
.medallists .medal-list{margin-block-start:.55rem}
.medallists .medal-list li{padding:.5rem .65rem;background:var(--surface);border:1px solid var(--border);border-radius:.6rem}
.medallists .medal-list li:hover{border-color:var(--accent)}

/* ---- venue map ---- */
.venue-map{position:relative;block-size:60vh;min-block-size:340px;border:1px solid var(--border);border-radius:1rem;margin-block:1rem;overflow:hidden;background:#0a0a0c}
.leaflet-container{background:#0a0a0c;font-family:var(--font)}
.venue-pin span{display:block;inline-size:14px;block-size:14px;border-radius:50%;box-shadow:0 0 0 3px rgba(0,0,0,.55),0 0 10px rgba(0,0,0,.6)}
/* themed Leaflet controls (zoom + reset) — dark glass, gold on hover (kills the default white) */
.leaflet-bar{border:1px solid var(--border);box-shadow:0 4px 16px rgba(0,0,0,.5)}
.leaflet-bar a,.leaflet-bar a:hover,a.vmap-reset{background:rgba(18,18,22,.92);color:var(--text);border-block-end-color:var(--border)}
.leaflet-bar a:hover,a.vmap-reset:hover{color:var(--accent-ink)}
a.vmap-reset{font-size:1.05rem;font-weight:700;line-height:1.7;text-align:center}
.leaflet-control-attribution{background:rgba(10,10,12,.7)!important;color:var(--text-muted)}
.leaflet-control-attribution a{color:var(--text-muted)}
/* popup — force dark surface + readable text. !important beats leaflet.css, which loads
   AFTER app.css (page head_extra) and would otherwise paint the bubble white. */
.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:var(--surface)!important;color:var(--text)!important;border:1px solid var(--border)}
.leaflet-popup-content-wrapper{border-radius:.7rem}
.leaflet-popup-content{margin:.7rem .85rem;color:var(--text)!important}
.leaflet-popup-close-button{color:var(--text-muted)!important}
.leaflet-popup-close-button:hover{color:var(--text)!important}
.leaflet-popup-content .vp{display:flex;flex-direction:column;gap:.15rem;color:var(--text);text-decoration:none;min-inline-size:10rem}
.leaflet-popup-content .vp img{inline-size:100%;block-size:6rem;object-fit:cover;border-radius:.4rem;margin-block-end:.35rem}
.leaflet-popup-content .vp b{font-family:var(--display);color:var(--text)}
.leaflet-popup-content .vp span{color:var(--text-muted);font-size:.8rem}
.leaflet-popup-content .vp .vp-go{color:var(--accent-ink);font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;margin-block-start:.3rem}
/* cooperative-zoom hint overlay */
.vmap-hint{position:absolute;inset:0;z-index:800;display:grid;place-items:center;pointer-events:none;opacity:0;transition:opacity .2s;background:rgba(10,10,12,.45);color:var(--text);font-weight:600;letter-spacing:.02em}
.venue-map.show-hint .vmap-hint{opacity:1}
/* sport / city filter dropdowns */
.map-filters{display:flex;flex-wrap:wrap;gap:1rem;margin-block:1rem .25rem}
.mf-field{display:flex;flex-direction:column;gap:.3rem;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--text-muted)}
.mf-field select{font:inherit;font-size:.92rem;font-weight:500;text-transform:none;letter-spacing:0;color:var(--text);background-color:var(--surface);border:1px solid var(--border);border-radius:.6rem;padding:.55rem 2.1rem .55rem .85rem;min-inline-size:12rem;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .75rem center;background-size:.7rem;transition:border-color .15s}
.mf-field select:hover,.mf-field select:focus{border-color:var(--accent);outline:none}
.venue-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(13rem,1fr));gap:.6rem;margin-block:1rem}
.venue-row{display:flex;flex-direction:column;gap:.15rem;padding:.8rem 1rem;background:var(--surface);border:1px solid var(--border);border-radius:.7rem;color:var(--text);text-decoration:none;cursor:pointer;transition:border-color .15s,transform .15s}
.venue-row:hover{border-color:var(--accent);transform:translateY(-2px)}
.venue-row .venue-city{color:var(--text-muted);font-size:.82rem}
.venue-row.venue-off .venue-name::after{content:" \2197";color:var(--accent-ink)}
@media (max-width:30rem){.venue-list{grid-template-columns:1fr 1fr}.venue-map{block-size:48vh}}

/* ===== /vl S1 — GymTV standup classes ===== */

/* HTMX error toast — fixed bottom-right, dark card, dismissible.
   [hidden] must win the cascade over display:flex — explicit override. */
.qb-toast{position:fixed;inset-block-end:1.25rem;inset-inline-end:1.25rem;z-index:200;
  display:flex;align-items:center;gap:.65rem;
  background:var(--surface);border:1px solid var(--border);
  border-inline-start:3px solid var(--accent);border-radius:.55rem;
  padding:.6rem .9rem;font-size:.88rem;color:var(--text);
  max-inline-size:min(22rem,90vw);box-shadow:0 8px 24px rgba(0,0,0,.55)}
.qb-toast[hidden]{display:none!important}
.qb-toast button{flex:0 0 auto;background:none;border:0;color:var(--text-muted);
  font:inherit;cursor:pointer;padding:.1rem .25rem;line-height:1;border-radius:.25rem}
.qb-toast button:hover{color:var(--text)}

/* Search empty-state CTA — calm muted paragraph, accent links (matches site vocabulary). */
.empty-cta{color:var(--text-muted);font-size:.9rem;margin-block:.5rem 1.25rem}
.empty-cta a{color:var(--accent-ink);font-weight:600}
.empty-cta a:hover{text-decoration:underline}

/* Poster fallback — when a thumbnail 404s, the parent .poster already carries the brand
   gradient inline; this class just ensures the box never collapses or clips wrong. */
.poster-fallback{overflow:hidden;min-block-size:7rem}

/* ============================================================================
   HOME STAGE — full-bleed bands + cinematic hero settle + scroll reveals  (2026-07-08)
   Everything is scoped under .home-stage so ONLY the landing page changes; the
   centred layout on every other page is untouched. This is a look-first draft —
   the performance pass (scroll cost, image weight) is deliberately deferred.

   Full-bleed technique: a band gets width:100vw and margin-inline:calc(50% - 50vw)
   to reach the viewport edges out of main's 78rem column, then re-insets its own
   content with padding of calc(50vw - 39rem) (39rem = half the 78rem column), never
   less than the base 1.25rem gutter on narrow screens.
   ============================================================================ */
body{overflow-x:clip}                 /* guard: full-bleed 100vw must not spawn a horizontal scrollbar */
.home-stage{position:relative;isolation:isolate}
/* Pull the full-bleed hero flush under the sticky header: the band breaks out horizontally
   but main's 1.5rem top padding still pushed it down, leaking the arena bg as a gap. Zero it
   on the landing only (page-home); every other page keeps the 1.5rem top gutter. */
body.page-home main{padding-block-start:0}

/* Landing background: plain white since the fidelity pass (2026-07-16) — the veiled
   ribbon-field backdrop is retired; colour now lives in the indigo band sections. */

/* --- band edge-to-edge breakout --- */
.home-stage > .marquee,
.home-stage > .reel-flags,
.home-stage > .home-rails,
.home-stage > .ec{width:100vw;margin-inline:calc(50% - 50vw)}

/* --- Cinematic hero: full-bleed, fills the screen, image shown NORMALLY (cover, subject
       centred — not cropped into the midsection, not half-faded). A restrained bottom+left scrim
       keeps the title/CTA readable without washing out the picture. On scroll the image
       PARALLAXES (drifts slower than the page) for depth. The Watch CTA sits comfortably in view
       above the fold. Pure-CSS; static + readable where unsupported. --- */
.home-stage > .marquee{position:relative;display:block;border:0;border-radius:0;margin-block:0;
  min-block-size:min(88svh,58rem);background:var(--bg);overflow:clip}

/* --- Participating-nations strip: full-bleed, sits flush under the hero --- */
.home-stage > .reel-flags{margin-block:0;border-block-color:var(--border)}

/* --- Rails band: one full-bleed panel with a faint tint; headings align to the
       column, and the card rows bleed off the right edge to signal "more →". --- */
.home-rails{padding-block:clamp(1.75rem,5vh,3rem) clamp(1.5rem,4vh,2.5rem);
  background:
    radial-gradient(120% 80% at 50% -10%, color-mix(in srgb, var(--accent) 7%, transparent), transparent 60%),
    linear-gradient(180deg, color-mix(in srgb, var(--text) 3%, transparent), transparent 40%)}
.home-rails > .shelf{margin-block-end:clamp(1.75rem,4.5vh,2.75rem);
  padding-inline:max(1.25rem,calc(50vw - 39rem))}
.home-rails > .shelf:last-child{margin-block-end:0}
/* Uniform rails: ONE row of equal-width cards. Every rail shows the same card size and only as
   many as fit the content column; any extra cards are hidden (reach them via "Show all →"). No
   horizontal scroller, so no ragged half-card clipping — and the grid children can reveal on page
   scroll cleanly. Column count steps down responsively; card width stays uniform across rails. */
.home-rails .shelf-row{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:1.1rem;
  margin:0;padding:0;overflow:visible;scroll-snap-type:none}
.home-rails .shelf-row .card{flex:none;width:auto;scroll-snap-align:none}
.home-rails .shelf-row .card:nth-child(n+6){display:none}
@media (max-width:75rem){.home-rails .shelf-row{grid-template-columns:repeat(4,minmax(0,1fr))}
  .home-rails .shelf-row .card:nth-child(n+5){display:none}}
@media (max-width:56rem){.home-rails .shelf-row{grid-template-columns:repeat(3,minmax(0,1fr))}
  .home-rails .shelf-row .card:nth-child(n+4){display:none}}
@media (max-width:40rem){.home-rails .shelf-row{grid-template-columns:repeat(2,minmax(0,1fr))}
  .home-rails .shelf-row .card:nth-child(n+3){display:none}}
.home-stage .all-events-link{padding-inline:max(1.25rem,calc(50vw - 39rem));margin-block-start:clamp(1.25rem,3vh,2rem)}

/* --- Sections "pop" in as they enter — a spring/overshoot entrance driven by a play-once
       IntersectionObserver in app.js (it adds `reveal-ready` to <html>, then `.in` per element).
       The hidden start-state is gated on `reveal-ready`, so if the JS never runs NOTHING is
       hidden — the page is always safe/visible. Cards cascade via nth-child delay. Skipped under
       reduced-motion (the JS doesn't arm it). Sections punch in as you scroll down. --- */
.reveal-ready .home-rails .card,
.reveal-ready .home-rails .shelf-title,
.reveal-ready .home-stage > .reel-flags,
.reveal-ready .home-stage .all-events-link{opacity:0;will-change:transform,opacity}
.home-rails .card.in,
.home-rails .shelf-title.in,
.home-stage > .reel-flags.in,
.home-stage .all-events-link.in{animation:hs-pop .6s cubic-bezier(.2,.85,.3,1.12) both}
/* Once the pop finishes, app.js swaps `.in` → `.shown` (a static visible state) so the animation
   stops holding `transform` and the JS 3D-tilt (inline transform) can take over on hover. */
.home-rails .card.shown,
.home-rails .shelf-title.shown,
.home-stage > .reel-flags.shown,
.home-stage .all-events-link.shown{opacity:1}
.home-rails .card:nth-child(1).in{animation-delay:.03s}
.home-rails .card:nth-child(2).in{animation-delay:.10s}
.home-rails .card:nth-child(3).in{animation-delay:.17s}
.home-rails .card:nth-child(4).in{animation-delay:.24s}
.home-rails .card:nth-child(5).in{animation-delay:.31s}
@keyframes hs-pop{0%{opacity:0;transform:translateY(38px) scale(.93)}60%{opacity:1}100%{opacity:1;transform:none}}

/* Enjoyable browsing — cards come alive on hover: the poster eases in a zoom, an accent glow
   blooms around the card, the play cue fades up and the title lights. Hover effects live on the
   poster + shadow/border (NOT a card transform) so they never fight the pop-in animation. */
.home-rails .card{overflow:hidden;transform-origin:center;
  transition:transform .18s ease, box-shadow .3s ease, border-color .3s ease}
.home-rails .card .poster{transition:transform .6s cubic-bezier(.2,.7,.3,1)}
.home-rails .card h3{transition:color .2s ease}
.home-rails .card:hover .poster,
.home-rails .card:focus-within .poster{transform:scale(1.08)}
.home-rails .card:hover,
.home-rails .card:focus-within{
  border-color:color-mix(in srgb,var(--accent) 78%,var(--border));
  box-shadow:0 26px 50px -24px rgba(0,0,0,.95),
    0 0 0 1px color-mix(in srgb,var(--accent) 48%,transparent),
    0 0 40px -8px color-mix(in srgb,var(--accent) 32%,transparent)}
.home-rails .card:hover h3,
.home-rails .card:focus-within h3{color:var(--accent-ink)}
.home-rails .card:hover .poster-play,
.home-rails .card:focus-within .poster-play{opacity:1}

.wm{font-family:var(--display);font-weight:800;font-size:22px;letter-spacing:.02em;color:var(--text)}
.wm-tv{color:var(--accent)}
/* Light header: lime is a FILL, not an ink — "TV" sits as ink-on-lime chip (the reference
   button language). Dark keeps the Kinetic yellow-text wordmark above. */
body:not(.theme-dark) .wm-tv{background:var(--accent);color:var(--on-accent);
  padding:.04em .22em;border-radius:.28em;margin-inline-start:.1em}

/* ============================================================================
   Live Wall home (2026-07-10, Task 8) — dual-mode shell: on-air ticker + editorial
   split hero. Kinetic treatment (client-approved): solid colour blocks driven by
   brand tokens, no gradients between accents. Marquee scroll + reveals land in
   Tasks 12–13; full discipline/up-next/endcard polish in Tasks 10–11. Logical
   properties only.
   ============================================================================ */
.home-stage{position:relative}

/* Hero live-feed rotator (client round 1) — the home hero cycles through every live session.
   Slides are grid-STACKED (all in cell 1/1) so the rotator sizes to the tallest slide and never
   jumps as slides swap; the active one cross-fades in. Only the first slide is visible on the
   server render, so with JS blocked/stale the lead live feed still shows (graceful degrade). The
   dots bar is JS-gated (.is-ready) — no dead controls without JS; the "All live feeds" button is
   always shown in live mode. Discrete swap + pause/dots live in app.js. Logical props only. */
.hero-rotator{margin-block-end:clamp(1.5rem,4vh,2.5rem)}
.hero-slides{display:grid;isolation:isolate}
.hero-slide{grid-area:1/1;opacity:0;visibility:hidden;transform:translateY(10px);
  transition:opacity .55s ease,transform .55s ease,visibility .55s ease}
.hero-slide.is-active{opacity:1;visibility:visible;transform:none;z-index:1}
.hero-rotator .hero-split{margin-block-end:0}
/* Client round 2 item 1: a 3-column grid (empty / dots+count / button) centers the dots group
   on the hero's own width regardless of the button's rendered size — both 1fr tracks share the
   same flex factor so they stay equal width (the classic "centered middle, balanced edges" grid
   trick), no spacer element needed. Grid line numbers + `justify-self` are flow-relative, so
   this holds under RTL without any direction-specific overrides. Below 30rem there isn't room
   for three columns side by side, so the bar stacks to a single centered column instead. */
.hero-rotator-bar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:.9rem 1.25rem;margin-block-start:clamp(.9rem,2.5vh,1.4rem)}
.hero-nav{display:none;grid-column:2;justify-self:center;align-items:center;gap:.85rem}       /* JS-gated: revealed on .is-ready */
.hero-rotator.is-ready .hero-nav{display:flex}
.hero-dots{display:flex;align-items:center;gap:.5rem}
.hero-dot{inline-size:.7rem;block-size:.7rem;border-radius:50%;padding:0;cursor:pointer;
  border:2px solid color-mix(in srgb,var(--text) 55%,transparent);background:transparent;
  transition:background .2s ease,border-color .2s ease,transform .2s ease}
.hero-dot:hover{border-color:var(--accent-ink);transform:scale(1.15)}
.hero-dot.is-active{background:var(--accent-ink);border-color:var(--accent-ink)}
.hero-dot:focus-visible{outline:2px solid var(--accent-ink);outline-offset:3px}
.hero-count{font-family:var(--display);font-weight:700;font-variant-numeric:tabular-nums;
  font-size:.82rem;letter-spacing:.04em;color:var(--text-muted)}
.hero-all-live{grid-column:3;justify-self:end}                /* pin the CTA to the row's end */
@media (max-width:30rem){
  .hero-rotator-bar{grid-template-columns:1fr;justify-items:center;gap:.7rem}
  .hero-nav,.hero-all-live{grid-column:1;justify-self:center}
}
@media (prefers-reduced-motion:reduce){
  .hero-slide{transition:none;transform:none}                /* no motion; dots still swap */
}

/* Editorial split hero — deep-indigo copy panel beside the media panel (fidelity pass
   2026-07-16, client round 3: "closer to the original" — the reference's hero/news bands are
   navy with white ink and the single ribbon motif; the neutral grey panel read as
   off-brand. The ribbon edge of band-ribbon.webp anchors the panel's far edge.) */
.hero-split{display:grid;grid-template-columns:1fr 1fr;min-block-size:520px;overflow:hidden;
  border:1px solid var(--border-card);border-radius:1rem;
  margin-block-end:clamp(1.5rem,4vh,2.5rem)}
.hs-copy{background:var(--band) url("bg/band-ribbon.webp") left center/cover no-repeat;color:#fff;
  display:flex;flex-direction:column;justify-content:center;gap:1rem;
  padding-inline:clamp(1.5rem,4vw,3rem);padding-block:clamp(1.75rem,5vh,3.25rem)}
.hs-copy .hs-title{color:#fff}
.hs-copy .hs-kicker{color:var(--support)}
.hs-copy .hs-sub{color:rgba(255,255,255,.78)}
.hs-copy .hs-score{background:rgba(255,255,255,.1);color:#fff;border-color:rgba(255,255,255,.18)}
.hs-copy .hs-score.is-lead{background:var(--accent);color:var(--on-accent);border-color:transparent}
.hs-copy .btn-underline{color:#fff}
.hs-copy .btn-underline:hover{color:var(--accent)}   /* lime reads ON indigo, unlike on white */
.hs-eyebrow{display:flex;align-items:center;flex-wrap:wrap;gap:.6rem .8rem}
.pill-live{display:inline-flex;align-items:center;gap:.4rem;
  background:var(--live);color:#fff;
  font-family:var(--display);font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  font-size:.72rem;border-radius:999px;padding-inline:.7rem;padding-block:.3rem}
/* .tk-dot: was the ON-AIR ticker's pulse dot (ticker removed, client round 1); kept because
   .pill-live (the hero LIVE pill, above) reuses it for its own dot. */
.tk-dot{inline-size:.5rem;block-size:.5rem;border-radius:50%;background:#fff;flex:0 0 auto;
  box-shadow:0 0 0 3px rgba(255,255,255,.3)}
.hs-kicker{color:var(--text-muted);
  text-transform:uppercase;letter-spacing:.1em;font-size:.74rem;font-weight:700}
.hs-title{margin:0;font-family:var(--display);font-weight:800;line-height:1.02;letter-spacing:-.01em;
  font-size:clamp(2rem,5vw,3.6rem);overflow-wrap:break-word;text-wrap:balance}
.hs-sub{margin:0;color:var(--text-soft);
  font-size:1rem;font-variant-numeric:tabular-nums}
.hs-scores{display:flex;align-items:center;flex-wrap:wrap;gap:.6rem 1rem;margin-block:.25rem}
.hs-athlete{display:inline-flex;align-items:center;gap:.5rem}
.hs-name{font-weight:700}
.hs-score{font-family:var(--display);font-weight:800;font-variant-numeric:tabular-nums;
  border-radius:.4rem;padding-inline:.5rem;padding-block:.15rem;color:var(--text);
  background:color-mix(in srgb,var(--text) 6%,var(--surface));border:1px solid var(--border-card)}
.hs-score.is-lead{background:var(--accent);color:var(--on-accent);border-color:transparent}
.hs-vs{opacity:.7;font-size:.8rem;text-transform:uppercase;letter-spacing:.08em}
.hs-cta{display:flex;align-items:center;flex-wrap:wrap;gap:.6rem 1.1rem;margin-block-start:.5rem}
.hs-media{position:relative;overflow:hidden;background:var(--surface);min-block-size:280px}
.hs-img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover}
.hs-scrim{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to right, rgba(16,18,66,.55), transparent 42%)}

/* Kinetic CTAs: solid accent button + underline link (readable on the blue copy panel). */
.btn-accent{background:var(--accent);color:var(--on-accent);border:0}
.btn-underline{display:inline-flex;align-items:center;color:var(--text);
  font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:.05em;
  font-size:.86rem;text-decoration:underline;text-underline-offset:.28em;text-decoration-thickness:2px}
.btn-underline:hover{color:var(--accent-ink)}

@media (max-width:52rem){
  .hero-split{grid-template-columns:1fr;min-block-size:0}
  .hs-media{order:-1;min-block-size:220px}
}

/* Athlete-in-focus band (Task 9) — portrait + name + count-up stats + CTAs for the brand's
   most-decorated athlete (Task 6's featured_athlete, cross-edition via person_key). Only the
   first stat is accented yellow. Plain <img> portrait, no parallax. data-count/data-reveal(-group)
   are Task 12/13 hooks — unstyled here. Logical properties only.
   Client round 2 item 2: the band previously sat flush with the page bg and stretched the full
   content width, leaving the text column starved of width relative to the fixed-width portrait
   (dead space on the right at wide viewports). It now gets its own raised-card surface
   (--surface, one step lighter than the page bg, vs. the portrait tile's own --bg-raised so the
   photo still reads as recessed inside the card) and is capped + centered as a group instead of
   stretching edge to edge. */
.af{display:grid;grid-template-columns:420px 1fr;gap:48px;align-items:center;
  margin-inline:auto;max-inline-size:64rem;
  background:var(--surface);border:1px solid var(--border-card);border-radius:16px;
  padding:clamp(1.5rem,3vw,2.75rem);
  margin-block-end:clamp(1.5rem,4vh,2.5rem)}
.af-portrait{position:relative;aspect-ratio:4/5;border-radius:16px;overflow:hidden;
  background:var(--bg-raised);border:1px solid var(--border-card)}
.af-img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover;
  object-position:top center}
.af-chip{position:absolute;inset-block-end:1rem;inset-inline-start:1rem;
  display:inline-flex;align-items:center;gap:.5rem;
  background:color-mix(in srgb,var(--bg) 68%,transparent);backdrop-filter:blur(6px);
  border-radius:999px;padding-inline:.75rem;padding-block:.4rem;
  font-size:.8rem;font-weight:700;color:var(--text)}
.af-chip .flag-img{block-size:.9rem;inline-size:auto;border-radius:2px}
.af-eyebrow{color:var(--accent-ink);text-transform:uppercase;letter-spacing:.1em;
  font-size:.8rem;font-weight:700;margin-block-end:.75rem}
.af-name{margin:0 0 1.75rem;font-family:var(--display);font-weight:800;line-height:1.02;
  letter-spacing:-.01em;font-size:clamp(2.25rem,5vw,66px);color:var(--text)}
.af-stats{display:flex;flex-wrap:wrap;gap:clamp(1.5rem,3vw,3rem);margin-block-end:2rem}
.af-stat-n{font-family:var(--display);font-weight:800;font-size:52px;line-height:1;
  font-variant-numeric:tabular-nums;color:var(--text)}
.af-stat-n.is-accent{color:var(--accent-ink)}
.af-stat-l{margin-block-start:.4rem;color:var(--text-muted);font-size:.82rem;
  text-transform:uppercase;letter-spacing:.06em}
.af-cta{display:flex;flex-wrap:wrap;gap:1rem}
/* Schedule bottom gateway (client round 1, Task 8): reuses .af-cta's flex/gap for the
   accent+outline button pair; own top gap since it can sit with no rail above it (an edition
   with no finished sessions yet). */
.sched-gateways{margin-block-start:.5rem}
/* Outline secondary CTA — pairs with .btn-accent (filled) so "Full profile" reads as the
   lighter-weight action next to "Watch her routines". */
.btn-outline{display:inline-block;background:transparent;color:var(--text);
  border:1px solid var(--border-btn);border-radius:.4rem;font-weight:700;
  font-family:var(--display);text-transform:uppercase;letter-spacing:.06em;font-size:.92rem;
  padding-inline:1.3rem;padding-block:.62rem;
  transition:border-color .15s ease,color .15s ease}
.btn-outline:hover{border-color:var(--accent);color:var(--accent-ink)}

@media (max-width:52rem){
  .af{grid-template-columns:1fr;gap:1.5rem}
  .af-portrait{aspect-ratio:4/5;max-inline-size:20rem;margin-inline:auto}
}
/* No-photo leader: a flat full-bleed initial filling the portrait tile (override the generic
   circular .monogram), same treatment as the athlete face-cards. */
.af-portrait .monogram{position:absolute;inset:0;inline-size:100%;block-size:100%;border:0;
  border-radius:0;background:transparent;font-family:var(--display);font-weight:800;
  font-size:clamp(4rem,10vw,7rem);color:color-mix(in srgb,var(--accent) 70%,var(--text))}

/* Athlete-in-focus rotator (client round 1) — the section cycles LEADER→LEADER per discipline.
   Same grid-STACK + discrete cross-fade mechanic as the hero rotator: panels share cell 1/1 so
   the block sizes to the tallest and never jumps; only the first is is-active on the server
   render (graceful degrade with JS off). The nav (dots + count) is JS-gated (.is-ready) so there
   are no dead controls without JS. Timing (~9s, offset from the hero) + pause/dots in app.js.
   Logical props only. */
.af-rotator{margin-block-end:clamp(1.5rem,4vh,2.5rem)}
.af-slides{display:grid;isolation:isolate}
.af-slide{grid-area:1/1;opacity:0;visibility:hidden;transform:translateY(10px);
  transition:opacity .55s ease,transform .55s ease,visibility .55s ease}
.af-slide.is-active{opacity:1;visibility:visible;transform:none;z-index:1}
.af-slide .af{margin-block-end:0}
.af-nav{display:none;justify-content:center;align-items:center;gap:.85rem;margin-block-start:clamp(.9rem,2.5vh,1.4rem)}   /* centered under the now-centered card */
.af-rotator.is-ready .af-nav{display:flex}
.af-dots{display:flex;align-items:center;gap:.5rem}
.af-dot{inline-size:.7rem;block-size:.7rem;border-radius:50%;padding:0;cursor:pointer;
  border:2px solid color-mix(in srgb,var(--text) 55%,transparent);background:transparent;
  transition:background .2s ease,border-color .2s ease,transform .2s ease}
.af-dot:hover{border-color:var(--accent-ink);transform:scale(1.15)}
.af-dot.is-active{background:var(--accent-ink);border-color:var(--accent-ink)}
.af-dot:focus-visible{outline:2px solid var(--accent-ink);outline-offset:3px}
.af-count{font-family:var(--display);font-weight:700;font-variant-numeric:tabular-nums;
  font-size:.82rem;letter-spacing:.04em;color:var(--text-muted)}
@media (prefers-reduced-motion:reduce){
  .af-slide{transition:none;transform:none}                  /* no motion; dots still swap */
}

/* Discipline rail — 3/4 poster cards, gradient scrim, hover-pop. Client round 1 item 5: all
   SEVEN disciplines render (was 4 + "All disciplines" link) with real imagery on every card —
   the old kinetic treatment (3rd card forced to a solid --accent-2 block, hiding its poster)
   read as a broken image to the client and is gone.
   Client round 2 item 3: `auto-fit minmax(15rem,1fr)` grid-stretched every card to fill its row,
   so the leftover row of 3 (7 cards over 4 columns) both left-aligned AND rendered wider than the
   row of 4 above it — read as lopsided. Switched to flex-wrap + justify-content:center with a
   FIXED (non-growing) card width, so every card stays the same size regardless of how many share
   a row, and any wrapped/leftover row centers instead of hugging the start edge. 17.5rem keeps
   the ~4-up size roughly matching the old auto-fit result at the main content width (~75.5rem);
   flex-shrink still lets cards yield gracefully at in-between viewport widths instead of
   overflowing. */
.dr{margin-block-end:clamp(1.5rem,4vh,2.5rem)}
.dr-grid{display:flex;flex-wrap:wrap;justify-content:center;gap:1.1rem;
  margin-block-start:1.1rem}
.dr-card{position:relative;display:block;flex:0 1 17.5rem;aspect-ratio:3/4;overflow:hidden;border-radius:.9rem;
  background:var(--surface);border:1px solid var(--border-card);text-decoration:none;
  background-size:cover;background-position:center}
.dr-img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover;
  transition:transform .6s cubic-bezier(.2,.7,.3,1)}
.dr-scrim{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to top, rgba(16,18,66,.92), rgba(16,18,66,.16) 55%, transparent)}
.dr-label{position:absolute;inset-inline:0;inset-block-end:0;padding:1rem 1.1rem}
.dr-name{font-family:var(--display);font-weight:800;text-transform:uppercase;letter-spacing:.02em;
  font-size:1.15rem;line-height:1.05;color:#fff}
.dr-count{margin-block-start:.3rem;color:rgba(255,255,255,.78);font-size:.8rem}
/* Reusable hover-pop for a media card: lift + accent glow. Kept generic (not scoped to .dr-card)
   so any future poster tile can opt in by adding the class, same spirit as .home-rails .card. */
.card-pop{transition:transform .2s ease, box-shadow .3s ease, border-color .3s ease}
.card-pop:hover,.card-pop:focus-within{transform:translateY(-4px);
  border-color:color-mix(in srgb,var(--accent) 70%,var(--border-card));
  box-shadow:0 22px 44px -22px rgba(0,0,0,.9),
    0 0 0 1px color-mix(in srgb,var(--accent) 40%,transparent)}
.card-pop:hover .dr-img,.card-pop:focus-within .dr-img{transform:scale(1.06)}
@media (max-width:64rem){.dr-card{flex-basis:calc(50% - .55rem)}}   /* 2 up; a lone leftover centers itself */
@media (max-width:30rem){.dr-card{flex-basis:100%}}

/* End-card — the indigo statement band (spec §4) over the luminous ribbon-wave image (Task 5
   A/B: ribbon-veiled beat flat indigo — the satin diagonals give the closer the standard's
   cinematic fuller feel while the ~.85-.9 indigo veil keeps white text contrast unchanged).
   Home-only asset (~79KB webp). Full-bleed via the .home-stage > .ec rule above; re-insets
   its own content the same way the marquee hero does (padding calc(50vw - 39rem) = half the 78rem col). */
.ec{position:relative;overflow:hidden;min-block-size:240px;display:flex;align-items:center;
  /* Fidelity pass 2026-07-16: the reference band runs UNVEILED — deep indigo with its single
     vivid ribbon on the right edge (bg/band-ribbon.webp = their own wg_news.jpg). The old
     generated ribbon-wave + heavy veil combination is what read "way off". */
  background:var(--band) url("bg/band-ribbon.webp") center/cover no-repeat}
/* Ghost watermark word behind the statement (reference news-band signature). */
.ec-ghost{position:absolute;inset-inline-start:-.05em;inset-block-end:-.2em;pointer-events:none;
  font-family:var(--display);font-weight:800;line-height:1;text-transform:uppercase;
  font-size:clamp(4.5rem,12vw,9rem);letter-spacing:.01em;color:rgba(255,255,255,.06);
  white-space:nowrap;user-select:none}
.ec-body{position:relative;z-index:1;inline-size:100%;margin-inline:auto;
  padding-inline:max(1.25rem,calc(50vw - 39rem));padding-block:2.5rem;
  display:flex;flex-direction:column;align-items:center;gap:.6rem;text-align:center}
.ec-eyebrow{color:var(--accent);text-transform:uppercase;letter-spacing:.12em;   /* lime on indigo */
  font-size:.8rem;font-weight:700}
.ec-h{margin:0 0 .5rem;font-family:var(--display);font-weight:800;line-height:1.05;
  letter-spacing:-.01em;font-size:clamp(1.75rem,4.2vw,2.75rem);color:#fff;text-wrap:balance}

/* ---- Portal landing -------------------------------------------------------
   The channel overview: a top strip of what is on now (or next, or last), the
   full calendar, partners, and what GymTV is. Light surface on the indigo
   canvas — white cards float, on-canvas text is white. No motion: the client's
   rotation ban applies here as everywhere.
   No section below adds its own horizontal padding: `main` already supplies
   `padding-inline:1.25rem` + the 78rem cap (the same convention events.html's
   bare .rail-h/.event-grid rely on) — there is no `--gutter` token in this file,
   so the original draft's `var(--gutter)` was dropped for block padding only. */
/* ============================================================================
   PORTAL HERO — cinematic rotator over the top championships
   Reuses the Live Wall hero pattern from the event home: grid-stacked slides that
   cross-fade (never a conveyor — the client's rotation ban permits slide-swaps only),
   JS-gated dots via .is-ready so there are no dead controls without JS, and the house
   full-bleed technique (100vw + margin-inline:calc(50% - 50vw)) so the band reaches the
   viewport edge while its copy stays on the 78rem column with the cards below.

   This replaced a static image band that was ALSO duplicated by a separate top-3 card
   strip below it — the same three editions rendered twice. One surface now.
   ============================================================================ */
.portal-hero{position:relative;isolation:isolate;width:100vw;margin-inline:calc(50% - 50vw);
  overflow:clip;margin-block:0 clamp(1.5rem,4vw,2.5rem)}
/* main's top padding would leak a strip of canvas above the band — zero it on the portal only. */
body.page-portal main{padding-block-start:0}

/* The standing brand line. Small on purpose: the EVENT is the headline here, so this stays a
   kicker — but it is still the page's h1, which is what a screen reader and Google want. */
.portal-hero-kicker{position:absolute;z-index:3;inset-block-start:clamp(1rem,3vw,1.75rem);
  inset-inline-start:max(1.25rem,calc(50vw - 39rem));margin:0;color:rgba(255,255,255,.92);
  font-size:clamp(.8rem,1.5vw,.95rem);letter-spacing:.14em;text-transform:uppercase;font-weight:700}

.portal-hero-slides{display:grid;isolation:isolate}
.portal-hero-slide{grid-area:1/1;position:relative;min-height:clamp(21rem,52vh,32rem);
  display:flex;align-items:flex-end;opacity:0;visibility:hidden;
  transition:opacity .6s ease,visibility .6s ease}
.portal-hero-slide.is-active{opacity:1;visibility:visible;z-index:1}
.portal-hero-img{position:absolute;inset:0;z-index:-2;width:100%;height:100%;object-fit:cover;
  object-position:center 35%}
/* The scrim is what makes white copy safe over ANY of these photos, several of which are bright
   at the bottom. Do not remove it to "show more of the picture". */
.portal-hero-slide::after{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(180deg,rgba(20,16,44,.34) 0%,rgba(20,16,44,.60) 40%,rgba(20,16,44,.96) 100%)}
.portal-hero-body{padding-inline:max(1.25rem,calc(50vw - 39rem));
  padding-block:0 clamp(2.25rem,5vw,3.25rem);max-width:100%}
.portal-hero-body .badge{margin-block-end:.7rem}
.portal-hero-body h2{color:#fff;font-size:clamp(1.8rem,4.6vw,3.1rem);line-height:1.05;margin:0;
  max-width:18ch;text-wrap:balance}
.portal-hero-meta{color:rgba(255,255,255,.82);margin:.5rem 0 1.1rem;font-size:clamp(.9rem,1.4vw,1.05rem)}

.portal-hero-nav{display:none;position:absolute;z-index:3;
  inset-block-end:clamp(1.1rem,3vw,1.75rem);inset-inline-end:max(1.25rem,calc(50vw - 39rem));
  align-items:center;gap:.85rem}
.portal-hero.is-ready .portal-hero-nav{display:flex}
/* Dots sit on the photo, so they need light ink — the shared .hero-dot is tuned for the event
   home's own dark band and already is; only the count needs saying. */
.portal-hero-nav .hero-count{color:rgba(255,255,255,.8);font-size:.8rem;font-variant-numeric:tabular-nums}

.portal-hero--bare{min-height:auto;padding-block:clamp(2rem,6vw,3.5rem);
  padding-inline:max(1.25rem,calc(50vw - 39rem))}
.portal-hero--bare h1{color:#fff;font-size:clamp(2rem,5vw,3.2rem);margin:0}

@media (max-width:48rem){
  .portal-hero-slide{min-height:clamp(18rem,58vh,24rem)}
  .portal-hero-nav{inset-block-end:.9rem}
}
.portal-strip{padding-block:clamp(2rem,6vw,4.5rem) 1rem}
/* The page's only bare-on-canvas heading (not inside a card) — `main`'s default
   ink is `--text` (dark indigo), which on the indigo canvas is dark-on-dark and
   invisible unless forced white, same trap as every other on-canvas heading in
   the INDIGO CANVAS block below. `[data-ghost]`'s ghost-word ::before only fires
   inside `.hero-sm`, which this bare h1 isn't wrapped in, so only the ink matters
   here — scoped to `.page-portal` so no other page's h1 is touched. */
.page-portal h1[data-ghost]{color:#fff;font-size:clamp(1.9rem,5vw,3.4rem);margin:0 0 1.5rem}
.portal-strip-grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr))}
.portal-card{display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--border);
  border-radius:14px;overflow:hidden;text-decoration:none;transition:transform .18s ease,box-shadow .18s ease}
.portal-card:hover{transform:translateY(-3px);box-shadow:0 12px 32px rgb(0 0 0 / .28)}
.portal-card-art{display:block;aspect-ratio:16/9;background:var(--band) center/cover no-repeat}
.portal-card-body{display:flex;flex-direction:column;gap:.45rem;padding:1rem 1.1rem 1.2rem}
/* The card keeps its own white fill, so its ink must be set explicitly — the
   canvas block below whitens bare-on-canvas text and would erase these. */
.portal-card-name{color:var(--text);font-weight:700;font-size:1.05rem;line-height:1.25}
.portal-card-host{color:var(--text-muted);font-size:.85rem}
/* Ongoing (a championship running right now with no live session at this instant — the
   flagship in-season case) shares the template's .badge-replay class with the finished/VOD
   reading, so by default it reads identically to a finished replay. Distinguish it with a
   scoped override under the card's own --ongoing modifier rather than touching .badge-replay
   itself, which plain event cards elsewhere (events.html, home) still use for real replays. */
.portal-card--ongoing .badge-replay{background:var(--accent-ink);color:#fff}
/* Replay state, same scoped-override reasoning: .badge-replay's shared ink
   (--text-muted #5c6270 on #2a2a32) computes to 2.27:1, below WCAG AA 4.5:1. That is a
   pre-existing sitewide miss, but the portal is the site's LANDING page — fix it here,
   under the card's own modifier, instead of restyling the shared class every replay
   badge on every rail already uses. */
/* (the portal-only .badge-replay override is gone — the shared class now passes AA) */
.portal-calendar{padding-block:clamp(1.5rem,4vw,3rem) 0}
/* Member-federation flag wall. ~150 flags, so: small, tight, centred, and quiet — it is a
   statement of the sport's reach, not a navigation surface. Flags keep their own artwork,
   so nothing here inherits the indigo-canvas ink rules. */
.fed-wall{padding-block:clamp(1.5rem,4vw,2.5rem);border-block-start:1px solid rgba(255,255,255,.14)}
.fed-grid{list-style:none;margin:.9rem 0 0;padding:0;display:flex;flex-wrap:wrap;
  justify-content:center;gap:.4rem}
.fed-grid li{display:block;line-height:0}
.fed-grid img{display:block;width:30px;height:22px;object-fit:cover;border-radius:2px;
  box-shadow:0 0 0 1px rgba(255,255,255,.18);opacity:.85;transition:opacity .15s ease,transform .15s ease}
.fed-grid img:hover{opacity:1;transform:scale(1.12)}
@media (prefers-reduced-motion:reduce){.fed-grid img{transition:none}
  .fed-grid img:hover{transform:none}}
@media (max-width:30rem){.fed-grid{gap:.3rem}.fed-grid img{width:24px;height:18px}}
.portal-about{padding-block:clamp(2rem,5vw,4rem)}
/* Centred to match the partners band directly above it — left-aligned, it read as a stray
   column against a centred page foot. */
.portal-about-copy{max-width:46rem;margin-inline:auto;text-align:center}
/* Also bare on the canvas (no card wrapper in the template) — same white-ink reasoning as the h1
   above; heading goes solid white, body copy the same translucent white .hero-lead uses. */
.portal-about-copy h2{color:#fff;font-size:clamp(1.4rem,3.5vw,2.2rem);margin:0 0 .75rem}
.portal-about-copy p{color:rgba(255,255,255,.86);margin:0 0 1.5rem;line-height:1.6}
@media (prefers-reduced-motion:reduce){
  .portal-card{transition:none}
  .portal-card:hover{transform:none}
}


/* ============================================================================
   INDIGO CANVAS (fidelity round 2, client 2026-07-16): "the background is still
   white instead of the blue, and the background is supposed to have the one big
   ribbon like the main site." The light pages' CANVAS is now the reference's
   deep indigo carrying its single big ribbon (one fixed bg/band-ribbon.webp,
   ~10KB, top-right like their news band) — while content CARDS/PANELS stay
   white, exactly like the reference's light rows sitting on the indigo band.
   Everything below is scoped to body:not(.theme-dark): watch/live keep their
   own near-black theme untouched. Rules fall in two families:
   1. solid white surfaces — translucent color-mix(surface, transparent) cards
      read milky over indigo, so they go opaque;
   2. canvas ink — text/controls sitting DIRECTLY on the canvas flip to white
      (in-card ink stays indigo), and on-canvas link accents use lime, which
      reads on indigo (unlike FIG blue, which stays the in-card accent).
   ============================================================================ */
body:not(.theme-dark){background:var(--band)}
body:not(.theme-dark)::before{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
  background:var(--band) url("bg/band-ribbon.webp") right top/cover no-repeat}

/* --- 1. translucent cards → solid white panels --- */
body:not(.theme-dark) .prose-card,
body:not(.theme-dark) .filters,
body:not(.theme-dark) .athlete-filters,
body:not(.theme-dark) .un-card,
body:not(.theme-dark) .standings-wrap{background:var(--surface)}
/* .athlete-bio's key/value list sits bare on the indigo canvas, so its --text-muted labels
   scored 2.76:1. Whiten them here rather than darkening the token — the background is DARK,
   so the intuitive 'use a darker grey' fix makes it worse, not better. */
body:not(.theme-dark) .athlete-bio .k{color:rgba(255,255,255,.72)}
body:not(.theme-dark) .athlete-bio .v{color:#fff}
/* .results has no background of its own, so on light pages it sat straight on the indigo
   canvas: the session link was var(--text) on --band = 1.00:1 (invisible), rank/mark 2.76:1.
   Affects athlete_detail, athlete_career and the sport-hub standings tabs. Rather than
   whitening the ink — which would break the same table inside .standings-wrap, a white card —
   give the rows the card treatment already used by .medal-list right above them. Scoped to
   :not(.theme-dark) so the watch page's #live-scores table is untouched, and excluded there
   explicitly because it already lives in its own dark panel. */
body:not(.theme-dark) .results:not(#live-scores .results) td{background:var(--surface)}
body:not(.theme-dark) .results:not(#live-scores .results) tr:first-child td:first-child{border-start-start-radius:.6rem}
body:not(.theme-dark) .results:not(#live-scores .results) tr:first-child td:last-child{border-start-end-radius:.6rem}
body:not(.theme-dark) .results:not(#live-scores .results) tr:last-child td:first-child{border-end-start-radius:.6rem}
body:not(.theme-dark) .results:not(#live-scores .results) tr:last-child td:last-child{border-end-end-radius:.6rem}
body:not(.theme-dark) .un-card .un-row:hover{background:var(--bg-raised)}
body:not(.theme-dark) .empty{background:rgba(255,255,255,.05);color:rgba(255,255,255,.8);
  border-color:rgba(255,255,255,.25)}

/* --- 2. canvas ink: white headings/meta, lime links, light chrome lines --- */
body:not(.theme-dark) .rail h2,
body:not(.theme-dark) .rail-h,
body:not(.theme-dark) .shelf-title,
body:not(.theme-dark) .day-h,
body:not(.theme-dark) .sport-h,
body:not(.theme-dark) .event-h,
body:not(.theme-dark) .hero h1,
body:not(.theme-dark) .profile-id h1,
body:not(.theme-dark) .profile-stats strong{color:#fff}
/* …except section labels INSIDE white panels, which keep the indigo ink. */
body:not(.theme-dark) .ned-edition .rail-h,
body:not(.theme-dark) .career-edition .rail-h,
body:not(.theme-dark) .prose-card h1,
body:not(.theme-dark) .prose-card h2{color:var(--text)}
body:not(.theme-dark) .hero .dates,
body:not(.theme-dark) .hero-lead,
body:not(.theme-dark) .mosaic-count,
body:not(.theme-dark) .reel-h,
body:not(.theme-dark) .result-count,
body:not(.theme-dark) .profile-sub,
body:not(.theme-dark) .profile-stats span,
body:not(.theme-dark) .crumbs,
body:not(.theme-dark) .crumbs a,
body:not(.theme-dark) .all-days,
body:not(.theme-dark) .back a,
body:not(.theme-dark) .hero-count,
body:not(.theme-dark) .af-count,
body:not(.theme-dark) .empty-cta,
body:not(.theme-dark) .ep-edition,
body:not(.theme-dark) .profile-section .auth-alt,
body:not(.theme-dark) .profile-section .auth-note,
body:not(.theme-dark) .pagination .page-info{color:rgba(255,255,255,.72)}
body:not(.theme-dark) .shelf-more,
body:not(.theme-dark) .sec-more,
body:not(.theme-dark) .mosaic-more,
body:not(.theme-dark) .all-events-link a,
body:not(.theme-dark) .archive-banner a,
body:not(.theme-dark) .empty-cta a,
body:not(.theme-dark) .crumbs a:hover,
body:not(.theme-dark) .all-days:hover,
body:not(.theme-dark) .back a:hover{color:var(--accent)}
body:not(.theme-dark) .pagination .page-link{color:#fff;border-color:rgba(255,255,255,.3)}
body:not(.theme-dark) .pagination .page-cur{color:var(--accent)}
body:not(.theme-dark) .shelf-head{border-block-end-color:rgba(255,255,255,.16)}
body:not(.theme-dark) .sport-h{border-block-end-color:rgba(255,255,255,.16)}
body:not(.theme-dark) .reel{border-block-color:rgba(255,255,255,.14)}
body:not(.theme-dark) .day-count,
body:not(.theme-dark) .sport-count{background:rgba(255,255,255,.08);color:rgba(255,255,255,.75);
  border-color:rgba(255,255,255,.2)}
/* rotator dots sat as indigo-mix outlines — flip to white-based, lime active */
body:not(.theme-dark) .hero-dot,
body:not(.theme-dark) .af-dot{border-color:rgba(255,255,255,.5)}
body:not(.theme-dark) .hero-dot:hover,
body:not(.theme-dark) .af-dot:hover{border-color:var(--accent)}
body:not(.theme-dark) .hero-dot.is-active,
body:not(.theme-dark) .af-dot.is-active{background:var(--accent);border-color:var(--accent)}
/* sticky strips (schedule day-nav / medal jump-nav) carry the canvas colour */
body:not(.theme-dark) .day-nav{background:var(--band);border-block-end-color:rgba(255,255,255,.16)}
body:not(.theme-dark) .day-nav a{border-color:rgba(255,255,255,.22);color:rgba(255,255,255,.66)}
body:not(.theme-dark) .day-nav a .d{color:#fff}
body:not(.theme-dark) .day-nav a:hover{border-color:var(--accent);color:#fff}
body:not(.theme-dark) .day-nav a.active{border-color:var(--accent);color:#fff}
body:not(.theme-dark) .day-nav a.active .d,
body:not(.theme-dark) .medal-jump a.active .d{color:var(--accent)}
body:not(.theme-dark) .medal-jump a.active{background:rgba(255,255,255,.08);border-color:var(--accent)}
/* sport mini-site tab bar + filter chips live on the canvas */
body:not(.theme-dark) .stab-bar{border-block-end-color:rgba(255,255,255,.16)}
body:not(.theme-dark) .stab-bar label{color:rgba(255,255,255,.66)}
body:not(.theme-dark) .stab-bar label:hover{color:#fff}
body:not(.theme-dark) #stab-schedule:checked ~ .stab-bar label[for="stab-schedule"],
body:not(.theme-dark) #stab-bracket:checked ~ .stab-bar label[for="stab-bracket"],
body:not(.theme-dark) #stab-results:checked ~ .stab-bar label[for="stab-results"],
body:not(.theme-dark) #stab-squads:checked ~ .stab-bar label[for="stab-squads"],
body:not(.theme-dark) #stab-athletes:checked ~ .stab-bar label[for="stab-athletes"],
body:not(.theme-dark) #stab-nations:checked ~ .stab-bar label[for="stab-nations"],
body:not(.theme-dark) #stab-standings:checked ~ .stab-bar label[for="stab-standings"],
body:not(.theme-dark) #stab-medals:checked ~ .stab-bar label[for="stab-medals"]{color:var(--accent);border-block-end-color:var(--accent)}
/* .facet's base rule fills the pill with var(--surface) (white). Recolouring only the ink for
   the canvas left white-on-white — the Live/Individual/Team labels rendered as blank capsules.
   The canvas IS the pill's backdrop here, exactly as .facet-on below assumes. */
body:not(.theme-dark) .facet{color:rgba(255,255,255,.75);border-color:rgba(255,255,255,.28);
  background:transparent}
body:not(.theme-dark) .facet:hover{color:#fff;border-color:var(--accent)}
body:not(.theme-dark) .facet-on{color:var(--accent);border-color:var(--accent);background:rgba(255,255,255,.06)}
/* Text that sits BARE on the canvas rather than inside a white card, and so kept its indigo ink
   on indigo. Each is scoped so the same class inside a card is untouched:
   - .sec-head only exists in _discipline_rail (the home rail header); .sched-head's .sec-h rides
     the FIG-blue band and must NOT go white.
   - `main > .meta` is the search page's "N results" line; every other .meta is nested in a card.
   - .crumbs is already white-on-canvas, but `.crumbs [aria-current]` (the current page) had a
     higher-specificity dark override, so the last crumb alone disappeared.
   - .pl-loading sets its colour explicitly, so it beat the inherited .pl-inner override. */
body:not(.theme-dark) .sec-head .sec-h{color:#fff}
/* …and the mirror case: .back's white-on-canvas ink is right on watch, but the article's copy of
   it lives INSIDE the white .prose-card, where white on white erased "← All news" entirely. */
body:not(.theme-dark) .prose-card .back a{color:var(--accent-ink)}
body:not(.theme-dark) main > .meta{color:rgba(255,255,255,.72)}
body:not(.theme-dark) .crumbs [aria-current]{color:#fff}
body:not(.theme-dark) .pl-loading{color:#fff}
body:not(.theme-dark) .pl-sponsor-label{color:rgba(255,255,255,.6)}
body:not(.theme-dark) .sport-nav a{color:rgba(255,255,255,.72)}
body:not(.theme-dark) .sport-nav a:hover{color:var(--accent);background:rgba(255,255,255,.06)}
/* /live-style timeline rows on the canvas (home up-next stays its white .un-card) */
body:not(.theme-dark) .up-next:not(.un-card) .un-row{background:var(--surface)}
body:not(.theme-dark) .un-time{color:var(--accent-ink)}   /* inside white rows/cards */
/* the home rails band: drop its light wash — the canvas IS the band now */
body:not(.theme-dark) .home-rails{background:none}
body:not(.theme-dark) .home-stage > .reel-flags{border-block-color:rgba(255,255,255,.14)}
/* hero split: light-grey card border reads wrong on indigo */
body:not(.theme-dark) .hero-split{border-color:rgba(255,255,255,.14)}
/* profile form labels sit bare on the canvas */
body:not(.theme-dark) .profile-section .auth-form label,
body:not(.theme-dark) .profile-section .helptext{color:rgba(255,255,255,.72)}

/* page-loader splash on the indigo canvas (was var(--bg) white — flashed a white screen) */
body:not(.theme-dark) .page-loader{background:var(--band)}
body:not(.theme-dark) .pl-spinner{border-color:rgba(255,255,255,.16);border-block-start-color:var(--accent)}
body:not(.theme-dark) .pl-inner{color:rgba(255,255,255,.8)}
/* outline CTAs that sit DIRECTLY on the canvas (schedule gateways, up-next card footer) —
   their indigo ink vanished on indigo; in-card outlines (.af) keep the token ink */
body:not(.theme-dark) .sched-gateways .btn-outline{color:#fff;border-color:rgba(255,255,255,.4)}
body:not(.theme-dark) .sched-gateways .btn-outline:hover{color:var(--accent);border-color:var(--accent)}

/* ---- About page — the reference "split" language (fidelity round 2026-07-16): full-bleed
   photo lead; the content panel rides OVER it on a wave-cut top edge (their wave-mask-vertical
   motif recoloured to the row surface). background-color continues the fill past the svg so
   any content length is seamless. Lime accent bars turn the CMS h2s into section dividers. */
.about-stage{width:100vw;margin-inline:calc(50% - 50vw);margin-block-start:-.5rem}
.about-lead{block-size:clamp(18rem,48vh,30rem);
  background:
    linear-gradient(rgba(16,18,66,.24), rgba(16,18,66,.08) 45%, transparent),
    url("stills/about-arena.webp?v=1") center 40%/cover no-repeat}
.about-panel{position:relative;background:#F0F2F4;
  padding:clamp(2rem,4vw,3rem) 1.5rem clamp(3rem,7vh,4.5rem);
  /* the PANEL is full-bleed (its wavy top must span the viewport); the .prose column cap
     moves onto its children so the copy still reads at 42rem, centered */
  max-width:none;margin-inline:0}
/* the wave-cut edge lives on a strip ABOVE the panel, overlapping the photo — a background-color
   on the panel itself would also fill the svg's transparent zone and flatten the cut */
.about-panel::before{content:"";position:absolute;inset-inline:0;inset-block-start:calc(1px - clamp(3.5rem,7vw,6.5rem));
  block-size:clamp(3.5rem,7vw,6.5rem);pointer-events:none;
  background:url("bg/wave-panel-top.svg") top center/100% auto no-repeat}
.about-panel>*{max-inline-size:42rem;margin-inline:auto}
.about-panel>:first-child{margin-block-start:0}
.about-panel h2{font-family:var(--display);letter-spacing:-.005em;color:var(--text);
  display:flex;align-items:center;gap:.65rem;margin-block:2.2rem .6rem}
.about-panel .lead{font-size:1.12rem}
.about-panel a{color:var(--accent-ink);font-weight:600}

/* ═══ Mobile touch ergonomics — 2026-07-27 sweep ═══════════════════════════════
   Every surface was rendered in real Chrome at 360/390/414/768. The layout came
   back clean — no horizontal overflow anywhere — but the shared chrome's touch
   targets sat well under the 44px minimum, the hamburger worst at 34×26.

   These rules grow the HIT AREA, not the design: icons, type scale and spacing
   keep their approved values, so the look signed off in the fidelity round is
   unchanged. Text is only raised where it fell below 11px; the deliberate
   11.5–11.8px secondary labels (mc-name, ep-edition, footer eyebrow) stay put.
   Findings: docs/mobile-sweep/2026-07-27/findings.md */

/* The burger appears at the drawer breakpoint, so its fix belongs there. Only the
   padding grows — the three 1.4rem bars are untouched. */
/* Follows the drawer breakpoint above (64rem) — the burger does not exist above it. */
@media (max-width:64rem){
  .burger{min-inline-size:44px;min-block-size:44px;align-items:center;justify-content:center;padding:.5rem .6rem}
}

@media (max-width:48rem){
  /* Header search / account — the visible 2.1rem circle stays, the reach grows. */
  .site-header .icon-btn{inline-size:44px;block-size:44px}

  /* Footer social icons: same bordered circle, full-size target. */
  .footer-social .social-link{inline-size:44px;block-size:44px}

  /* Stacked footer link columns were 22px rows with no vertical padding. Trade the
     column gap for per-link padding so the footer's overall height barely moves. */
  .footer-col{gap:.1rem}
  .footer-col a{padding-block:.7rem}

  /* Native selects are the touch control on every filter form. */
  .filters select,.medal-filters select,.medal-filter select,.mf-field select,
  .athlete-filters select,.athlete-filters input{min-block-size:44px}

  /* Live standings — the differentiating surface. Nation codes and athlete names
     were 17–24px tall; padding the cell links makes the row itself the target. */
  .results td a{display:inline-block;padding-block:.45rem}

  /* Text that fell below 11px — unreadable at arm's length on a phone. */
  .mp-chip i{font-size:.72rem}
  .col-label{font-size:.72rem}
  .mp-glabel{font-size:.72rem}
  .badge{font-size:.72rem}
  .athlete-card .rank-badge{font-size:.72rem}
  .pl-sponsor-label{font-size:.72rem}
  .mdf-label{font-size:.72rem}
  .sched-eyebrow{font-size:.72rem}
  .dow{font-size:.72rem}
  .dc-live{font-size:.72rem}

  /* Carousel dots were 11×11 — the smallest controls on the site. The visible dot
     keeps its 0.7rem size; a transparent ::after supplies the reach, and the row
     gap widens so neighbouring hit areas can't overlap and steal each other's taps
     (7 dots × ~31px still fits comfortably in 360). */
  .hero-dots,.af-dots{gap:1.25rem}
  .hero-dot,.af-dot{position:relative}
  .hero-dot::after,.af-dot::after{content:"";position:absolute;inset-block:-16px;inset-inline:-10px}

  /* Primary buttons sat 2px under the minimum. */
  .btn{min-block-size:44px}

  /* "Show all →" style section links were 20px tall. */
  .shelf-more,.sec-more,.mosaic-more,.all-days{display:inline-block;padding-block:.7rem}

  /* Filter submit buttons are bare <button>s, so .btn above doesn't reach them. */
  .medal-filters button,.filters button,.athlete-filters button{min-block-size:44px}

  /* Auth secondary links ("Forgot your password?") were 16px tall. */
  .auth-note a,.auth-alt a{display:inline-block;padding-block:.7rem}
}

/* ---- Draw page (/events/<slug>/draw/) ---- */
.draw-page{max-width:1200px;margin:0 auto;padding:0 16px 48px}
.draw-gender h2{margin:32px 0 4px}
.draw-gender h3{margin:24px 0 12px;font-size:1rem;text-transform:uppercase;letter-spacing:.08em;color:var(--text-mute,#5b5d86)}
.draw-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px}
.draw-card{background:#fff;border:1px solid #e3e6ea;border-radius:10px;padding:14px}
.draw-card header{display:flex;justify-content:space-between;gap:8px;align-items:baseline;margin-bottom:10px;flex-wrap:wrap}
.draw-card header span{font-size:.8rem;color:#5b5d86}
.draw-card ol{list-style:none;margin:0;padding:0;display:grid;gap:6px}
.draw-card li{display:flex;align-items:center;gap:8px;font-weight:600}
.draw-card img{border-radius:2px;object-fit:cover}
.draw-group{color:#5b5d86}
.draw-note{margin-top:28px;font-size:.8rem;color:#5b5d86}

/* ---- Single-event footer: the event, the nations wall (replaces the brand statement) ---- */
.brand-event{display:block;height:38px;width:auto}
.footer-nations{max-width:1200px;margin:0 auto;padding:8px 16px 24px}
.footer-nations h3{font-size:.8rem;text-transform:uppercase;letter-spacing:.1em;margin:0 0 12px;opacity:.75}
.footer-flags{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:10px 12px}
.footer-flags a{display:flex;align-items:center;gap:6px;font-size:.7rem;font-weight:700;letter-spacing:.04em;opacity:.85}
.footer-flags a:hover{opacity:1}
.footer-flags img{width:34px;height:23px;object-fit:cover;border-radius:3px}

/* Minimal legible header for the event identity (the white AGWC26 mark and the orange pass pill
   need a dark bar). The full Rotterdam re-skin lives in rotterdam.css and overrides this. */
.site-header{background:#000735;border-bottom:1px solid rgba(255,255,255,.14);color:#fff}
.site-header .nav a{color:#fff}
.site-header .nav a:hover{color:#ff6315;background:transparent}
.site-header .nav a.active{color:#000735;background:#ff6315}
.site-header .purchase-link{background:#ff6315;color:#000735;border-radius:999px;padding:.5rem 1rem;font-weight:800;text-transform:uppercase;font-size:.78rem;letter-spacing:.04em}
.site-header .signin-link,.site-header .account-menu summary{color:#fff}
@media (max-width:64rem){
  /* The drawer panel is the dark header ink (#000735, set in rotterdam.css), the same surface as
     the bar above it, so its links are WHITE. This block once assumed a light panel and painted
     them dark indigo: 1.15:1, unreadable on every phone. Orange is legal as text on this navy
     (6.51:1) and as a fill only with navy ink (white on orange is 2.98:1, fails AA). */
  .site-header .nav a{color:#fff}
  .site-header .nav a:hover{color:#ff6315}
  .site-header .nav a:focus-visible{outline:2px solid #ff6315;outline-offset:-2px;border-radius:.5rem}
  /* ...but the orange ring vanished on the orange pills (Live, current page, pass button): navy
     ring with a white ring inside it, visible on both the pill and the navy panel. */
  .site-header .nav a.active:focus-visible,.site-header .nav a.nav-live:focus-visible,
  .site-header .nav .nav-action-cta:focus-visible{outline:3px solid #000735;outline-offset:-3px;box-shadow:inset 0 0 0 5px #fff}
  .site-header .nav a.active{color:#000735;background:#ff6315}
  .site-header .nav .nav-action-cta{background:#ff6315;color:#000735}
}

/* ---- World Gymnastics mark beside the event mark (header + footer), after rotterdam2026.com ----
   White mono PNG: both the header and the footer are ink. Hidden in the header below 69rem (1104px):
   with the pass button the nav then ends within ~30px of the actions at 1100px, and under that it
   collides (measured 2026-10-13). The footer always shows it. */
.brand-wg{display:inline-flex;align-items:center;flex-shrink:0;padding-inline-start:1rem;margin-inline-start:-.25rem;
  border-inline-start:1px solid rgba(255,255,255,.35)}
.brand-wg img{height:28px;width:auto;display:block}
.site-header .brand-wg img{transition:height .2s ease}
.site-header.scrolled .brand-wg img{height:24px}
.footer-brand .brand-wg{display:inline-flex;margin:.9rem 0 0;padding:0;border:0}
.footer-brand .brand-wg img{height:30px}
.footer-brand .brand-ninor{display:inline-flex;margin:.9rem 0 0 1.25rem}
.footer-brand .brand-ninor img{height:30px;width:auto;display:block}
.footer-brand .brand-lining{display:inline-flex;margin:.9rem 0 0 1.25rem;vertical-align:bottom}
.footer-brand .brand-lining img{height:36px;width:auto;display:block}
@media(max-width:69rem){.site-header .brand-wg{display:none}}

/* Device limit: the card shown instead of the stream (reuses .player-gated) */
.player-devices form{margin:0}

/* Running order: who is on each apparatus now / next / just done (#live-scores, live sessions only) */
.floor{margin-block-end:1.5rem}
.floor-rot{margin-inline-start:.7rem;font-size:.8rem;font-weight:600;color:var(--text-muted)}
.lanes{list-style:none;margin:0;padding:0;display:grid;gap:.75rem;grid-template-columns:repeat(auto-fill,minmax(15.5rem,1fr))}
.lane{background:var(--surface);border:1px solid var(--border-card);border-inline-start:4px solid var(--accent);border-radius:.5rem;padding:.8rem .95rem;box-shadow:var(--shadow-card)}
.lane-app{margin:0 0 .35rem;font-size:.85rem;font-weight:700;color:var(--text-muted)}
.lane-on{margin:0 0 .5rem;display:flex;flex-direction:column;gap:.1rem}
.lane-who{font-size:1.05rem;font-weight:800;line-height:1.25;color:var(--text)}
.lane-who .who,.lane-row .who{display:block;font-size:.8rem;font-weight:600;color:var(--text-muted)}
.lane-on--none .lane-who{font-weight:600;color:var(--text-muted)}
.lane-state{font-size:.78rem;font-weight:700;color:var(--accent-ink)}
.lane-state--wait{color:var(--text-muted)}
.lane-row{margin:.15rem 0 0;display:flex;gap:.6rem;font-size:.85rem;color:var(--text-soft)}
.lane-k{flex:0 0 4.6rem;color:var(--text-muted);font-size:.78rem}
.lane-mark{font-variant-numeric:tabular-nums;margin-inline-start:.35rem;color:var(--text)}
.plan{margin-block-start:.9rem}
.plan summary{cursor:pointer;font-weight:700;font-size:.9rem;color:var(--accent-ink);padding-block:.3rem}
.plan-list{list-style:none;margin:.5rem 0 0;padding:0;display:grid;gap:.5rem}
.plan-rot{display:grid;grid-template-columns:6rem 1fr;gap:.6rem;padding:.55rem .7rem;border:1px solid var(--border);border-radius:.4rem;font-size:.82rem}
.plan-rot--now{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 8%,transparent)}
/* running order: --text-dim / opacity .6 read 2.91:1 on the dark watch surface; --text-muted is 6.58:1 */
.plan-rot--done{color:var(--text-muted)}
.plan-n{font-weight:700}
.plan-cells{list-style:none;margin:0;padding:0;display:grid;gap:.2rem 1rem;grid-template-columns:repeat(auto-fill,minmax(11rem,1fr))}
.plan-app{color:var(--text-muted);margin-inline-end:.3rem}
.plan-team{margin-inline-end:.45rem;white-space:nowrap;font-weight:600}
@media(max-width:30rem){.plan-rot{grid-template-columns:1fr}}

/* Live-feedback round (2026-10-14): channel selector (now in the line under the player), live rows in the
   standings, jump link to the scores. Watch is .theme-dark: surfaces/ink are the dark tokens. */
.channel-k{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--text-muted);margin-inline-end:.35rem}
.channel-pick{display:flex;align-items:center;gap:.4rem;margin:0}
.channel-select{min-block-size:2.5rem;max-inline-size:100%;padding:.4rem 2rem .4rem .7rem;font:inherit;font-weight:700;color:var(--text);background-color:var(--bg);border:1px solid var(--accent);border-radius:.4rem}
.channel-select:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media (max-width:40rem){.channel-pick{inline-size:100%}.channel-select{flex:1 1 auto;min-inline-size:0}}
.to-scores{margin:.2rem 0 .8rem}
.to-scores a{font-weight:700;color:var(--accent-ink)}
/* watch page, qualification subdivision: links to the rankings across every subdivision (results.py) */
.watch-rankings{margin:1rem 0 1.4rem}
.watch-rankings .rail-h{margin-block-end:.3rem}
.watch-rankings-links{display:flex;flex-wrap:wrap;gap:.4rem;margin:.6rem 0 0}
.watch-rankings-links a{display:inline-block;padding:.35rem .8rem;border-radius:999px;border:1px solid currentColor;font-weight:700;font-size:.8rem;color:var(--accent-ink);text-decoration:none}
.watch-rankings-links a:hover{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
#live-scores .results tr.row-live td{background:color-mix(in srgb,var(--accent) 16%,transparent)}
#live-scores .results tr.row-live td:first-child{box-shadow:inset 4px 0 0 var(--accent)}
.live-tag{display:inline-flex;align-items:center;gap:.3rem;margin-inline-start:.4rem;padding:.05rem .45rem;border-radius:99px;background:var(--live);color:#0a0a0c;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;vertical-align:.1em}
.live-tag .live-dot{margin:0;background:#0a0a0c}

/* ---- g5 account pages (2026-10-17) ---------------------------------------------------------- */
/* Single-purpose account pages (reset/change results, expired link, 429, lockout, expired form)
   are now the same white .auth-card as sign-in: their body copy sat bare on the navy canvas in
   navy ink (1:1). In-card ink: --text-soft 12.5:1, links --accent-ink 5.73:1 on white. */
.auth-card .auth-lead{margin:0 0 1.1rem;color:var(--text-soft);line-height:1.6;text-align:center}
.auth-card>.auth-alt{text-align:center;font-size:.9rem;margin-block:.6rem 0}
.auth-card>.btn{margin-block-start:.35rem}
/* Field errors render UNDER their input (account/forms/p.html); pull each list up to its field. */
.auth-form .errorlist{margin:0;padding:0;list-style:none;font-size:.85rem;font-weight:600}
.auth-form p+.errorlist{margin-block-start:-.55rem}
/* Delete my account: a danger button (white on #c42b1c 5.66:1, coral edge 7.75:1 on navy) behind
   an "I understand" checkbox the server also checks. */
.btn.btn-danger{background:#c42b1c;border-color:#ff8a80;color:#fff}
.btn.btn-danger:hover{background:#a32500;border-color:#ff8a80;color:#fff}
.auth-form p.delete-confirm{flex-direction:row;align-items:center;gap:.6rem}
/* Its label sits on the bare navy canvas (no card): white ink, 17.7:1 on --rt-navy. */
body:not(.theme-dark) .auth-form p.delete-confirm,
body:not(.theme-dark) .auth-form p.delete-confirm label{color:#fff}
/* Watch/Live (.theme-dark): --surface is near-black there, so the account button's hover/open disc
   turned #14141a under the navy icon and the icon vanished. Same white disc + navy icon as every
   other page, and the dropdown re-declares the light tokens so it is the same white panel too. */
.theme-dark .site-header .account-menu summary:hover,
.theme-dark .site-header .account-menu[open] summary{background:#fff;color:#000735}
.theme-dark .account-list{--surface:#fff;--bg:#fff;--text:#101242;--text-muted:#5b5d86;--border:#e9dfd8;--accent-ink:#b83b00}
/* The language dropdown had the same near-black Kinetic panel on Watch/Live: same white panel too. */
.theme-dark .lang-list{--surface:#fff;--bg:#f3eee9;--text:#101242;--text-muted:#5b5d86;--border:#e9dfd8;--accent-ink:#b83b00}
/* Player card actions (gated / ended / device-limit cards): primary + ghost buttons side by side,
   wrapping on phones. The ghost keeps white ink and border on the black card in every theme. */
.pl-actions{display:flex;flex-wrap:wrap;gap:.6rem;justify-content:center;margin:.6rem 0 0}
.player .btn-ghost{color:#fff;border-color:rgba(255,255,255,.7)}
.player .btn-ghost:hover{color:#ff6315;border-color:#ff6315}
/* Invalid fields: a 2px dark orange-red border on the white auth card (5.9:1 on white), kept while
   focused; bare account forms on the navy canvas use the light red that reads there. */
body:not(.theme-dark) .auth-form :is(input,select,textarea):is([aria-invalid="true"],.is-invalid),
body:not(.theme-dark) .auth-form :is(input,select,textarea):is([aria-invalid="true"],.is-invalid):focus{border:2px solid #ff8a80}
body:not(.theme-dark) .auth-card .auth-form :is(input,select,textarea):is([aria-invalid="true"],.is-invalid),
body:not(.theme-dark) .auth-card .auth-form :is(input,select,textarea):is([aria-invalid="true"],.is-invalid):focus{border:2px solid #a32500}

/* Watch player, YouTube-style (player.js, Alex 18 Oct). .player-frame wraps the <mux-player> and is
   what goes fullscreen (fullscreen-element), so the feedback below shows there too. touch-action stops
   a double-tap from zooming the page instead of reaching the player. */
.player-frame{position:relative;touch-action:manipulation}
.player-frame:fullscreen{display:flex;align-items:center;justify-content:center;background:#000}
.player-frame:fullscreen>mux-player{inline-size:100%;block-size:100%;aspect-ratio:auto;border-radius:0}
.player-frame:-webkit-full-screen{display:flex;align-items:center;justify-content:center;background:#000;inline-size:100%;block-size:100%}
.player-frame:-webkit-full-screen>mux-player{inline-size:100%;block-size:100%;aspect-ratio:auto;border-radius:0}
/* The brief centred icon/label for a click or key (play, pause, +10 seconds, 45%, 1.5x). */
.pv-osd{position:absolute;top:50%;left:50%;z-index:3;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.15rem;
  min-inline-size:4.75rem;min-block-size:4.75rem;padding:.55rem .8rem;border-radius:999px;background:rgba(0,0,0,.62);color:#fff;
  font-weight:700;font-size:.85rem;line-height:1.1;white-space:nowrap;pointer-events:none;opacity:0;transform:translate(-50%,-50%)}
.pv-osd-t:empty,.pv-osd-i:empty{display:none}
.pv-osd[data-side=left]{left:18%}
.pv-osd[data-side=right]{left:82%}
.pv-osd.is-on{animation:pv-osd .65s ease-out both}
@keyframes pv-osd{0%{opacity:0;transform:translate(-50%,-50%) scale(.82)}18%{opacity:1;transform:translate(-50%,-50%) scale(1)}
  65%{opacity:1;transform:translate(-50%,-50%) scale(1)}100%{opacity:0;transform:translate(-50%,-50%) scale(1.12)}}
@keyframes pv-osd-fade{0%,60%{opacity:1}100%{opacity:0}}
@media (prefers-reduced-motion:reduce){.pv-osd.is-on{animation:pv-osd-fade .7s linear both}}
@media (max-width:40rem){.pv-osd{min-inline-size:3.6rem;min-block-size:3.6rem;padding:.4rem .6rem;font-size:.72rem}.pv-osd svg{inline-size:26px;block-size:26px}}
/* "Resume from 12:34" (a replay left part-way) and "Up next" (a routine clip ended). */
.pv-resume{position:absolute;inset-inline-start:1rem;inset-block-end:4.25rem;z-index:3;display:flex;align-items:stretch;border-radius:999px;overflow:hidden;
  background:rgba(0,0,0,.78);box-shadow:0 2px 12px rgba(0,0,0,.4)}
.pv-resume button{min-block-size:44px;border:0;background:transparent;color:#fff;font:inherit;font-weight:700;cursor:pointer}
.pv-resume-go{padding:.35rem .5rem .35rem 1rem}
.pv-resume-x{padding:.35rem .9rem;font-size:1.2rem;line-height:1}
.pv-resume button:hover{color:var(--accent)}
.pv-resume button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.pv-next{position:absolute;inset-inline-end:1rem;inset-block-end:4.25rem;z-index:3;max-inline-size:min(20rem,calc(100% - 2rem));padding:.75rem .9rem;
  border-radius:.6rem;background:rgba(0,0,0,.82);color:#fff;box-shadow:0 2px 12px rgba(0,0,0,.4)}
.pv-next-k{margin:0 0 .25rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:rgba(255,255,255,.75)}
.pv-next-n{display:inline-grid;place-items:center;inline-size:1.6em;block-size:1.6em;border-radius:50%;background:var(--accent);color:#000735;letter-spacing:0}
.pv-next-who{display:block;color:#fff;font-weight:800;text-decoration:underline;text-underline-offset:.2em;margin-block-end:.5rem}
.pv-next-x{min-block-size:44px;padding:.3rem 1rem;border:1px solid rgba(255,255,255,.6);border-radius:999px;background:transparent;color:#fff;font:inherit;font-weight:700;cursor:pointer}
.pv-next-x:hover{border-color:var(--accent);color:var(--accent)}
/* "Still watching?" (player.js, off unless STILL_WATCHING_MINUTES): the paused video behind a
   centred card; the whole veil continues, the button is the keyboard target. */
.pv-still{position:absolute;inset:0;z-index:4;display:grid;place-content:center;justify-items:center;gap:.75rem;padding:1rem;
  background:rgba(0,0,0,.62);color:#fff;text-align:center;cursor:pointer}
.pv-still-q{margin:0;font-size:clamp(1.1rem,3vw,1.6rem);font-weight:800}
.pv-still-go{min-block-size:44px;padding:.5rem 1.4rem;border:0;border-radius:999px;background:var(--accent);color:#000735;font:inherit;font-weight:800;cursor:pointer}
.pv-still-go:hover{filter:brightness(1.08)}
.pv-still-go:focus-visible{outline:3px solid #fff;outline-offset:3px}
@media (max-width:40rem){.pv-resume,.pv-next{inset-block-end:3.25rem;font-size:.85rem}.pv-resume{inset-inline-start:.5rem}.pv-next{inset-inline-end:.5rem;padding:.55rem .7rem}}
/* Verify card (account/_verify_card.html): taller than 16:9 on a phone, so it grows with its
   content instead of clipping. The webmail links lead; resend + "change address" sit below,
   smaller, as the fallback. */
.player.player-verify{aspect-ratio:auto;min-block-size:min(56.25vw,24rem);overflow:visible;padding:1.25rem 1rem}
.verify-card{display:flex;flex-direction:column;align-items:center;gap:.7rem;max-inline-size:34rem}
.verify-card .pl-note{margin:0}
.verify-junk{font-weight:700}
.verify-actions{display:flex;flex-direction:column;align-items:center;gap:.6rem;margin-block-start:.3rem;font-size:.9rem}
.verify-actions form{margin:0}
/* `button.btn` (rotterdam.css) paints every button orange; resend must read as the fallback. */
.verify-card button.verify-resend{background:transparent;color:#fff;border:1px solid rgba(255,255,255,.6);text-transform:none;letter-spacing:0;font-weight:600;font-size:.85rem;min-block-size:44px;padding:.35rem 1rem}
.verify-card button.verify-resend:hover{background:transparent;color:#ff6315;border-color:#ff6315}
.verify-card button.verify-resend[disabled]{opacity:.6;cursor:not-allowed;color:#fff;border-color:rgba(255,255,255,.6)}
.verify-webmail{display:flex;flex-wrap:wrap;justify-content:center;gap:.5rem;margin:0}
.verify-webmail .btn{min-block-size:44px;display:inline-flex;align-items:center}
.verify-auto{font-size:.85rem}
.verify-card .btn-sm{min-block-size:44px;padding:.35rem 1rem;font-size:.85rem}
.verify-change summary{cursor:pointer;text-decoration:underline;text-underline-offset:.2em;min-block-size:44px;display:flex;align-items:center;justify-content:center}
.verify-change form{display:flex;flex-direction:column;gap:.4rem;align-items:stretch;inline-size:min(22rem,80vw);margin-block-start:.4rem;text-align:start}
.verify-change label{font-size:.85rem}
.verify-change input{font:inherit;padding:.55rem .7rem;border-radius:.5rem;border:1px solid var(--border);background:#fff;color:#000735}
/* Date of birth: three selects in one row (forms.BirthDateWidget). */
.auth-form .dob-row{display:flex;gap:.5rem}
/* controls.css styles every select (chevron, 2.3rem end padding): too roomy for three in a
   phone row, so the padding shrinks here and the month, the longest word, gets more width. */
html body .dob-row select:not([multiple]):not([size]){flex:1 1 0;min-inline-size:0;padding-inline:.55rem 1.6rem;background-position:right .5rem center;font-size:.95rem}
html body .dob-row select[name$="_month"]:not([multiple]):not([size]){flex-grow:1.7}
.auth-form .auth-exists{display:block;margin:0;font-size:.85rem;font-weight:600}
.auth-exists a{color:var(--accent-ink)}
