/* =========================================================
   THE ROUND ROBIN — hub.css
   The category hub (_includes/category-hub.html) and its process
   scenes (_includes/hub-scene-*.html). Loaded by each hub page's
   `extra_css: [hub.css]`; listed in fingerprint-assets.js.

   Moved out of the include's inline <style> (and bracket/index.html's
   seedline block) on 2026-09-15, when the hub moved from bordered
   cards to an editorial spread: DESIGN_DIRECTION.md §7, "reserve a
   card for an object with a real boundary."
   ========================================================= */

/* ── Hero spread ───────────────────────────────────────── */

/* The hub hero sits on the same centered --max column as the path and shelves
   below it. Sitewide .page-header-inner is left-aligned; with a two-column hero
   that offset read as a misaligned grid, so the hub centers its own. */
.hub-hero .page-header-inner { margin-inline: auto; box-sizing: border-box; }

/* 1101px is the ladder's "wide desktop, where a layout can afford a second axis." */
@media (min-width: 1101px) {
  .hub-hero.has-scene .page-header-inner {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: var(--s-6);
    align-items: start;
  }
}
.hub-scene-slot { margin-top: var(--s-5); }
@media (min-width: 1101px) { .hub-scene-slot { margin-top: 0; } }

/* The "now" block (_includes/hub-now-board.html): where the board stands today, between the hero
   copy and the record line. One dominant claim on a projection-blue rule (a third party's straight
   ranking, so blue, never the orange reserved for my voice), its credit and caveat, then the days
   to the next decision. Flat, no card: DESIGN_DIRECTION.md section 4.1 and 7. */
.hub-now { margin-top: var(--s-5); max-width: 540px; padding-top: var(--s-3); border-top: 2px solid var(--projection); }
.hub-now-claim { margin: 0; font-family: var(--fe); font-weight: 600; font-size: var(--t-h2); line-height: 1.15; color: var(--text); }
.page-header-inner .hub-now .hub-now-meta { margin-top: var(--s-1); font-family: var(--fb); font-size: var(--t-meta); color: var(--sub); max-width: none; }
.page-header-inner .hub-now .hub-now-note { margin-top: var(--s-2); font-size: var(--t-meta); line-height: 1.55; color: var(--sub); max-width: none; }
.hub-now-note a { color: var(--projection); text-decoration: none; }
.hub-now-note a:hover { text-decoration: underline; }
.page-header-inner .hub-now .hub-now-count { margin-top: var(--s-3); display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--s-2); row-gap: var(--s-1); font-size: var(--t-meta); max-width: none; }
.hub-now-days { font-family: var(--fd); font-weight: 700; font-size: var(--t-h2); line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
/* The count is filled by hub-scenes.js after first paint. Until then a hidden stand-in holds its line, so the
   date does not wrap under it (+32px on a phone) and push everything below. hub-scenes.js hides the span
   when the date is already past. */
.hub-now-days:empty::before { content: "000 days"; visibility: hidden; }
.hub-now-date { font-family: var(--fm); font-size: var(--t-label); color: var(--sub); }
.hub-now-link { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; font-family: var(--fb); font-weight: 600; font-size: var(--t-meta); color: var(--orange); text-decoration: none; }
.hub-now-link:hover { text-decoration: underline; }
.hub-now-link:focus-visible { outline: 2px solid var(--orange); outline-offset: 4px; }

/* The one number the hub carries, always with its scope. A small stat block on a
   projection-blue rule: the number leads, its label beside it, then scope and the
   honest caveat as their own lines rather than a run-on of 9px mono. */
.hub-record {
  margin-top: var(--s-5); padding-left: var(--s-3); border-left: 2px solid var(--projection);
  display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--s-2); row-gap: 3px;
}
.page-header-inner .hub-record { max-width: 540px; }
.hub-record-link { display: inline-flex; align-items: baseline; gap: var(--s-2); color: var(--text); text-decoration: none; }
.hub-record-link:hover .hub-record-label { color: var(--orange); }
.hub-record-link:focus-visible { outline: 2px solid var(--orange); outline-offset: 4px; }
.hub-record-link .trr-icon { align-self: flex-end; margin-bottom: 2px; color: var(--orange); }
.hub-record-val { font-family: var(--fd); font-weight: 700; font-size: var(--t-display); line-height: 1; color: var(--projection); font-variant-numeric: tabular-nums; }
.hub-record-label { font-family: var(--fb); font-weight: 600; font-size: var(--t-body); color: var(--text); }
.hub-record-scope { flex-basis: 100%; margin-top: var(--s-1); font-family: var(--fm); font-size: var(--t-label); color: var(--sub); }
.hub-record-sub { flex-basis: 100%; font-family: var(--fm); font-size: var(--t-label); line-height: 1.5; color: var(--muted); }

/* ── The cover (cat.hub.cover; DESIGN_DIRECTION.md §14) ─────
   The hero spread on warm cover paper: the question, the sub and the scoped record in the
   copy column, subject artwork beside it, then the dark page resumes with the scene. The
   headline is capped so the sub and the record stay above the fold at 1440x764 (§7). */
.hub-cover { background: var(--paper-cover); color: var(--ink); border-bottom: 0; }
.hub-cover .page-header-inner { padding-top: clamp(32px, 4.4vw, 64px); padding-bottom: clamp(28px, 3.6vw, 48px); }
@media (min-width: 1101px) {
  .hub-cover .page-header-inner {
    /* Even columns: at 5fr the bracket's "Who makes the Dance?" took three lines and pushed
       the record line below the 1440x764 fold. The art is capped at 500px either way. */
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: var(--s-6); align-items: center;
  }
}
.hub-cover .page-header-inner h1 {
  font-size: clamp(44px, 6.2vw, 92px); line-height: 0.98; letter-spacing: -0.01em;
  margin-bottom: var(--s-4); color: var(--ink);
}
.hub-cover .page-header-inner h1 span { color: var(--orange-ink); font-style: italic; }
.hub-cover .page-header-inner p { color: var(--paper-cover-sub); }
/* The record line on paper: same block, ink colours (blue keeps meaning "the model"). */
.hub-cover .hub-record { border-left-color: var(--projection-ink); }
.hub-cover .hub-record-link { color: var(--ink); }
.hub-cover .hub-record-val { color: var(--projection-ink); }
.hub-cover .hub-record-label { color: var(--ink); }
.hub-cover .hub-record-link:hover .hub-record-label,
.hub-cover .hub-record-link .trr-icon { color: var(--orange-ink); }
.hub-cover .hub-record-link:focus-visible { outline-color: var(--ink); }
.hub-cover .hub-record-scope, .hub-cover .hub-record-sub { color: var(--paper-cover-sub); }

.hub-cover-art-slot { margin-top: var(--s-6); }
@media (min-width: 1101px) { .hub-cover-art-slot { margin-top: 0; } }

/* Posters laid on the table: a 3 x 2 grid with small, fixed tilts and the middle column
   dropped half a step, so it reads as a spread of prints rather than a card grid. Every
   card keeps its slip (title, year, the backtest's odds and result) in view. */
.hub-cover-posters {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-5) var(--s-4);
}
.hub-cover-card {
  position: relative; display: flex; flex-direction: column;
  background: var(--paper-cover); box-shadow: 0 1px 2px rgba(1, 23, 43, 0.12), 0 8px 20px rgba(1, 23, 43, 0.14);
  transform: rotate(var(--tilt, 0deg)) translateY(var(--drop, 0px));
}
.hub-cover-card:nth-child(1) { --tilt: -2deg; }
.hub-cover-card:nth-child(2) { --tilt: 1.5deg; --drop: 22px; }
.hub-cover-card:nth-child(3) { --tilt: -1deg; }
.hub-cover-card:nth-child(4) { --tilt: 2deg; }
.hub-cover-card:nth-child(5) { --tilt: -1.5deg; --drop: 22px; }
.hub-cover-card:nth-child(6) { --tilt: 2.5deg; }
.hub-cover-card.is-featured { z-index: 1; }
.hub-cover-card img, .hub-cover-blank { display: block; width: 100%; height: auto; aspect-ratio: 2 / 3; object-fit: cover; background: var(--paper-cover-rule); }
.hub-cover-slip { display: flex; flex-direction: column; gap: 2px; padding: 8px 10px 10px; }
.hub-cover-name { font-family: var(--fe); font-weight: 600; font-size: 15px; line-height: 1.2; color: var(--ink); }
.hub-cover-year { font-family: var(--fm); font-weight: 400; font-size: var(--t-label); color: var(--paper-cover-sub); }
.hub-cover-fact { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; font-size: var(--t-label); }
.hub-cover-prob { font-family: var(--fd); font-weight: 700; font-size: 17px; line-height: 1; color: var(--projection-ink); font-variant-numeric: tabular-nums; }
.hub-cover-result { font-family: var(--fb); font-weight: 600; color: var(--paper-cover-sub); }
.hub-cover-result.is-won { color: var(--ink); }

/* Program cards (bracket): the poster's frame on a lighter sheet, the team's self-hosted mark
   (logos/ are 80x80, so never drawn larger), the program in Newsreader, then two seeds side by
   side. "My seed" is Grant's voice, so it takes the orange ink (_includes/CLAUDE.md, "Voices");
   the committee's seed is plain ink. Women's cards have no pick to show, so theirs is a dash. */
.hub-cover-programs .hub-cover-card { background: var(--paper-card); }
.hub-program-face {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 12px 14px 12px;
}
.hub-program-field { font-family: var(--fm); font-size: var(--t-label); letter-spacing: 0.04em; color: var(--paper-cover-sub); }
.hub-cover-card .hub-program-logo { display: block; background: none; width: clamp(48px, 4.4vw, 64px); height: auto; aspect-ratio: 1; object-fit: contain; margin: 10px 0 8px; }
.hub-program-name {
  font-family: var(--fe); font-weight: 600; font-size: clamp(18px, 1.6vw, 22px); line-height: 1.1;
  color: var(--ink); overflow-wrap: anywhere;
}
.hub-program-conf { font-family: var(--fb); font-size: var(--t-label); color: var(--paper-cover-sub); }
.hub-program-seeds {
  display: grid; grid-template-columns: 1fr 1fr; column-gap: 8px; row-gap: 6px;
  margin-top: auto; padding: 10px 14px 12px; border-top: 1px solid var(--paper-cover-rule);
}
.hub-program-stat { display: flex; flex-direction: column; }
.hub-program-num { font-family: var(--fd); font-weight: 700; font-size: 28px; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.hub-program-stat.is-mine .hub-program-num { color: var(--orange-ink); }
.hub-program-stat.is-none .hub-program-num { color: var(--paper-cover-sub); }
.hub-program-lbl { margin-top: 3px; font-family: var(--fm); font-size: var(--t-label); color: var(--paper-cover-sub); }
.hub-program-diff { grid-column: 1 / -1; font-family: var(--fb); font-weight: 600; font-size: var(--t-label); color: var(--paper-cover-sub); }
.hub-program-diff.is-exact { color: var(--ink); }

/* Photo cards (HoF): the poster frame with a Commons photograph cropped from the top, so faces
   stay in frame whatever the source's shape, then the model's odds (blue ink, the model's voice)
   and the signature stat. The credits sit under the table at label size. */
.hub-cover-photos .hub-cover-card img { aspect-ratio: 4 / 5; object-position: 50% 15%; }
.hub-cover-photos .hub-cover-year { display: block; margin-top: 1px; }
.hub-photo-stat {font-family: var(--fb); font-size: var(--t-label); color: var(--ink); }
.hub-photo-credits {
  margin: var(--s-5) 0 0; font-family: var(--fm); font-size: var(--t-label); line-height: 1.5;
  color: var(--paper-cover-sub);
}
.page-header-inner .hub-photo-credits { max-width: none; font-size: var(--t-label); }
.hub-photo-credits a { color: var(--ink); }
@media (min-width: 1101px) { .hub-photo-credits { max-width: 500px; margin-left: auto; } }

/* The "now" board on cover paper: the dark-page colours (--text, --sub, --projection) wash out
   on cream, so it takes the same ink colours as the record line below it. */
.hub-cover .hub-now { border-top-color: var(--projection-ink); }
.hub-cover .page-header-inner .hub-now .hub-now-meta,
.hub-cover .page-header-inner .hub-now .hub-now-note,
.hub-cover .hub-now-date { color: var(--paper-cover-sub); }
.hub-cover .hub-now-claim, .hub-cover .hub-now-days { color: var(--ink); }
.hub-cover .hub-now-note a { color: var(--projection-ink); }
.hub-cover .hub-now-link { color: var(--orange-ink); }
.hub-cover .hub-now-link:focus-visible { outline-color: var(--ink); }

/* The caption and credit live on a navy band at the cover's foot (white 12.6:1, --sub 6.6:1 on #003368). */
.hub-cover-band { background: var(--navy); }
.hub-cover-band .hub-cover-caption {
  max-width: var(--max); margin: 0 auto; padding: var(--s-4) var(--pad);
  font-family: var(--fb); font-size: var(--t-meta); line-height: 1.55; color: var(--sub);
}
.hub-cover-credit { display: block; margin-top: 4px; font-family: var(--fm); font-size: var(--t-label); }
.hub-cover-credit a { color: var(--text); text-underline-offset: 3px; }

/* The scene, moved off the cover onto the dark page directly beneath it. */
.hub-scene-below { margin-top: 36px; }

/* Beside the copy the table is capped so its two rows stay near the copy's height; stacked
   between the ladder's 700 and 1100 it becomes one row of six; on phones, two across. */
@media (min-width: 1101px) { .hub-cover-posters { max-width: 500px; margin-left: auto; } }
@media (min-width: 701px) and (max-width: 1100px) {
  .hub-cover-posters { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .hub-cover-card:nth-child(n) { --drop: 0px; }
  .hub-cover-card:nth-child(even) { --drop: 16px; }
  .hub-cover-name { font-size: 14px; }
}
@media (max-width: 520px) {
  .hub-cover-posters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hub-cover-card:nth-child(n) { --drop: 0px; }
  .hub-cover-card:nth-child(even) { --drop: 14px; }
}
.category-hub { width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 var(--pad) 64px; box-sizing: border-box; }
@media (max-width: 760px) { .category-hub { padding: 0 16px 48px; } }

/* ── The ordered path ───────────────────────────────────── */
.hub-path-wrap { margin-top: 36px; }
.hub-path-wrap h2.section-label { display: flex; }
.hub-path { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-5); }
@media (max-width: 900px) { .hub-path { grid-template-columns: 1fr; gap: 0; } }

.hub-step { --node: 13px; position: relative; border-top: 2px solid var(--c, var(--orange)); }
.hub-step-link { display: flex; flex-direction: column; height: 100%; padding-top: var(--s-4); color: inherit; text-decoration: none; }
/* The step's stop on its rule: the ordinals it replaced (2026-09-25) now live only in DOM order. */
.hub-step-node {
  position: absolute; top: calc(var(--node) / -2 - 1px); left: 0; width: var(--node); height: var(--node);
  border-radius: var(--r-circle); background: var(--c, var(--orange));
}
.hub-step-title {
  font-family: var(--fb); font-weight: 700; font-size: var(--t-h3);
  line-height: 1.1; color: var(--text);
}
.hub-step-subtext { margin-top: 4px; font-family: var(--fb); font-weight: 600; font-size: var(--t-meta); color: var(--c, var(--orange)); }
.hub-step-desc { margin-top: var(--s-2); font-size: var(--t-body); line-height: 1.6; color: var(--sub); flex: 1; }
.hub-step-foot { margin-top: var(--s-3); display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap; }
.hub-step-cta {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--fb); font-weight: 600; font-size: var(--t-label);
  color: var(--orange); /* one link colour; the step's rule and dot carry its pillar colour (2026-10-08) */
}
a.hub-step-link:hover .hub-step-title { color: var(--orange); }
a.hub-step-link:focus-visible { outline: 2px solid var(--c, var(--orange)); outline-offset: 4px; }
.hub-step.soon { opacity: 0.5; }

/* Stacked: the rule turns vertical, so the three steps read as one descending path. */
@media (max-width: 900px) {
  .hub-step { border-top: none; border-left: 2px solid var(--c, var(--orange)); }
  .hub-step-node { top: 2px; left: calc(var(--node) / -2 - 1px); }
  .hub-step-link { padding: 0 0 var(--s-5) var(--s-4); }
  .hub-step:last-child .hub-step-link { padding-bottom: 0; }
}

/* ── Latest Projections (hub-leaders.js renders the widgets) ── */
.leader-shelf-wrap { margin-top: 48px; }
.pick-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-6); margin-top: 10px; }
.pick-grid.is-single { grid-template-columns: 1fr; max-width: 520px; }
/* A lone seed-line ranking (the off-season KenPom board) has no second widget to pair with: it takes the
   row, four teams to a line, rather than leaving half the shelf empty. */
.pick-grid.is-single:has(.seedline-thead) { max-width: none; }
@media (min-width: 900px) { .pick-grid.is-single:has(.seedline-thead) .seedline-teams { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 860px) { .pick-grid { grid-template-columns: 1fr; gap: var(--s-5); } }
.pick-widget {
  display: flex; flex-direction: column;
  border-top: 2px solid var(--projection);
  padding-top: var(--s-3); text-decoration: none; color: inherit;
}
/* Grant's own picks take the orange the site reserves for his voice; the model
   half keeps --projection blue. Never swapped for variety. */
.pick-widget.is-mine { border-top-color: var(--orange); }
a.pick-widget:hover .pick-widget-title { color: var(--orange); }
a.pick-widget:focus-visible { outline: 2px solid var(--orange); outline-offset: 4px; }
.pick-widget-title { font-family: var(--fb); font-weight: 600; font-size: var(--t-ui); color: var(--text); }
.pick-widget.is-mine .pick-widget-title { color: var(--orange); }
.pick-widget-sub { font-family: var(--fb); font-size: var(--t-meta); color: var(--muted); margin-top: 2px; }
.pick-widget-body { margin-top: var(--s-3); flex: 1; }
.pick-empty { font-family: var(--fb); font-size: var(--t-meta); color: var(--muted); font-style: italic; padding: 10px 0; }
.pick-widget-foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3);
  margin-top: auto; padding-top: var(--s-3); border-top: 1px solid var(--border);
}
.pick-widget-foot:only-child { border-top: none; }
.pick-stamp { font-family: var(--fm); font-size: var(--t-label); color: var(--muted); }
.pick-cta { display: inline-flex; align-items: center; gap: 4px; font-family: var(--fb); font-size: var(--t-meta); font-weight: 600; color: var(--orange); white-space: nowrap; }
.leader-shelf { display: flex; flex-direction: column; margin-top: 10px; }
.leader-row { display: flex; align-items: center; gap: var(--s-3); padding: 8px 0; border-bottom: 1px solid var(--border); }
.leader-row:last-child { border-bottom: none; }
.leader-rank { font-family: var(--fd); font-weight: 700; font-size: var(--t-meta); color: var(--muted); width: 18px; flex-shrink: 0; text-align: right; }
.leader-img { width: 28px; height: 28px; border-radius: var(--r-sm); object-fit: cover; flex-shrink: 0; background: var(--surface); }
.leader-body { min-width: 0; flex: 1; }
.leader-name { font-family: var(--fb); font-weight: 600; font-size: var(--t-ui); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.leader-meta { font-size: var(--t-label); color: var(--muted); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.leader-value { font-family: var(--fm); font-size: var(--t-meta); font-weight: 600; color: var(--projection); flex-shrink: 0; white-space: nowrap; font-variant-numeric: tabular-nums; }
.leader-skeleton { height: 48px; position: relative; overflow: hidden; }
.leader-skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--surface), transparent);
  animation: leader-shimmer 1.4s infinite;
}
@keyframes leader-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@media (max-width: 760px) { .leader-name { white-space: normal; } }

/* Seed-line rows inside the picks widgets: bracket's projection is naturally seed
   lines rather than a ranked list. Moved from bracket/index.html. */
.seedline-thead { display: flex; align-items: center; gap: var(--s-3); padding-bottom: 7px; border-bottom: 1px solid var(--border); }
.seedline-thead span:first-child { width: 22px; flex-shrink: 0; }
.seedline-thead span { font-family: var(--fb); font-weight: 700; font-size: var(--t-label); color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; }
.seedline-row { display: flex; align-items: center; gap: var(--s-3); padding: 9px 0; border-bottom: 1px solid var(--border); }
.seedline-row:last-child { border-bottom: none; padding-bottom: 0; }
.seedline-num {
  font-family: var(--fd); font-weight: 700; font-size: var(--t-meta); color: var(--orange);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm);
  width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.seedline-teams { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-1); min-width: 0; flex: 1; }
.seedline-team { display: flex; align-items: center; gap: var(--s-1); border-bottom: 1px solid var(--border); padding: 4px 0; min-width: 0; }
.seedline-team span { font-family: var(--fb); font-size: var(--t-meta); color: var(--sub); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.seedline-logo { width: 15px; height: 15px; border-radius: var(--r-sm); object-fit: cover; flex-shrink: 0; background: var(--card); }
.seedline-empty { font-family: var(--fb); font-size: var(--t-meta); color: var(--muted); font-style: italic; padding-top: 10px; }
@media (max-width: 480px) { .seedline-teams { grid-template-columns: 1fr; } }

/* ── Shelf switch (category-hub.html, when picks.extra_shelves exist) ──
   Men's | Women's as one pill toggle, the homepage card's (.call-sport) look, in
   front of one shelf at a time. Radio inputs are visually hidden but focusable;
   arrow keys move between them natively. */
.hub-shelves { margin-top: 48px; }
.hub-shelves .section-label { margin-bottom: var(--s-3); }
.hub-shelf-input { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; clip: rect(0 0 0 0); overflow: hidden; white-space: nowrap; }
.hub-shelf-tab {
  display: inline-flex; align-items: center; min-height: 32px; padding: 6px 14px; margin-right: var(--s-1);
  font-family: var(--fb); font-size: var(--t-label); font-weight: 500; color: var(--muted); border: 1px solid var(--border); border-radius: var(--r-pill); cursor: pointer; user-select: none;
}
.hub-shelf-tab:hover { color: var(--sub); }
.hub-shelf-input:checked + .hub-shelf-tab { color: var(--text); border-color: var(--orange); background: rgba(255, 119, 4, .14); }
.hub-shelf-input:focus-visible + .hub-shelf-tab { outline: 2px solid var(--orange); outline-offset: 2px; }
.hub-shelf-panel { display: none; }
.hub-shelf-panels .leader-shelf-wrap { margin-top: var(--s-4); }
/* Each shelf keeps its own "Latest Projections · Men's" label for screen readers and
   for hub-leaders.js, which re-reads it; the shared heading above shows instead. */
.hub-shelf-panels .section-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

/* ── What's next ────────────────────────────────────────── */
.cal-shelf-wrap { margin-top: 48px; }
.cal-shelf { display: flex; flex-direction: column; margin-top: 10px; border-top: 1px solid var(--border); }
.cal-row { display: flex; align-items: baseline; gap: var(--s-5); padding: 12px 0; border-bottom: 1px solid var(--border); }
.cal-when { font-family: var(--fm); font-size: var(--t-meta); color: var(--text); width: 168px; flex-shrink: 0; }
.cal-tentative { font-style: italic; color: var(--muted); }
.cal-label { font-size: var(--t-body); color: var(--text); }
@media (max-width: 760px) {
  .cal-row { flex-direction: column; gap: 3px; }
  .cal-when { width: auto; }
}

/* =========================================================
   SCENES — shared frame (every hub-scene-*.html)
   ========================================================= */
.hub-scene { margin: 0; border-top: 2px solid var(--orange); padding-top: var(--s-3); }
:is(.page-header-inner, .hub-scene-below) .hub-scene p { max-width: none; font-size: inherit; }
.scene-claim { margin-top: 0; font-family: var(--fe); font-weight: 600; font-size: var(--t-h3); line-height: 1.2; color: var(--text); }
/* grid-column: inside .cut-door (a 2-column grid) the stamp would otherwise fall
   into the 44px count column and wrap one word per line. */
:is(.page-header-inner, .hub-scene-below) .hub-scene .scene-stamp { grid-column: 1 / -1; font-family: var(--fm); font-size: var(--t-label); color: var(--sub); margin-top: var(--s-2); }

.scene-controls { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); margin-top: var(--s-4); padding-top: var(--s-3); border-top: 1px solid var(--border); }
.scene-controls[hidden] { display: none; }
.scene-btn {
  display: inline-flex; align-items: center; gap: var(--s-1);
  background: none; border: 1px solid var(--border); border-radius: var(--r-sm);
  min-height: 36px; padding: 6px 12px; color: var(--sub); cursor: pointer;
  font-family: var(--fb); font-weight: 600; font-size: var(--t-label); }
.scene-btn:hover:not(:disabled) { color: var(--orange); border-color: var(--orange); }
.scene-btn:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
.scene-btn:disabled { opacity: 0.4; cursor: default; }
:is(.page-header-inner, .hub-scene-below) .hub-scene .scene-status { flex: 1; text-align: center; font-family: var(--fm); font-size: var(--t-label); color: var(--sub); }

/* Stepper states, set by hub-scenes.js. Without JS no step carries a class, so the
   final state shows. Future stages are what hasn't happened yet: dimmed, never hidden. */
.hub-scene [data-scene-step] { transition: opacity 180ms ease; }
.hub-scene.is-stepped .is-future { opacity: 0.22; }
.hub-scene.is-stepped .is-past { opacity: 0.75; } /* 0.6 took --sub notes to 4.1:1 */
@media (prefers-reduced-motion: reduce) {
  .hub-scene [data-scene-step], .hub-scene [data-scene-step] * { transition: none !important; }
}

/* AUTOPLAY (hub-scenes.js, scenes carrying [data-scene-play]): the narrowing plays once on entry. A stage not
   yet reached holds the previous stage's bar width, so its bar narrows when its turn comes; seats and names
   of the last stage arrive in order and the cut line draws across. Everything here is scoped to .is-playing,
   which the script removes when the sequence ends, so the final state is the page's ordinary one. */
.hub-scene .cut-bar span { transition: width 800ms cubic-bezier(.2, .7, .2, 1), opacity 180ms ease, background-color 180ms ease; }
.hub-scene .seat, .hub-scene .door-name, .hub-scene .door-cut { transition: opacity 260ms ease, transform 260ms ease; }
.hub-scene.is-playing .cut-stage.is-future .cut-bar span { width: 100% !important; }
.hub-scene.is-priming, .hub-scene.is-priming * { transition: none !important; }
.hub-scene.is-playing .cut-door.is-future .seat { opacity: 0; transform: scale(0.4); }
.hub-scene.is-playing .cut-door.is-future .door-name { opacity: 0; transform: translateY(4px); }
.hub-scene.is-playing .cut-door.is-future .door-cut { opacity: 0; transform: scaleX(0); transform-origin: left; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(1) { transition-delay: 80ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(2) { transition-delay: 160ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(3) { transition-delay: 240ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(4) { transition-delay: 320ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(5) { transition-delay: 400ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(6) { transition-delay: 480ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(7) { transition-delay: 560ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(8) { transition-delay: 640ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(9) { transition-delay: 720ms; }
.hub-scene.is-playing .cut-door.is-active .seat:nth-child(10) { transition-delay: 800ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(1) { transition-delay: 250ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(2) { transition-delay: 350ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(3) { transition-delay: 450ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(4) { transition-delay: 550ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(5) { transition-delay: 650ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(6) { transition-delay: 800ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(7) { transition-delay: 900ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(8) { transition-delay: 1000ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(9) { transition-delay: 1100ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(10) { transition-delay: 1180ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(11) { transition-delay: 1260ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(12) { transition-delay: 1340ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(13) { transition-delay: 1420ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(14) { transition-delay: 1500ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(15) { transition-delay: 1580ms; }
.hub-scene.is-playing .cut-door.is-active .door-names > li:nth-child(16) { transition-delay: 1660ms; }
@media (prefers-reduced-motion: reduce) {
  .hub-scene .cut-bar span, .hub-scene .seat, .hub-scene .door-name, .hub-scene .door-cut { transition: none !important; }
}

/* =========================================================
   SCENE — cut-funnel (the narrowing cut)
   ========================================================= */
.cut-stages { list-style: none; margin: var(--s-4) 0 0; padding: 0; }
.cut-stage {
  display: grid; grid-template-columns: 44px minmax(0, 1fr); column-gap: var(--s-3);
  align-items: center; padding: 7px 0; border-bottom: 1px solid var(--border);
}
.cut-count { grid-row: span 2; font-family: var(--fd); font-weight: 700; font-size: var(--t-h3); line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
/* Width is the stage's share of the first stage's count, set inline from the funnel. */
.cut-bar { display: block; height: 6px; }
.cut-bar span { display: block; height: 100%; background: var(--sub); opacity: 0.7; }
.cut-text { display: block; margin-top: 4px; min-width: 0; }
.cut-label { font-family: var(--fb); font-weight: 600; font-size: var(--t-meta); color: var(--text); }
.cut-note { font-family: var(--fb); font-size: var(--t-meta); color: var(--sub); }
.hub-scene.is-stepped .cut-stage.is-active .cut-bar span { background: var(--orange); opacity: 1; }
.hub-scene.is-stepped .cut-stage.is-active .cut-count { color: var(--orange); }

/* The door: the class drawn as seats (solid = the Hall's minimum, outlined = up to
   its maximum), then the model's current class beneath it. */
.cut-door { border-bottom: none; }
.cut-seats { display: flex; gap: 3px; height: 10px; }
.seat { width: 10px; height: 10px; background: var(--orange); }
.seat.is-maybe { background: none; box-shadow: inset 0 0 0 1.5px var(--orange); }
.cut-door .cut-count { color: var(--orange); }

.door-names { grid-column: 1 / -1; list-style: none; margin: var(--s-3) 0 0; padding: 0; }
.door-name {
  display: grid; grid-template-columns: 10px minmax(0, 1fr) auto auto; column-gap: var(--s-2);
  align-items: baseline; padding: 4px 0; border-bottom: 1px solid var(--border);
}
.door-name:last-child { border-bottom: none; }
/* Square marks per CHART_STYLE.md §2. Every row is a projection, so every mark is
   notched; a filled mark clears the room's vote threshold, an outlined one does not. */
.door-mark { width: 9px; height: 9px; align-self: center; box-shadow: inset 0 0 0 1.5px var(--projection); clip-path: polygon(0 0, 100% 0, 100% 62%, 62% 100%, 0 100%); }
.door-name.clears .door-mark { background: var(--projection); }
.door-who { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.door-player { font-family: var(--fb); font-weight: 600; font-size: var(--t-meta); color: var(--text); }
.door-pos { font-family: var(--fm); font-size: var(--t-label); color: var(--muted); }
.door-stat { font-family: var(--fm); font-size: var(--t-label); color: var(--sub); white-space: nowrap; }
.door-chance { font-family: var(--fm); font-size: var(--t-meta); font-weight: 600; color: var(--projection); font-variant-numeric: tabular-nums; min-width: 44px; text-align: right; }
.door-name:not(.clears) .door-player { color: var(--sub); }
:is(.page-header-inner, .hub-scene-below) .hub-scene .door-more { grid-column: 1 / -1; margin-top: var(--s-2); font-family: var(--fb); font-size: var(--t-meta); color: var(--muted); }
.door-more a { display: inline-flex; align-items: center; gap: 3px; color: var(--orange); text-decoration: none; font-weight: 600; }
.door-more a:hover { text-decoration: underline; }
.door-hint { display: none; }
/* Used by the nomination-cut scene: the line between the rows that are
   in and the rows that are not, and an "Out" label that is not a probability. */
.door-cut { list-style: none; margin: 3px 0; border-top: 2px solid var(--orange); padding-top: 2px; }
.door-cut span { font-family: var(--fm); font-size: var(--t-label); color: var(--sub); letter-spacing: 0.04em; }
.door-chance.is-out { color: var(--muted); }
.door-who .door-pos { display: inline-block; min-width: 1.6em; }
/* nomination-cut's poster wall (.door-names.is-posters). From 900px, ten across: the first row
   is the ten slots, the cut line spans the grid, the films outside follow, dimmed. Below
   900px, two-across tiles with a thumbnail. The chance stays projection blue (the model's). */
.door-names.is-posters { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3) var(--s-4); }
.door-names.is-posters .door-name {
  display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; column-gap: var(--s-2); row-gap: 0;
  align-items: center; padding: 0; border-bottom: 0;
}
.door-names.is-posters .door-poster { grid-row: 1 / span 2; width: 36px; height: auto; aspect-ratio: 2 / 3; object-fit: cover; background: var(--card); }
.door-names.is-posters .door-who { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.25; }
.door-names.is-posters .door-chance { min-width: 0; }
.door-names.is-posters .door-stat { grid-column: 2 / -1; }
.door-names.is-posters .door-name:not(.clears) { opacity: 0.62; }
.door-names.is-posters .door-cut { grid-column: 1 / -1; margin: 0; }
@media (min-width: 900px) {
  .door-names.is-posters { grid-template-columns: repeat(10, minmax(0, 1fr)); gap: var(--s-4) var(--s-3); }
  .door-names.is-posters .door-name { display: flex; flex-direction: column; align-items: stretch; gap: 3px; }
  .door-names.is-posters .door-poster { width: 100%; margin-bottom: 4px; }
  .door-names.is-posters .door-who { font-size: var(--t-label); }
  .door-names.is-posters .door-player { font-size: var(--t-label); }
  .door-names.is-posters .door-pos { min-width: 0; margin-right: 2px; }
  .door-names.is-posters .door-chance { text-align: left; }
}
@media (max-width: 480px) {
  .door-name { grid-template-columns: 10px minmax(0, 1fr) auto; }
  .door-stat { grid-column: 2 / -1; grid-row: 2; }
  /* Tap to reveal (hub-scenes.js [data-scene-reveal]). Only once JS has wired it
     (.has-reveal), so a no-JS phone still shows every stat. */
  .hub-scene.has-reveal .door-name[data-scene-reveal] { cursor: pointer; }
  .hub-scene.has-reveal .door-name[data-scene-reveal] .door-stat { display: none; }
  .hub-scene.has-reveal .door-name.is-open .door-stat { display: block; }
  /* The toggle is the name inside the row (hub-scenes.js), so the focus ring goes there. */
  .hub-scene.has-reveal .door-name[data-scene-reveal] .door-who:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
  .hub-scene.has-reveal .door-hint { display: inline; }
}


/* =========================================================
   SCENE — bubble-shift (Bracket: what the 76-team field changes)
   The seats (32 automatic, the at-large seats as before, the new ones), then a dumbbell per season:
   hollow = where the last team in ranked by NET under the 68-team field, solid = under 76.
   Static; the spans grow in on scroll where scroll-driven animation exists. Orange marks the
   change (the new seats, the solid dots, the gain), the sitewide accent for what is new.
   ========================================================= */
.shift-sub { margin: var(--s-2) 0 0; font-family: var(--fb); font-size: var(--t-body); color: var(--sub); }
.shift-seats { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-4); margin-top: var(--s-4); }
.shift-group { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; }
.shift-seatrow { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.shift-seat { width: 7px; height: 7px; background: var(--sub); opacity: 0.55; }
.shift-seat.is-auto { opacity: 0.9; }
.shift-seat.is-new { background: var(--orange); opacity: 1; }
.shift-cap { font-family: var(--fm); font-size: var(--t-label); color: var(--sub); }
.shift-cap.is-new { color: var(--orange); font-weight: 600; }
.shift-lede { margin: var(--s-4) 0 var(--s-2); font-family: var(--fb); font-size: var(--t-meta); color: var(--sub); }
.shift-rows { list-style: none; margin: 0; padding: 0; }
.shift-row, .shift-axis {
  display: grid; grid-template-columns: 46px minmax(0, 1fr) 62px 34px; column-gap: var(--s-3); align-items: center;
}
.shift-row { min-height: 28px; border-bottom: 1px solid var(--border); }
.shift-year { font-family: var(--fm); font-size: var(--t-label); color: var(--sub); }
.shift-track { position: relative; display: block; height: 16px; margin: 0 7px; }
.shift-track::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--border); }
.shift-span { position: absolute; top: 50%; height: 3px; margin-top: -1.5px; background: var(--orange); opacity: 0.55; transform-origin: left center; }
.shift-dot { position: absolute; top: 50%; box-sizing: border-box; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: var(--r-circle); border: 1.5px solid var(--sub); background: var(--bg); }
.shift-dot.is-76 { border-color: var(--orange); background: var(--orange); }
.shift-vals { font-family: var(--fm); font-size: var(--t-meta); color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.shift-arrow { color: var(--muted); }
.shift-gain { font-family: var(--fm); font-size: var(--t-meta); font-weight: 600; color: var(--orange); font-variant-numeric: tabular-nums; text-align: right; }
.shift-row.is-median { border-bottom: none; border-top: 1px solid var(--sub); margin-top: 2px; }
.shift-row.is-median .shift-year, .shift-row.is-median .shift-vals { color: var(--text); font-weight: 600; }
.shift-row.is-median .shift-span { opacity: 1; }
.shift-axis { margin-top: 2px; }
.shift-axis-track { position: relative; display: block; height: 14px; margin: 0 7px; }
.shift-tick { position: absolute; top: 0; transform: translateX(-50%); font-family: var(--fm); font-size: var(--t-label); color: var(--muted); font-variant-numeric: tabular-nums; }
@media (max-width: 480px) {
  .shift-row, .shift-axis { grid-template-columns: 40px minmax(0, 1fr) 54px 30px; column-gap: var(--s-2); }
}
@media (prefers-reduced-motion: no-preference) {
  .shift-span { animation: shift-grow 700ms cubic-bezier(.2, .7, .2, 1) both; animation-delay: calc(var(--i, 6) * 90ms); }
  @supports (animation-timeline: view()) {
    .shift-span { animation-timeline: view(); animation-range: entry 20% cover 45%; animation-delay: 0s; animation-duration: auto; }
  }
}
@keyframes shift-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
