/* ==========================================================================
   League Leaders — stylesheet
   Dense, scannable stat tables in the spirit of a classic league-leaders
   page, with the brand red carried from the logo.
   ========================================================================== */

:root {
  --brand:        #b22524;
  --brand-dark:   #8c1b1a;
  --brand-tint:   #fbeceb;

  --ink:          #16191d;
  --ink-2:        #3d444d;
  --ink-3:        #6b737d;
  --ink-4:        #98a0aa;

  --bg:           #f2f3f5;
  --surface:      #ffffff;
  --surface-2:    #f8f9fa;
  --border:       #dfe3e8;
  --border-strong:#c6ccd4;

  --header-bg:    #16191d;
  --header-ink:   #ffffff;

  /* The puzzle's own colour, and deliberately not the brand red. Everything
     that carries the red is a leaderboard — a link into the data — and the
     game is the one thing on the page that is not that. It is also the only
     saturated non-red on a site that is otherwise ink on white, which is the
     point: indigo through teal reads as "play this" at a glance. */
  --accent:       #3730a3;
  --accent-2:     #0e7490;
  --accent-ink:   #312e81;
  /* The accent as *text on a surface*, which is a different job from the
     accent as a fill. #3730a3 on white is 9.9:1 and needs no help; the dark
     palette lifts its accent to #4f46e5 so it reads as colour against the
     page, and at that value 11px type on a card is 2.75:1, which fails. So
     the text tint is its own token and only dark has to move it. */
  --accent-text:  #3730a3;

  --gold:         #b8860b;
  /* The highlighter behind a league-leading figure. */
  --led-bg:       #ffe66d;
  --led-ink:      #16191d;
  /* The race chart's five lines, leader first. */
  --race-1:       #b22524;
  --race-2:       #1f6feb;
  --race-3:       #1a7f37;
  --race-4:       #b8860b;
  --race-5:       #8250df;
  --green:        #1a7f37;
  --green-tint:   #e6f4ea;
  --green-line:   rgba(26, 127, 55, .28);

  --ad-hatch:     rgba(16, 20, 26, .16);

  /* The bar behind a leaderboard value. Low enough alpha that the digits
     on top of it stay the thing being read. */
  --bar-fill:     rgba(178, 37, 36, .14);
  /* The leaderboard number on a phone, where the bar is not drawn. Light keeps
     the brand red; dark cannot, because red on the near-black surface is the
     low-contrast pairing the bar was hiding. */
  --value-ink:    #b22524;

  --radius:       8px;
  --radius-sm:    4px;
  --shadow:       0 1px 2px rgba(16, 20, 26, .06), 0 2px 8px rgba(16, 20, 26, .04);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, sans-serif;
  --mono: "SF Mono", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;

  /* Tells the browser which way to paint the things we do not style: scrollbars,
     select menus, date pickers, the canvas behind an overscroll. Without it a
     reader who has forced light on a dark-preference machine gets our light page
     with the browser's dark form controls in it. Kept in step with the palette
     by the same three rules below. */
  color-scheme: light;
}

/* -------------------------------------------------------------- dark mode --
   Three states, and all three are needed.

   No attribute is the default: follow the operating system, which is the right
   answer for the large majority who never touch the switch. data-theme="light"
   pins light on a machine set to dark; data-theme="dark" pins dark on a machine
   set to light. The switch in the masthead writes the attribute and remembers
   it; with no JavaScript the media query alone still does the sensible thing.

   The two dark blocks carry the same values and have to stay that way. CSS has
   no way to hand one declaration list to a selector inside a media query and a
   selector outside it, so this is a duplicate on purpose: edit one, edit both.
   ------------------------------------------------------------------------- */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
}
:root[data-theme="dark"] { color-scheme: dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --brand:        #e2504a;
    --brand-dark:   #b22524;
    --brand-tint:   #2a1917;

    --ink:          #eef1f4;
    --ink-2:        #c2c9d1;
    --ink-3:        #939ba5;
    --ink-4:        #6f7883;

    --bg:           #0f1216;
    --surface:      #171b21;
    --surface-2:    #1d222a;
    --border:       #2a313a;
    --border-strong:#3a424d;

    --header-bg:    #0a0c0f;
    /* Lifted off the dark ground; the light-mode pair is too close to the
       page background to read as colour here. */
    --accent:       #4f46e5;
    --accent-2:     #0891b2;
    --accent-ink:   #4338ca;
    --accent-text:  #818cf8;   /* 5.6:1 on --surface. See the light block. */
    --gold:         #d8a730;
    --led-bg:       rgba(250, 204, 21, .28);
    --led-ink:      #fde68a;
    --race-1:       #e2504a;
    --race-2:       #58a6ff;
    --race-3:       #4ac26b;
    --race-4:       #d8a730;
    --race-5:       #b392f0;
    --green:        #4ac26b;
    --green-tint:   rgba(74, 194, 107, .13);
    --green-line:   rgba(74, 194, 107, .32);
    --shadow:       0 1px 2px rgba(0, 0, 0, .4), 0 2px 8px rgba(0, 0, 0, .25);
    --ad-hatch:     rgba(255, 255, 255, .12);
    --bar-fill:     rgba(226, 80, 74, .22);
    --value-ink:    #fbbf24;   /* 10.6:1 on --surface. */
  }
}

/* Dark pinned by the switch, on a machine whose preference is light. Same
   values as the block above — see the note there. */
:root[data-theme="dark"] {
  --brand:        #e2504a;
  --brand-dark:   #b22524;
  --brand-tint:   #2a1917;

  --ink:          #eef1f4;
  --ink-2:        #c2c9d1;
  --ink-3:        #939ba5;
  --ink-4:        #6f7883;

  --bg:           #0f1216;
  --surface:      #171b21;
  --surface-2:    #1d222a;
  --border:       #2a313a;
  --border-strong:#3a424d;

  --header-bg:    #0a0c0f;
  --accent:       #4f46e5;
  --accent-2:     #0891b2;
  --accent-ink:   #4338ca;
  --accent-text:  #818cf8;
  --gold:         #d8a730;
  --led-bg:       rgba(250, 204, 21, .28);
  --led-ink:      #fde68a;
  --race-1:       #e2504a;
  --race-2:       #58a6ff;
  --race-3:       #4ac26b;
  --race-4:       #d8a730;
  --race-5:       #b392f0;
  --green:        #4ac26b;
  --green-tint:   rgba(74, 194, 107, .13);
  --green-line:   rgba(74, 194, 107, .32);
  --shadow:       0 1px 2px rgba(0, 0, 0, .4), 0 2px 8px rgba(0, 0, 0, .25);
  --ad-hatch:     rgba(255, 255, 255, .12);
  --bar-fill:     rgba(226, 80, 74, .22);
  --value-ink:    #fbbf24;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
}

a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { margin: 0; line-height: 1.25; font-weight: 700; letter-spacing: -.01em; }
h1 { font-size: 26px; }
h2 { font-size: 18px; }
h3 { font-size: 15px; }

/* --------------------------------------------------------------- header -- */

.masthead {
  background: var(--header-bg);
  border-bottom: 3px solid var(--brand);
}

.masthead__inner {
  max-width: 1240px;
  margin: 0 auto;
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 28px;
  flex-wrap: wrap;
}

.brand { display: flex; align-items: center; flex-shrink: 0; }
.brand img { display: block; height: 76px; width: auto; }
.brand:hover { text-decoration: none; }

.sport-nav { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }

.sport-nav a {
  display: flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: var(--radius-sm);
  color: rgba(255, 255, 255, .72);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  /* Active state is a bottom bar rather than a filled pill: a red block behind
     a league mark fights the mark's own colours. */
  border-bottom: 3px solid transparent;
}
.sport-nav a:hover { background: rgba(255, 255, 255, .1); color: #fff; text-decoration: none; }
.sport-nav a.is-active { color: #fff; border-bottom-color: var(--brand); }

/* League marks */
.sport-nav a.has-icon { padding: 6px 12px 3px; }

.sport-nav a.has-icon img {
  display: block;
  height: 30px;
  width: auto;
  /* Marks are full-colour artwork, so dim rather than recolour. */
  opacity: .62;
  transition: opacity .12s ease, filter .12s ease;
}
.sport-nav a.has-icon:hover img { opacity: 1; }
.sport-nav a.has-icon.is-active img { opacity: 1; }

/* Sports with no data yet read as inactive: desaturated and further dimmed,
   but still clickable through to their placeholder page. */
.sport-nav a.is-upcoming img { filter: grayscale(1); opacity: .38; }
.sport-nav a.is-upcoming:hover img { filter: grayscale(.35); opacity: .8; }
.sport-nav a.is-upcoming { color: rgba(255, 255, 255, .38); }

.masthead__search { margin-left: auto; }

.masthead__search input {
  width: 210px;
  padding: 7px 11px;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, .08);
  color: #fff;
  font-family: inherit;
  font-size: 13px;
}
.masthead__search input::placeholder { color: rgba(255, 255, 255, .45); }
.masthead__search input:focus {
  outline: none;
  border-color: var(--brand);
  background: rgba(255, 255, 255, .14);
}

/* ---------------------------------------------------------------- layout -- */

.wrap { max-width: 1240px; margin: 0 auto; padding: 22px 20px 56px; }

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.page-head p { margin: 4px 0 0; color: var(--ink-3); font-size: 13px; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
/* Spacing for cards stacked directly on top of one another. Grid children get
   their spacing from `gap` instead — without this reset the rule below leaks
   in and drops every card except the first by 18px, knocking the first card in
   each row out of alignment with its neighbours. */
.card + .card { margin-top: 18px; }
.grid .card + .card { margin-top: 0; }

.card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.card__head h2, .card__head h3 { font-size: 14px; text-transform: uppercase; letter-spacing: .05em; }
.card__body { padding: 16px; }

/* ------------------------------------------------------------- controls -- */

.toolbar {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  flex-wrap: wrap;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 16px;
}

.field { display: flex; flex-direction: column; gap: 5px; }

.field label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-3);
}

.field select, .field input[type="text"], .field input[type="number"] {
  padding: 7px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 13px;
  min-width: 130px;
}
.field select:focus, .field input:focus { outline: 2px solid var(--brand); outline-offset: -1px; }

.check { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--ink-2); }
.check input { accent-color: var(--brand); width: 15px; height: 15px; }

.btn {
  padding: 8px 15px;
  border: 1px solid var(--brand);
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.btn:hover { background: var(--brand-dark); border-color: var(--brand-dark); }

.btn--ghost { background: transparent; color: var(--brand); }
.btn--ghost:hover { background: var(--brand-tint); }

/* Tab strip for batting / pitching and category switching */
.tabs {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
}

.tabs a {
  padding: 9px 16px;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 600;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
}
.tabs a:hover { color: var(--brand); text-decoration: none; }
.tabs a.is-active { color: var(--brand); border-bottom-color: var(--brand); }

.chips { display: flex; gap: 6px; flex-wrap: wrap; }

.chip {
  display: inline-block;
  padding: 5px 11px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.chip:hover { border-color: var(--brand); color: var(--brand); text-decoration: none; }
.chip.is-active { background: var(--brand); border-color: var(--brand); color: #fff; }

/* ---------------------------------------------------------------- tables -- */

.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table.stats {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

table.stats th, table.stats td {
  padding: 8px 10px;
  text-align: right;
  border-bottom: 1px solid var(--border);
}

table.stats thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-2);
  border-bottom: 2px solid var(--border-strong);
  color: var(--ink-3);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
}
table.stats thead th a { color: inherit; }
table.stats thead th a:hover { color: var(--brand); }

table.stats tbody tr:nth-child(even) { background: var(--surface-2); }
table.stats tbody tr:hover { background: var(--brand-tint); }

/* Player links sit in ink, not brand red: a full column of red competes with
   the highlighted sort column and makes the table hard to scan. */
table.stats tbody a { color: var(--ink); }
table.stats tbody a:hover { color: var(--brand); }

/* Left-aligned identity columns */
.col-rank { width: 46px; text-align: right !important; color: var(--ink-4); font-weight: 700; }
.col-player { text-align: left !important; min-width: 178px; font-weight: 600; }
.col-team, .col-text { text-align: left !important; color: var(--ink-3); }
.col-year { text-align: left !important; font-weight: 600; width: 64px; }

/* Fielding: the one season table with more than one row per season, because a
   fielding line is per position and a player who moved around the diamond gets
   a row for each. Two of the defaults above are wrong for it. The zebra stripe
   counts rows, so a three-position year lands across two shades and reads as
   three years; here it counts seasons instead. And the rule under every row
   would cut a season into its positions, so it is dropped between them and
   kept only under the last one, which leaves each year as one block. */
table.stats--fielding tbody tr:nth-child(even) { background: transparent; }
table.stats--fielding tbody tr.is-alt-season { background: var(--surface-2); }
table.stats--fielding tbody tr:hover { background: var(--brand-tint); }
table.stats--fielding tbody tr.is-continuation td { border-bottom-color: transparent; }
/* Career totals are per position too, so the foot is several rows. Only the
   first carries the heavy rule that separates it from the seasons. */
table.stats--fielding tfoot td { color: var(--ink-3); }

/* The column the board is sorted by */
th.is-sorted, td.is-sorted { background: var(--brand-tint); color: var(--brand); font-weight: 700; }
table.stats tbody tr:hover td.is-sorted { background: transparent; }
th.is-sorted { color: var(--brand) !important; }

.rank-medal { color: var(--gold); }

.table-empty { padding: 40px 16px; text-align: center; color: var(--ink-3); }

/* ------------------------------------------------------------- home grid -- */

/* Flex rather than grid, so a row is always full.
 *
 * This was repeat(auto-fill, minmax(300px, 1fr)), which lays out a fixed number
 * of tracks and leaves the spare ones standing empty — three cards in a
 * four-track row left a quarter of the page blank, and which leagues that hit
 * was arbitrary, since a league's card count follows what it records. auto-fit
 * collapses a wholly empty track but still cannot fill a partial last row.
 *
 * flex-wrap with a 300px basis has no tracks to leave empty: the cards on a row
 * share out whatever that row has. A league with two boards gets two half-width
 * ones, a league with five gets three and then two, and neither has a hole in
 * it. Cards can differ in width from row to row, which is the trade and is the
 * right way round — a wider card is content, an empty track is a bug. */
.grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.grid > * { flex: 1 1 300px; min-width: 0; }

.leader-card__list { list-style: none; margin: 0; padding: 0; }

.leader-card__list li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 7px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.leader-card__list li:last-child { border-bottom: 0; }
.leader-card__list li:nth-child(even) { background: var(--surface-2); }

.leader-card__rank { width: 18px; color: var(--ink-4); font-weight: 700; }
.leader-card__name { flex: 1; font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.leader-card__name a { color: var(--ink); }
.leader-card__name a:hover { color: var(--brand); }
.leader-card__team { color: var(--ink-4); font-size: 12px; }
.leader-card__value { font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------- player photos -- */

.player-photo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  /* Commons crops vary wildly; bias to the top so heads are not cut off. */
  object-position: 50% 12%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  flex-shrink: 0;
  vertical-align: middle;
}

/* The large photo keeps the source proportions instead of being cropped to a
   circle. Of the harvested photos 81% are portrait and the average is roughly
   200x313, so a square crop threw away about a third of the picture — heads
   ended up tight against the frame. Row thumbnails stay circular: at 32px
   there is nothing to lose and the round shape reads better in a table. */
/* Fills the height its column is given, so its bottom edge meets the panel's.
   object-fit keeps the framing sane while it does — a mild crop in a portrait
   box, not the third of the picture a square crop was discarding. */
.player-photo--card {
  width: 100%;
  flex: 1 1 auto;
  min-height: 170px;
  height: auto;
  aspect-ratio: auto;
  border-radius: var(--radius);
  border-width: 1px;
  object-fit: cover;
  object-position: 50% 18%;
}

/* The initials fallback stands in for a photo, so it stretches the same way. */
span.player-photo--card {
  height: auto;
  min-height: 170px;
}

.player-photo--avatar {
  color: #fff;
  font-weight: 700;
  letter-spacing: .02em;
  border-color: transparent;
  user-select: none;
}

/* Photo + name in a table cell */
.player-cell { display: flex; align-items: center; gap: 10px; }
.player-cell__name { overflow: hidden; text-overflow: ellipsis; }

/* Attribution overlays the foot of the photo rather than sitting under it.
   Only the ~42% of photos under CC BY / CC BY-SA carry one, so a credit in
   normal flow made those players' images 23px shorter than everyone else's
   and broke the alignment with the leadership panel. A scrim keeps it legible
   over any picture. */
.photo-credit {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: 18px 9px 6px;
  border-radius: 0 0 var(--radius) var(--radius);
  background: linear-gradient(to top, rgba(0, 0, 0, .72), rgba(0, 0, 0, 0));
  color: rgba(255, 255, 255, .88);
  font-size: 10px;
  line-height: 1.35;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
  pointer-events: auto;
}
.photo-credit a { color: #fff; text-decoration: underline; }
.photo-credit a:hover { color: #fff; }

/* ------------------------------------------------------------ player page -- */

.player-head {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  /* Stretch, not flex-start: the leadership panel sets the row height, and the
     photo fills it so the two line up at the bottom. Pinning the panel to a
     fixed height instead would only align for one player — every Commons
     photo has its own aspect ratio, so the natural photo height varies. */
  align-items: stretch;
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 18px;
}
.player-head__photo {
  flex: 0 0 164px;
  width: 164px;
  display: flex;
  flex-direction: column;
  position: relative;   /* anchors the overlaid photo credit */
}
.player-head__id { flex: 1 1 260px; min-width: 240px; }
.player-head__lead {
  flex: 2 1 420px;
  min-width: 300px;
  display: flex;
  flex-direction: column;
}
.player-head h1 { font-size: 30px; }

/* Career totals are supporting context, not the headline — one quiet line. */
.career-line {
  margin: 12px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.career-line__tag {
  display: inline-block;
  margin-right: 8px;
  color: var(--ink-4);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
}
.career-line__sep { color: var(--ink-4); }

/* --------------------------------------------------------- leadership -- */

/* One composed panel rather than a grid of equal boxes: the headline figure
   is what the page is about, the other four are context. A uniform grid gave
   them all equal weight and wrapped raggedly at in-between widths. */
.lead-panel {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  overflow: hidden;
}

.lead-panel__hero {
  padding: 13px 16px 12px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.lead-hero__label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ink-4);
}

.lead-hero__figure {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 2px;
}

.lead-hero__value {
  font-size: 40px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

/* Green portion also led all of baseball; gold portion led the league only.
   Nested parts of one total, which is why they share a single bar. */
.lead-split {
  display: flex;
  height: 7px;
  margin-top: 10px;
  border-radius: 4px;
  overflow: hidden;
  background: var(--border);
}
.lead-split__major { background: var(--green); }
.lead-split__league { background: var(--gold); }

.lead-split__key {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin-top: 7px;
  font-size: 11px;
  color: var(--ink-3);
}
.lead-split__key .swatch { margin-right: 5px; }

/* Supporting figures: an evenly divided rail, so they can never wrap into an
   orphaned row the way grid cells did. */
.lead-panel__rail { display: flex; }

.lead-stat {
  flex: 1 1 0;
  min-width: 0;
  padding: 9px 8px 10px;
  text-align: center;
  border-left: 1px solid var(--border);
}
.lead-stat:first-child { border-left: 0; }

.lead-stat__value {
  display: block;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.lead-stat__label {
  display: block;
  margin-top: 3px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-4);
  line-height: 1.3;
}

.lead-panel { flex: 1 1 auto; display: flex; flex-direction: column; }
.lead-panel__rail { margin-top: auto; }
.lead-panel__note { margin: 8px 0 0; color: var(--ink-3); font-size: 12px; }

@media (max-width: 560px) {
  .lead-hero__value { font-size: 38px; }
  .lead-panel__rail { flex-wrap: wrap; }
  .lead-stat { flex: 1 1 50%; }
  .lead-stat:nth-child(3) { border-left: 0; }
  .lead-stat:nth-child(n+3) { border-top: 1px solid var(--border); }
}

.lead-empty {
  padding: 18px;
  background: var(--surface-2);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: 13px;
  line-height: 1.6;
}
.lead-empty strong { display: block; margin-bottom: 3px; }

/* ------------------------------------------------------ all-time standing -- */

.standing {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
}
.standing__col {
  flex: 1 1 240px;
  padding: 16px;
  min-width: 240px;
}
.standing__col--wide { flex: 2 1 420px; border-left: 1px solid var(--border); }

.standing__title {
  margin-bottom: 10px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-4);
}

.standing__list { list-style: none; margin: 0; padding: 0; }
.standing__list--grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
  gap: 0 20px;
}

.standing__list li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}

.standing__rank {
  min-width: 42px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
/* Top ten all-time is the line worth drawing attention to. */
.standing__rank.is-elite { color: var(--green); }

.standing__label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.standing__label a { color: var(--ink); }
.standing__label a:hover { color: var(--brand); }

.standing__value { font-weight: 700; font-variant-numeric: tabular-nums; }

/* Shown when a player reaches no career top 500 — which is most of them. The
   column stays in place so the ranks beside it keep their column width. */
.standing__empty {
  padding: 14px 15px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-3);
}
.standing__empty strong {
  display: block;
  margin-bottom: 2px;
  color: var(--ink-2);
  font-size: 13px;
}

.standing__note { margin: 10px 0 0; color: var(--ink-4); font-size: 11px; }

@media (max-width: 720px) {
  .standing__col--wide { border-left: 0; border-top: 1px solid var(--border); }
}

/* Triple Crowns — the rarest thing in the data */
.crown-strip { display: grid; gap: 10px; margin-bottom: 18px; }

.crown {
  padding: 14px 18px;
  border-radius: var(--radius);
  background: linear-gradient(100deg, rgba(184, 134, 11, .16), rgba(184, 134, 11, .05));
  border: 1px solid rgba(184, 134, 11, .4);
}
.crown__title {
  font-size: 15px;
  font-weight: 700;
  color: var(--gold);
  letter-spacing: .01em;
}
.crown__detail { margin-top: 3px; font-size: 13px; color: var(--ink-2); }

.note--streak { border-left-color: var(--green); margin-bottom: 18px; }

/* Current league leader: an award for leading a season still being played.
   Gold like the Triple Crown, with a trophy, because it is the same kind of
   honour read in the present tense. */
.award {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 14px 18px;
  margin-bottom: 18px;
  border-radius: var(--radius);
  background: linear-gradient(100deg, rgba(184, 134, 11, .18), rgba(184, 134, 11, .04));
  border: 1px solid rgba(184, 134, 11, .45);
}
.award__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  border-radius: 50%;
  background: var(--gold);
  color: var(--surface);
}
.award__body { min-width: 0; }
.award__eyebrow {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--gold);
}
.award__asof {
  margin-left: 6px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink-3);
}
.award__title { margin-top: 2px; font-size: 17px; font-weight: 700; color: var(--ink); }
.award__list { margin-top: 8px; display: flex; flex-wrap: wrap; }
.award__note { margin-top: 2px; font-size: 12px; color: var(--ink-3); }

/* A figure that led the league, on the year-by-year tables. */
.stat-led {
  display: inline-block;
  padding: 1px 5px;
  margin: -1px -5px;
  border-radius: 3px;
  background: var(--led-bg);
  color: var(--led-ink);
  font-weight: 700;
  cursor: help;
}
.stat-led--key {
  width: 11px; height: 11px;
  padding: 0; margin: 0 2px 0 0;
  vertical-align: -1px;
  cursor: default;
}

/* Legend swatches in the card header */
.swatch {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 2px;
  vertical-align: baseline;
}
.swatch--major { background: var(--green); }
.swatch--gold { background: var(--gold); }

/* Title tables hold wrapping badge lists, so let those cells breathe. */
table.stats--titles td.col-text { white-space: normal; }
table.stats--titles td { vertical-align: top; padding-top: 10px; }
table.stats--titles .badge { margin: 0 4px 4px 0; }

.badge--near {
  background: var(--surface-2);
  color: var(--ink-3);
  box-shadow: inset 0 0 0 1px var(--border);
  font-weight: 600;
}
.player-head__meta { margin: 6px 0 0; color: var(--ink-3); font-size: 13px; }

.bio-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 14px 22px;
  margin-top: 16px;
}
.bio-grid dt {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-4);
}
.bio-grid dd { margin: 2px 0 0; font-size: 14px; font-weight: 600; }

.stat-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 10px;
  margin-top: 4px;
}
.stat-tile {
  padding: 11px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  text-align: center;
}
.stat-tile__label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-4);
}
.stat-tile__value {
  font-size: 21px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border-radius: var(--radius-sm);
  background: var(--brand-tint);
  color: var(--brand);
  font-size: 12px;
  font-weight: 700;
  margin: 0 5px 5px 0;
}
/* Season badges are links to the board they came from. Keep the badge's own
   colour rather than the global link red, and lift slightly on hover so they
   read as clickable without turning the table into a wall of underlines. */
a.badge {
  cursor: pointer;
  transition: filter .12s ease, box-shadow .12s ease, transform .12s ease;
}
a.badge:hover,
a.badge:focus-visible {
  text-decoration: none;
  filter: brightness(1.06);
  box-shadow: 0 0 0 1px currentColor inset, 0 1px 3px rgba(16, 20, 26, .18);
  transform: translateY(-1px);
}
a.badge:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

.badge--gold { background: rgba(184, 134, 11, .12); color: var(--gold); }

/* Led all of Major League Baseball, not just one league — the top tier of
   honour, so it gets its own colour and drops the league name entirely. */
.badge--major {
  background: var(--green-tint);
  color: var(--green);
  box-shadow: inset 0 0 0 1px var(--green-line);
}

/* ------------------------------------------------------------- utilities -- */

.muted { color: var(--ink-3); }
.small { font-size: 12px; }
.note {
  padding: 11px 14px;
  background: var(--surface-2);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  font-size: 13px;
}

.pager { display: flex; align-items: center; gap: 10px; padding: 12px 16px; }
.pager__spacer { flex: 1; }

.placeholder {
  padding: 56px 24px;
  text-align: center;
  color: var(--ink-3);
}
.placeholder h2 { color: var(--ink-2); margin-bottom: 8px; }
.placeholder__badge {
  display: inline-block;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  margin-bottom: 14px;
}

.site-foot {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: 22px 20px;
  color: var(--ink-3);
  font-size: 12px;
}
.site-foot__inner { max-width: 1240px; margin: 0 auto; display: flex; gap: 16px; flex-wrap: wrap; }
.site-foot__inner p { margin: 0; }

/* The support line. Takes a row to itself rather than flowing beside the
   credits: it is the only line down here meant to be read rather than
   scanned past, and wrapped into the flex row it would look like a third
   column of small print. Brand tint so the link can be found, footer type
   size so it never competes with the page above it. Both tints are already
   redefined for dark mode with the rest of the palette. */
.site-foot__support {
  flex: 1 0 100%;
  margin-top: 4px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--brand-tint);
  color: var(--ink-2);
}
.site-foot__support a { font-weight: 700; color: var(--brand); }

@media (max-width: 720px) {
  .masthead__inner { gap: 12px; }
  .masthead__search { margin-left: 0; width: 100%; }
  .masthead__search input { width: 100%; }
  .brand img { height: 54px; }
  h1 { font-size: 21px; }

  /* On a phone the masthead is already stacked rows, and a wordmark pushed
     against the left edge of the top row reads as the first item in a list
     rather than as the name of the site. Centred it is the masthead. The row
     below it is centred with it, because a centred mark over a left-aligned
     row of league badges looks like the centring was an accident. */
  .brand { width: 100%; justify-content: center; }
  .sport-nav { width: 100%; justify-content: center; }
}

/* ==========================================================================
   Admin panel (/admin)
   Reuses the public components; only the few admin-specific pieces live here.
   ========================================================================== */

.admin-badge {
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
}

.admin-login { max-width: 380px; margin: 40px auto; }

.flash {
  padding: 11px 14px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  margin-bottom: 16px;
}
.flash--ok  { background: var(--green-tint); color: var(--green);
              box-shadow: inset 0 0 0 1px var(--green-line); }
.flash--err { background: var(--brand-tint); color: var(--brand);
              box-shadow: inset 0 0 0 1px rgba(178, 37, 36, .3); }

/* Photo and credit sit side by side; the details form takes the full width. */
.admin-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 18px;
  align-items: start;
}
.admin-cols__wide { grid-column: 1 / -1; }

.admin-photo { display: flex; justify-content: center; }
/* Outside the player-head flex row the card photo has no height to fill, so
   give it one here rather than letting it collapse. */
.admin-photo .player-photo--card { width: 164px; flex: 0 0 auto; height: 210px; }

.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px 16px;
}
.admin-grid .field input,
.admin-grid .field select { width: 100%; }

/* The ad booking form. Two or three columns of fields, each with room for the
   sentence explaining what it does — a placement has enough switches on it
   (weight, cap, flight dates, nofollow) that a bare label is not enough, and
   the explanation belongs beside the field rather than in a manual. */
.admin-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 16px 18px;
  padding: 16px;
  align-items: start;
}
.admin-form .field input[type="text"],
.admin-form .field input[type="email"],
.admin-form .field input[type="number"],
.admin-form .field input[type="date"],
.admin-form .field input[type="file"],
.admin-form .field select,
.admin-form .field textarea { width: 100%; }

/* The date and email inputs are not covered by the public form styling, which
   only ever needed text and number. */
.field input[type="email"],
.field input[type="date"],
.field textarea {
  padding: 7px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 13px;
}
.field textarea { resize: vertical; line-height: 1.5; }

.field__hint {
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-3);
}
.field__hint code {
  font-family: var(--mono);
  font-size: 10px;
}

.admin-cols code, .page-head code {
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--surface-2);
  font-family: var(--mono);
  font-size: 12px;
}

/* ==========================================================================
   Front page
   Built around leaders rather than a leaderboard, so the components here are
   faces and reigns rather than dense stat rows.
   ========================================================================== */

/* The hero block that used to open this page is gone; .home-brief further down
   is what replaced it. */

.section-head { margin-top: 30px; }
.section-head h2 { font-size: 20px; }

/* ---------------------------------------------------- spotlight players -- */

/* Fixed column counts, never auto-fit: there are always four cards, and letting
   the browser choose gave three across with the fourth orphaned on its own row.
   One, two, then all four — every step divides four evenly.

   The four-across step also changes the card's shape. Side by side, a 140px
   portrait plus a name plus a 40px number needs about 460px of card; at a
   quarter of the page there is half that, so the card stands the photo on top
   of the text instead of beside it. Same components, turned through ninety
   degrees. */
.spotlight-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}
@media (min-width: 700px) {
  .spotlight-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1100px) {
  .spotlight-grid { grid-template-columns: repeat(4, 1fr); }

  .spotlight-grid .spot { flex-direction: column; gap: 13px; }

  /* Capped at 180 rather than stretched to the card. The stored file is 200px
     wide and upscaling it shows — which is the reason this card was two-across
     in the first place. */
  .spotlight-grid .spot__photo {
    flex: none;
    width: 100%;
    max-width: 180px;
    margin: 0 auto;
  }
  .spotlight-grid .player-photo--tile {
    width: 100%;
    height: auto;
    aspect-ratio: 140 / 180;
  }
  /* The initials avatar is a span, so it has no intrinsic ratio to hold it
     open the way the image does. */
  .spotlight-grid span.player-photo--tile { aspect-ratio: auto; height: 232px; }

  .spotlight-grid .spot__name { font-size: 16px; white-space: nowrap; }
  .spotlight-grid .spot__count { margin-top: 10px; }
  .spotlight-grid .spot__count-num { font-size: 34px; }
}

/* An editorial card rather than a profile chip: upright portrait on the left,
   the numbers that justify the spotlight on the right. Two per row keeps the
   photo at 140px, which is under the 200px stored width — a four-across grid
   stretched it past its native size and it showed. */
.spot {
  display: flex;
  gap: 16px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  color: var(--ink);
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.spot:hover {
  text-decoration: none;
  transform: translateY(-2px);
  border-color: var(--brand);
  box-shadow: 0 6px 20px rgba(16, 20, 26, .13);
}

.spot__photo { position: relative; flex: 0 0 140px; }

.player-photo--tile {
  width: 140px;
  height: 180px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  object-position: 50% 16%;
  border: 1px solid var(--border);
  display: block;
}
span.player-photo--tile { display: flex; }

/* ---------------------------------------------------------- triple crowns -- */

/* A roll of honour, not a ranking — see the note at the markup. Tiles rather
   than rows, sized so a face is recognisable at a glance and the year reads as
   the label on a portrait.
 *
 * auto-fill, not auto-fit, and this is the one place on the site that wants it:
 * a league with three members should get three tiles at their proper size with
 * the row unfilled beside them, not three tiles stretched a third of the page
 * wide each. The unit here is the portrait, and stretching it past the 200px
 * file it comes from would visibly soften every face in the row. */
.crown-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 14px;
  padding: 16px;
}

/* crown-tile, not crown: .crown is already the player page's gold Triple Crown
   strip, and reusing the name handed every tile that rule's padding, border and
   gradient. */
.crown-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  color: var(--ink);
  min-width: 0;
}
.crown-tile:hover { text-decoration: none; }

/* One fixed box for every tile, photo or initials.
 *
 * A ratio rather than a height was the obvious way and the wrong one here: the
 * initials avatar is a span with no intrinsic ratio, so it sized from its
 * height while the images sized from their width, and a row containing one of
 * each had its captions on two different lines. A flat height cannot disagree
 * with itself, and object-fit does the framing either way. */
.crown-tile .player-photo--tile {
  width: 100%;
  height: 176px;
  flex: 0 0 auto;
  margin-bottom: 7px;
  transition: border-color .12s ease;
}
.crown-tile:hover .player-photo--tile { border-color: var(--brand); }

.crown-tile__year {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .06em;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}
.crown-tile__name {
  font-weight: 700;
  font-size: 13.5px;
  line-height: 1.25;
}
.crown-tile:hover .crown-tile__name { color: var(--brand); }
.crown-tile__league {
  font-size: 11px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* All-time standing, sat on the portrait — the one number that says why this
   player is worth looking at. */
.spot__rank {
  position: absolute;
  left: 0;
  bottom: 0;
  padding: 5px 9px;
  border-radius: 0 var(--radius-sm) 0 var(--radius-sm);
  background: var(--brand);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.spot__body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.spot__name {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -.01em;
  overflow: hidden;
  text-overflow: ellipsis;
}
.spot__years { margin-top: 1px; color: var(--ink-4); font-size: 12px; }

.spot__count { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.spot__count-num {
  font-size: 40px;
  font-weight: 700;
  line-height: .95;
  letter-spacing: -.03em;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}
.spot__count-label {
  font-size: 11px;
  font-weight: 600;
  line-height: 1.3;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-4);
}

.spot__split {
  display: flex;
  height: 6px;
  margin-top: 11px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--border);
}
.spot__split span { background: var(--green); }
.spot__split span.is-league { background: var(--gold); }

.spot__key { margin-top: 6px; font-size: 11px; color: var(--ink-3); }

.spot__sig {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: auto;
  padding-top: 11px;
  border-top: 1px solid var(--border);
  font-size: 12px;
}
.spot__sig-label { color: var(--ink-2); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spot__sig-count { color: var(--brand); font-weight: 700; font-variant-numeric: tabular-nums; }

@media (max-width: 420px) {
  .spot { flex-direction: column; align-items: center; text-align: center; }
  .spot__sig { width: 100%; }
}


/* ------------------------------------------------------------- boards -- */

.board { list-style: none; margin: 0; padding: 0; }

.board li {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.board li:last-child { border-bottom: 0; }
.board li:nth-child(even) { background: var(--surface-2); }

.board__rank {
  flex: 0 0 auto;
  min-width: 26px;
  text-align: center;
  color: var(--ink-4);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.board__rank.is-first  { color: var(--gold); }
.board__rank.is-streak { color: var(--green); font-size: 17px; }
.board__rank.is-crown  { color: var(--gold); font-size: 12px; min-width: 38px; }

.board__player {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  color: var(--ink);
}
.board__player:hover { color: var(--brand); text-decoration: none; }
.board__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.board__name small { display: block; color: var(--ink-4); font-weight: 400; font-size: 11px; }

.board__team  { color: var(--ink-4); font-size: 12px; }
.board__note  { color: var(--ink-3); font-size: 12px; text-align: right; }
.board__value { font-weight: 700; font-variant-numeric: tabular-nums; min-width: 46px; text-align: right; }
.board__value--big { font-size: 20px; color: var(--brand); }

.board__split {
  display: flex;
  flex-direction: column;
  gap: 1px;
  text-align: right;
  font-size: 11px;
  color: var(--ink-4);
}
.board__major { color: var(--green); }

/* The rich board gives its faces more room. */
.board--rich li { padding: 11px 16px; }
.board--rich .player-photo--round { width: 44px; height: 44px; border-width: 1px; }

/* Both modifiers now only set the width a card wants before it wraps; the
   filling is .grid's job. See the note there for why this is flex. */
.grid--two > * { flex-basis: 340px; }
.grid--three > * { flex-basis: 300px; }

/* The rich board carries a photo, a name, a two-part sub-label and a big
   number. In a third of the page the sub-label is what has to go — it is the
   only part repeated elsewhere on the card. */
@media (max-width: 1240px) {
  .grid--three .board--rich .board__split { display: none; }
}


@media (max-width: 640px) {
  .board__split, .board__note { display: none; }
}

/* A utility bar directly under the nav: for the visitor who already knows the
   season they want and does not need the spotlight to sell them one. Deliberately
   quieter than the hero it sits above — one line, no card chrome. */
.browse-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 16px;
  margin-bottom: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.browse-bar__label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-4);
}

.browse-bar__field { display: flex; align-items: center; gap: 7px; }
.browse-bar__field > span {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-3);
}
.browse-bar__field select {
  padding: 6px 9px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}
.browse-bar__field select:focus { outline: 2px solid var(--brand); outline-offset: -1px; }

.browse-bar .btn { padding: 6px 13px; }

.browse-bar__link {
  margin-left: auto;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.browse-bar__link:hover { color: var(--brand); }
/* A second link sits beside the first rather than being pushed apart from it. */
.browse-bar__link + .browse-bar__link { margin-left: 0; }

@media (max-width: 620px) {
  .browse-bar__label { width: 100%; }
  .browse-bar__link { margin-left: 0; }
}

/* ==========================================================================
   Landing page: two-column hub, sponsor slots, browse matrix
   ========================================================================== */

/* -------------------------------------------------------- sponsor slots -- */

/* Every slot reserves its height whether or not it is sold. A slot that
   collapses when empty and expands when filled moves the page under the
   reader, which is the layout shift Core Web Vitals measures and ranks on.
   An unsold slot is not blank any more: it carries a quiet house creative
   linking to the rate card. See .ad-slot__house at the end of this file for
   why, and why it must stay clickable. */
/* Room on both sides, not just below. The margin used to be bottom-only, which
   left every in-flow slot pressed against whatever module ended above it —
   an advertisement touching the content is the layout that makes a reader think
   the ad is part of the article, and it is the one thing a placement should
   never be mistaken for. 30px is a clear break at both edges. */
.ad-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 6px;
  margin: 30px 0;
  overflow: hidden;
}
.ad-slot img { max-width: 100%; height: auto; display: block; }

/* The header banner is the first thing in the wrap on every page, so its top
   margin is doubling the wrap's own padding. Only the gap below it is wanted. */
.wrap > .ad-slot--leaderboard:first-child { margin-top: 0; }

/* Unsold slot, drawn only off a production server. An empty slot and a broken
   layout look exactly alike, so while the site is being built the inventory
   says what it is and what size artwork it wants.

   Deliberately loud. This is scaffolding, not decoration — the first version
   was toned to sit politely in the design and the result was inventory nobody
   could find on the page. Diagonal hatching is the standard visual language
   for reserved space and reads as obviously-not-content in either theme. */
.ad-slot__ph {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  max-width: 100%;
  background-color: var(--surface-2);
  background-image: repeating-linear-gradient(
    45deg,
    var(--ad-hatch) 0, var(--ad-hatch) 1px,
    transparent 1px, transparent 9px
  );
  border: 2px dashed var(--ink-4);
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  text-align: center;
}
.ad-slot__ph b {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  /* Sits on the hatching, so it needs its own ground to stay readable. */
  background: var(--surface);
  padding: 2px 10px;
  border-radius: var(--radius-sm);
}
.ad-slot__ph span {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  background: var(--surface);
  padding: 1px 8px;
  border-radius: var(--radius-sm);
}

/* A short slot has no room for the label to sit above the size line. */
.ad-slot--leaderboard .ad-slot__ph,
.ad-slot--footer .ad-slot__ph { flex-direction: row; gap: 10px; }

.ad-slot__label {
  align-self: flex-start;
  font-size: 10px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* The rail is a stack of cards 16px apart and the slots are part of that
   rhythm, so they keep the column's spacing rather than the 30px used in the
   reading flow. Spacing on both sides — bottom-only left the lower slot sitting
   flush against the promo card above it — but never above the first, which has
   to line up with the top of the main column beside it. */
.ad-slot--rail, .ad-slot--rail_small { margin: 16px 0; }
.home-rail > .ad-slot:first-child { margin-top: 0; }

/* Sits between the last of the page and the footer rule, so it needs the full
   break above and enough below that it is not sitting on the border. */
.ad-slot--footer { margin: 30px 0 26px; }

/* The rail does not exist below the breakpoint, so its slots must not hold
   open 850px of nothing on a phone. min-height is set inline, which is why
   this needs the override. */
@media (max-width: 1080px) {
  .ad-slot--desktop { display: none !important; min-height: 0 !important; }
}

/* ------------------------------------------------------------ home grid -- */

.home-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 28px;
  align-items: start;
}
.home-main { min-width: 0; }

/* Not sticky. A rail that follows the screen is the standard trick for ad
   viewability, and it makes the content beside it — a birthday list — trail
   the reader down four thousand pixels of page it has nothing to do with.
   The rail scrolls away with everything else. */
.home-rail { position: static; }

@media (max-width: 1080px) {
  .home-layout { grid-template-columns: minmax(0, 1fr); }
}

/* A rail card that fills the height the rail has left.

   With the advertising off the rail ends long before the main column does, and
   the white column beside the rest of the page reads as something missing. The
   rail is stretched to the main column's height, .rail-fill takes whatever is
   left of it, and the card inside is positioned out of flow so its own length
   never makes the rail taller: it is as tall as its rows or as the gap,
   whichever is less.

   Rows that do not fit are not cut in half. The list is a column flexbox that
   wraps, each row a full column wide, so a row that would overflow wraps into
   a second column that overflow: hidden keeps out of sight. */
@media (min-width: 1081px) {
  .home-rail { align-self: stretch; display: flex; flex-direction: column; }
  .rail-fill { flex: 1 1 auto; position: relative; min-height: 380px; }
  .rail-fill:first-child { margin-top: 0; }
  .rail-fill > .card {
    position: absolute;
    top: 0; left: 0; right: 0;
    max-height: 100%;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
  }
  .board--fill {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    align-content: flex-start;
    overflow: hidden;
  }
  .board--fill li { width: 100%; }
}
.rail-fill { margin-top: 18px; }
@media (max-width: 1080px) {
  /* Below the breakpoint the rail is a stack under the page, with no gap to
     fill, so the card is an ordinary card and a short one. */
  .board--fill li:nth-child(n+11) { display: none; }
}
.board--fill .board__note strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.board--fill .board__note strong { font-size: 13px; }

/* Club logos. Several marks are navy or black and vanish on the dark ground,
   so in dark mode each gets a hairline light halo that follows its shape. */
.team-logo { flex: 0 0 auto; object-fit: contain; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .team-logo {
    filter: drop-shadow(0 0 1px rgba(255, 255, 255, .55));
  }
}
:root[data-theme="dark"] .team-logo { filter: drop-shadow(0 0 1px rgba(255, 255, 255, .55)); }

/* Clubs with a dark-ground version: swap it in by theme, and it needs no halo. */
.team-logo--dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .team-logo--light { display: none; }
  :root:not([data-theme="light"]) .team-logo--dark { display: inline-block; filter: none; }
}
:root[data-theme="dark"] .team-logo--light { display: none; }
:root[data-theme="dark"] .team-logo--dark { display: inline-block; filter: none; }

.card__icon { vertical-align: -4px; margin-right: 6px; }

.card__foot {
  margin: 0;
  padding: 10px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}
.card__foot a { margin-left: 4px; }

/* The puzzle card in the rail. Its foot is a call to action rather than a
   footnote, so the button gets the full width of the card and none of the
   left indent .card__foot gives a trailing link. */
.card--game .card__body p { margin: 0 0 8px; }
.card--game .card__body p:last-child { margin-bottom: 0; }
.card--game .card__foot { padding: 12px 16px; }
.card--game .card__foot .btn { display: block; margin-left: 0; text-align: center; }

/* ---------------------------------------------------------------------------
   A season still being played.

   The card is the same card; the only difference is a tinted top edge, a dot,
   a date and a bar showing how much season is left. That restraint is
   deliberate. Everything else on this page is settled history, and the live
   board earns attention by being the one thing that moved since yesterday,
   not by being louder than a century of finished seasons.
   --------------------------------------------------------------------------- */

.card--live { border-top: 2px solid var(--accent); }

/* Pulses, because a static dot beside a date reads as a bullet point. Anyone
   who has asked their system not to animate gets the dot without the pulse:
   the information is in the colour, and the motion is decoration. */
.live-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: 7px;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: middle;
  animation: live-pulse 2.4s ease-in-out infinite;
}
@keyframes live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .45; transform: scale(.82); }
}
@media (prefers-reduced-motion: reduce) {
  .live-dot { animation: none; }
}

.live-stamp {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 0;
  padding: 10px 16px 8px;
  color: var(--ink-3);
}
.live-stamp__date {
  font-weight: 700;
  color: var(--accent-text);
  text-transform: uppercase;
  letter-spacing: .05em;
  font-size: 11px;
}
.live-stamp__games { font-variant-numeric: tabular-nums; }

/* How much season is left to change the board. Two thirds full in August is
   the honest answer to "is this decided yet", and it says it faster than the
   sentence beside it. */
.season-bar {
  height: 3px;
  margin: 0 16px 12px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}
.season-bar__fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
}

/* ---------------------------------------------------------------------------
   A grid of small boards: one card per category, five names in each.

   The unit the season pages are built from. A minitable is a list of links
   dressed as a table; this is meant to read as a leaderboard at a glance, so
   the rank is a real column, the values line up on their own edge, and first
   place is the only row given weight.
   --------------------------------------------------------------------------- */

.livegrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
  margin: 16px 0 22px;
}

/* Cancel the stacked-cards margin, as every other grid container here does.
   Without it the second card onward is pushed down 18px while the first is
   not, so the first card in each row sits high and stretches to compensate.
   It only shows when a season is in progress, because that is the only time
   this grid holds more than one card. */
.livegrid .card + .card { margin-top: 0; }

.livegrid__card { display: flex; flex-direction: column; }
.livegrid__card .card__head h3 { margin: 0; }
.livegrid__card .card__head h3 a { color: inherit; }
.livegrid__card .card__head h3 a:hover { color: var(--brand); }
.livegrid__card .card__foot { margin-top: auto; }

.livegrid__board {
  list-style: none;
  margin: 0;
  padding: 6px 0;
}
.livegrid__board li {
  display: grid;
  /* Fixed rank and value columns so five names form a column rather than five
     independently centred rows. */
  grid-template-columns: 22px minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 8px;
  padding: 4px 14px;
  font-size: 13px;
}
.livegrid__board li.is-leader { font-weight: 700; }

.livegrid__rank {
  color: var(--ink-4);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.livegrid__board li.is-leader .livegrid__rank { color: var(--accent-text); }

.livegrid__name {
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.livegrid__value { font-variant-numeric: tabular-nums; }

/* The season page gives the grid the full width, so it can hold four across
   where the league page's main column holds three. */
.livegrid--page { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }

/* The "129 of 162 games played" line, with the bar sharing its row. The bar
   is the wider half: it is the part read at a glance. */
.live-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 16px;
  color: var(--ink-3);
}
.live-progress__text { flex: 0 0 auto; }
.live-progress .season-bar { flex: 1 1 auto; margin: 0; min-width: 80px; }

.season-scope { margin-bottom: 16px; }

/* "Batting" / "Pitching" over each half of the season page. A quiet rule
   rather than a heading block: it separates two grids that are already
   visually dense, and competing with them would be noise. */
.season-group {
  margin: 22px 0 0;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-3);
}
.season-group + .livegrid { margin-top: 12px; }

.card--promo { padding: 16px; }
.card--promo h3 { font-size: 14px; text-transform: uppercase; letter-spacing: .05em; }
.card--promo p { margin: 6px 0 12px; }

/* ----------------------------------------------- last-completed-season -- */

/* Three stacked top-threes per league. Deliberately not a table: the columns
   are independent leaderboards that happen to sit side by side, and a table
   would claim a relationship between the rows that does not exist. */
.minitable {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}
.minitable__col { padding: 12px 14px; border-right: 1px solid var(--border); min-width: 0; }
.minitable__col:last-child { border-right: 0; }

.minitable__head {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 7px;
}
.minitable__head:hover { color: var(--brand); text-decoration: none; }

.minitable ol { list-style: none; margin: 0; padding: 0; }
.minitable li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 3px 0;
  font-size: 13px;
  min-width: 0;
}
.minitable li a {
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.minitable li:first-child a { font-weight: 700; }
.minitable li b { font-variant-numeric: tabular-nums; color: var(--ink-2); }

/* --------------------------------------------------- cross-league board -- */

.board--compact li { padding: 7px 14px; }
.board--compact .board__note { font-size: 11px; }

/* A league tag, so a combined board says which sport each row came from
   without spending a column on it. */
.board__league {
  display: inline-block;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .06em;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--ink-3);
}

/* ---------------------------------------------------- browse everything -- */

/* 300px, not 340: a 340px minimum is wider than the content box on a 375px
   phone, so the track overflows its own container by a few pixels. */
/* Flex-filled for the same reason .grid is: the number of blocks here is the
   number of groups a league records — two for baseball, five for football —
   and a track layout leaves the remainder standing empty. */
.browse {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
/* 280 rather than 300 so the landing page's four leagues sit abreast at full
   width: four 300s plus their gaps overflow 1200 by a hair and drop one league
   onto a row of its own. */
.browse > * { flex: 1 1 280px; min-width: 0; }

.browse__league {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px 16px;
}
.browse__league > h3 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .05em;
  margin: 0 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.browse__league > h3 a { color: var(--ink); }
.browse__league > h3 a:hover { color: var(--brand); }

.browse__group + .browse__group { margin-top: 12px; }

.browse__group-label {
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 6px;
}

/* The browse block is the crawl surface, so it carries a couple of hundred
   links. At full chip size that is a wall; tightened, it reads as an index. */
.chips--tight { gap: 4px; }
.chips--tight .chip { padding: 3px 8px; font-size: 11px; }
.chips--wide .chip { padding: 7px 14px; font-size: 13px; }

/* Chips in a 300px column. Tighter than the reading-flow set, because a rail
   card holding six of them should be six lines shorter than the page's. */
.chips--rail { gap: 5px; }
.chips--rail .chip { padding: 4px 9px; font-size: 11.5px; }

.chip--all { border-style: dashed; color: var(--ink-3); }

/* ---------------------------------------------------------- season index -- */

.season-index { display: flex; flex-direction: column; gap: 14px; }

.season-decade {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 12px 16px 14px;
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr);
  gap: 14px;
  align-items: baseline;
}
/* The linked-to decade, so arriving from the landing page lands somewhere
   visible rather than at an anonymous block. */
.season-decade.is-focus { border-color: var(--brand); }

.season-decade h2 {
  font-size: 15px;
  letter-spacing: -.01em;
  color: var(--ink-3);
  margin: 0;
}

.season-decade__years {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.season-decade__years a {
  display: inline-block;
  min-width: 52px;
  text-align: center;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.season-decade__years a:hover {
  border-color: var(--brand);
  color: var(--brand);
  text-decoration: none;
}

@media (max-width: 620px) {
  .season-decade { grid-template-columns: minmax(0, 1fr); gap: 8px; }
}

/* ------------------------------------------------------------ footer map -- */

/* Appears on every page in the site, which is what makes it the reliable
   route from any deep page back up to the hubs. */
.site-foot__map {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 18px;
  width: 100%;
  padding-bottom: 20px;
  margin-bottom: 18px;
  /* The footer sits on --surface, which is white in light mode — a hardcoded
     translucent-white rule is invisible there. */
  border-bottom: 1px solid var(--border);
}
.site-foot__map h2 {
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  margin: 0 0 8px;
  opacity: .65;
}
.site-foot__map ul { list-style: none; margin: 0; padding: 0; }
.site-foot__map li + li { margin-top: 5px; }
.site-foot__map a { font-size: 13px; opacity: .85; }
.site-foot__map a:hover { opacity: 1; }

.wrap--flush { padding-top: 0; padding-bottom: 0; }

.note {
  margin: -6px 0 14px;
  padding: 9px 12px;
  border-left: 3px solid var(--border-strong);
  background: var(--surface-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
/* Twelve-row board as two columns of six. array_chunk preserves the original
   keys, so the rank span still prints the real position rather than 1-6 twice. */
.board-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 16px;
  align-items: start;
}
.board-split .card + .card { margin-top: 0; }
.board-split .board--rich li { padding: 9px 12px; gap: 9px; }
.board-split .board--rich .player-photo--round { width: 36px; height: 36px; }
.board-split .board__value--big { font-size: 17px; min-width: 32px; }
.board-split .board__cats { white-space: nowrap; }
/* --------------------------------------------------------- game promo -- */

/* The banner row: puzzle on the left, top ad on the right, sharing the band.
   The ad column is sized by its own creative rather than by a fraction, so a
   728px banner is never scaled and the puzzle simply takes what is left. */
/* Page title and the site's three totals, on one line. This replaced the hero
   block that used to open both the landing page and every league page: it cost
   most of a screen to restate the meta description and offer a third copy of
   the search box that is already in the masthead. Everything below it — the
   season jump, the puzzle, the leaderboards — is what people actually came
   for, and now it is above the fold. */
.home-brief {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 14px 26px;
  margin-bottom: 16px;
}
.home-brief h1 {
  margin: 0;
  font-size: 24px;
  letter-spacing: -.02em;
}
.home-brief__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  margin: 0;
}
.home-brief__stats div { display: flex; align-items: baseline; gap: 7px; }
/* --ink-3 rather than the --ink-4 the old hero used for the same labels: at
   11px on white, ink-4 is 2.4:1 and this is the line carrying what each number
   means. */
.home-brief__stats dt {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-3);
}
.home-brief__stats dd {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

@media (max-width: 620px) {
  .home-brief h1 { font-size: 20px; }
  .home-brief__stats { gap: 6px 16px; }
  .home-brief__stats dd { font-size: 14px; }
}

/* Season jump and the daily puzzle, side by side. The puzzle used to sit up on
   the ad row; it belongs next to the controls, which is where a returning
   reader is already looking. */
.home-jump {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: stretch;
  margin-bottom: 16px;
}
.home-jump .browse-bar { margin-bottom: 0; }
.home-jump .game-promo { min-width: 260px; }

@media (max-width: 900px) {
  .home-jump { grid-template-columns: 1fr; }
}

/* Solid colour block, not a bordered card. It is the one thing on the page
   asking for a click rather than a read, and at card weight it disappeared
   into the cards under it. Indigo→teal rather than the brand red: see the
   --accent note at the top of the file. */
.game-promo {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12px;
  padding: 16px 20px;
  border-radius: var(--radius);
  background: linear-gradient(105deg, var(--accent), var(--accent-2));
  color: #fff;
  box-shadow: var(--shadow);
}

.game-promo__main { display: flex; align-items: center; gap: 10px; }
.game-promo__main:hover { text-decoration: none; }
.game-promo__main:hover .game-promo__title { text-decoration: underline; }

.game-promo__tag {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: #fff;
  padding: 5px 9px;
  border-radius: var(--radius-sm);
}
.game-promo__title {
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.01em;
  color: #fff;
}

/* One chip per league plus the mixed set. The league marks are full-colour
   logos on a coloured ground, so each gets its own light pad to sit on rather
   than being knocked out or tinted. */
.game-promo__leagues { display: flex; flex-wrap: wrap; gap: 6px; }
.game-promo__league {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 34px;
  padding: 0 8px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, .92);
  color: var(--accent-ink);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.game-promo__league img { width: 24px; height: 24px; display: block; }
.game-promo__league:hover {
  background: #fff;
  text-decoration: none;
  transform: translateY(-1px);
}
.game-promo__league.is-all {
  /* The mixed set is the default the title already links to, so it reads as a
     label among the marks rather than a fifth league. */
  background: rgba(0, 0, 0, .26);
  color: #fff;
}
.game-promo__league.is-all:hover { background: rgba(0, 0, 0, .38); }

@media (max-width: 700px) {
  .game-promo { padding: 14px 16px; gap: 10px; }
  .game-promo__title { font-size: 19px; }
}

.masthead__game {
  margin-left: auto;
  padding: 7px 13px;
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: var(--radius-sm);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
}
/* Accent, not brand: the header's puzzle link and the home promo are the same
   thing in two places and should light up the same colour. */
.masthead__game:hover { background: var(--accent); border-color: var(--accent); text-decoration: none; }

/* The search box owned the auto margin before the game link existed; with
   both present only the first may push. */
.masthead__game + .masthead__search { margin-left: 12px; }

/* The livestream link takes the push the puzzle link had, and sits beside it. */
.masthead__live {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border: 1px solid var(--brand);
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}
.masthead__live:hover { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; text-decoration: none; }
.masthead__live-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 0 rgba(255, 255, 255, .7);
  animation: live-pulse 1.6s ease-out infinite;
}
@keyframes live-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(255, 255, 255, .7); }
  100% { box-shadow: 0 0 0 7px rgba(255, 255, 255, 0); }
}
@media (prefers-reduced-motion: reduce) { .masthead__live-dot { animation: none; } }
.masthead__live + .masthead__game { margin-left: 8px; }
/* With the Live link the masthead is one button wider; tighten it at middling
   widths so the theme toggle stays on the first line instead of wrapping. */
@media (min-width: 1001px) and (max-width: 1100px) {
  .masthead__inner { gap: 18px; }
  .masthead__search input { width: 150px; }
}
@media (min-width: 721px) and (max-width: 1000px) {
  .masthead__inner { gap: 12px; }
  .masthead__search input { width: 120px; }
  .sport-nav a.has-icon { padding: 6px 9px 3px; }
}
/* ==========================================================================
   Who Led? — timed multiple choice
   ========================================================================== */

/* ------------------------------------------------------------ set switcher -- */

.game-sets { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }

.game-set {
  display: flex;
  flex-direction: column;
  padding: 8px 15px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .03em;
}
.game-set span { font-size: 10px; font-weight: 500; color: var(--ink-4); letter-spacing: 0; }
.game-set:hover { border-color: var(--brand); color: var(--brand); text-decoration: none; }
.game-set.is-active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
.game-set.is-active span { color: rgba(255, 255, 255, .75); }

/* ---------------------------------------------------------------- the board -- */

.game-board { padding: 0; overflow: hidden; }

.game-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 18px;
  background: var(--header-bg);
  color: #fff;
}

.game-bar__pips { display: flex; gap: 7px; }
.game-bar__pips i {
  width: 26px;
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .22);
}
.game-bar__pips i.is-right { background: var(--green); }
.game-bar__pips i.is-wrong { background: var(--brand); }

.game-bar__clock {
  font-size: 20px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  min-width: 34px;
  text-align: right;
}
.game-bar__clock.is-low { color: #ff6b62; }

/* The bar drains left to right over the round. Width is animated rather than
   transform so it stays pinned to the left edge. */
.game-timer { height: 3px; background: rgba(127, 127, 127, .18); }
.game-timer span { display: block; height: 100%; width: 0; background: var(--brand); }

.game-stage { padding: 22px 20px 24px; }
.game-stage--start, .game-stage--final { text-align: center; padding: 34px 20px 38px; }

.game-stage__meta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 10px;
}

.game-league {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
  background: var(--ink-3);
  padding: 3px 8px;
  border-radius: var(--radius-sm);
}
/* One colour per league, so a mixed round says which sport it is before the
   words do. */
.game-league--mlb { background: #16619b; }
.game-league--nfl { background: #6d4f1c; }
.game-league--nba { background: #9c3a1c; }
.game-league--nhl { background: #3c4a58; }

.game-stage__q { font-size: 22px; line-height: 1.3; margin: 0; }
.game-stage__q strong { color: var(--brand); }
.game-stage__hint { margin: 6px 0 0; }

/* ------------------------------------------------------------------ options -- */

.game-options {
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.game-option {
  width: 100%;
  text-align: left;
  padding: 13px 16px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}
.game-option:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.game-option:disabled { cursor: default; }

/* After the answer: the right one greens, the one picked wrongly reds, the
   rest fade back rather than disappear — they were the rest of the top five
   and that is worth reading. */
.game-option.is-right {
  border-color: var(--green);
  background: var(--green-tint);
  color: var(--green);
}
.game-option.is-wrong {
  border-color: var(--brand);
  background: var(--brand-tint);
  color: var(--brand);
}
.game-option:disabled:not(.is-right):not(.is-wrong) { opacity: .45; }

.game-reveal {
  margin-top: 16px;
  padding: 11px 13px;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  font-size: 14px;
}
.game-reveal b.is-right { color: var(--green); }
.game-reveal b.is-wrong { color: var(--brand); }
.game-reveal .v { font-variant-numeric: tabular-nums; }

.game-next { margin-top: 14px; }
.btn--big { padding: 12px 30px; font-size: 15px; }

/* -------------------------------------------------------------------- final -- */

.game-final__score {
  margin: 0;
  font-size: 46px;
  font-weight: 800;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.game-final__squares { margin: 2px 0 12px; font-size: 28px; letter-spacing: 4px; }
/* The streak sits between the squares and the "you beat N%" line, and is
   deliberately the loudest thing after the score itself — it is the only
   number on this screen that is a reason to come back tomorrow. */
.game-final__streak {
  margin: 0 0 10px;
  font-size: 15px;
  font-weight: 700;
  color: var(--accent-ink);
}
.game-final__beat:empty { display: none; }
.game-final__actions { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }

.game-review {
  list-style: none;
  margin: 16px auto 0;
  padding: 0;
  max-width: 440px;
  text-align: left;
  font-size: 14px;
}
.game-review li { padding: 6px 0; border-bottom: 1px solid var(--border); }
.game-review li:last-child { border-bottom: 0; }

@media (max-width: 620px) {
  .game-stage__q { font-size: 19px; }
  .game-stage { padding: 18px 15px 20px; }
}

/* ------------------------------------------------------------ two utilities -- */

/* Visible to a screen reader and nothing else. Used for the labels on the
   name boxes, which have placeholders a sighted reader can see and a
   placeholder is not a label. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* A button that reads as a link. For the two places where the thing being
   offered is an action rather than a destination — declining the board,
   opening the rename box — and where a real <a href="#"> would be a lie. */
.linkish {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--brand);
  cursor: pointer;
  text-decoration: underline;
}
.linkish:hover { color: var(--ink); }

/* --------------------------------------------------------------- date nav -- */

/* The date used to be a label in the corner. Every past day has always been
   playable, and nothing said so, which made the whole back catalogue a feature
   only the URL bar knew about. */
.game-datenav {
  display: flex;
  align-items: stretch;
  gap: 6px;
  flex-shrink: 0;
}

.game-datenav__step {
  display: flex;
  align-items: center;
  padding: 0 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1;
}
.game-datenav__step:hover { border-color: var(--brand); color: var(--brand); text-decoration: none; }
.game-datenav__step.is-off { opacity: .3; }

.game-datenav__date {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  padding: 6px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink);
  text-align: right;
}
.game-datenav__date:hover { border-color: var(--brand); text-decoration: none; }
.game-datenav__date strong { font-size: 13px; font-weight: 700; }
.game-datenav__date span { font-size: 11px; color: var(--ink-4); }

@media (max-width: 620px) {
  .game-datenav { width: 100%; }
  .game-datenav__date { flex: 1; text-align: center; }
}

/* ----------------------------------------------------------- the board -- */

/* Four columns on one row: place, name, score, time. A table would be the
   honest markup for four columns, and an ordered list is the honest markup for
   a ranking; the ranking wins, because the rail is 300px wide and a table in
   it wraps into something unreadable. */
.ladder {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.ladder__row {
  display: grid;
  grid-template-columns: 22px 1fr auto auto;
  align-items: baseline;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
}
.ladder__row:last-child { border-bottom: 0; }

.ladder__rank { color: var(--ink-4); font-weight: 700; text-align: right; }
/* Names are typed by strangers and can be anything up to 24 characters, so the
   column that holds them is the one that gives way. */
.ladder__name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ladder__score { font-weight: 700; }
.ladder__time { color: var(--ink-4); min-width: 34px; text-align: right; }

/* The reader's own row. The point of the whole feature is finding this line
   without reading the others, so it is marked rather than merely tinted. */
.ladder__row.is-you {
  background: var(--brand-tint);
  margin: 0 -8px;
  padding-left: 8px;
  padding-right: 8px;
  border-radius: var(--radius-sm);
}
.ladder__row.is-you .ladder__name { color: var(--brand); }

/* The top three carry the medal colour, and only in the day's board — in the
   thirty-day table it would be three golds a month and mean nothing. */
.ladder:not(.ladder--rolling) .ladder__row:nth-child(1) .ladder__rank { color: var(--gold); }

.ladder__foot { margin: 10px 0 0; }

/* -------------------------------------------------- entering, and standing -- */

.game-enter {
  margin: 4px auto 18px;
  padding: 16px;
  max-width: 420px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.game-enter__ask { margin: 0 0 10px; font-size: 15px; font-weight: 700; }

.game-enter__form { display: flex; gap: 8px; }
.game-enter__form input {
  flex: 1;
  min-width: 0;
  padding: 9px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
}
.game-enter__form input:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

.game-enter__note { margin: 9px 0 0; text-align: left; }
.game-enter__error { margin: 8px 0 0; color: var(--brand); }

.game-standing {
  margin: 4px auto 18px;
  max-width: 420px;
}

/* --------------------------------------------------- a puzzle already played -- */

/* The done screen wears the same big score as the fresh one, so a returning
   reader sees what they got rather than a notice about why they cannot play.
   The eyebrow above it is what carries the refusal, quietly. */
.game-stage--done { text-align: center; padding: 34px 20px 38px; }

.game-done__eyebrow {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.game-done__when { margin: 2px 0 16px; }
.game-stage--done .game-review { margin-top: 18px; }
.game-stage--done .game-review li { display: flex; gap: 6px; justify-content: space-between; }
.game-standing__rank {
  margin: 0;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -.01em;
}
.game-standing__who { margin: 2px 0 8px; }

/* ------------------------------------------------------------- the archive -- */

.archive-me { margin-bottom: 18px; }

.archive-me__figures {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
}
.archive-me__figures li { display: flex; flex-direction: column; }
.archive-me__figures b {
  font-size: 24px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.archive-me__figures span {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-4);
}

/* A display rule beats the hidden attribute's own display:none, and this box
   starts hidden. Scoped rather than a global [hidden] reset: adding one of
   those to a stylesheet this size is a change to every component in it. */
.archive-rename[hidden] { display: none; }

.archive-rename {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.archive-rename input {
  padding: 7px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
}

/* The day list. Two columns carry text rather than numbers, so they say so;
   everything else is a figure and right-aligns with the rest of the site. */
table.stats--archive .col-year { width: auto; min-width: 128px; }
table.stats--archive td.col-text { white-space: normal; }
table.stats--archive td.col-text strong { font-weight: 600; }

/* A day this browser has played. The score is written in by script, so the
   column is empty until then and empty forever for a first-time reader —
   which is why it is the marking rather than the row's own background that
   changes, and why an empty cell has to look deliberate. */
.archive-you { color: var(--ink-4); }
.archive-you.is-played { color: var(--green); font-weight: 700; }
table.stats--archive tr.is-played .col-year a { font-weight: 700; }

.badge--today { background: var(--brand-tint); color: var(--brand); }

/* ==========================================================================
   Unsold inventory, and the page it points at
   ========================================================================== */

/* The live house creative in an empty slot. Deliberately quiet: a dashed
   hairline and two lines of muted text. It has to be visible enough to be
   clickable — an invisible link filling a 728x250 hole is a trap for anyone
   using a keyboard or a screen reader — and quiet enough that a reader's eye
   passes over it the way it passes over whitespace.

   The former `.ad-slot.is-empty { pointer-events: none }` is gone with it: the
   slot is a link now, and suppressing its clicks would defeat the point. */
/* Carries the brand colour. The first version was grey-on-grey, on the theory
   that empty inventory should keep its head down — and it kept it down so far
   that nobody would ever click it. This is house advertising: it is allowed to
   look like an advertisement, and the only thing it can cost us is a reader
   glancing at a red box and moving on. */
.ad-slot__house {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 100%;
  height: 100%;
  padding: 10px;
  border: 2px dashed var(--brand);
  border-radius: var(--radius-sm);
  background: var(--brand-tint);
  color: var(--brand);
  text-align: center;
  transition: background-color .15s, box-shadow .15s;
}
.ad-slot__house:hover {
  background: var(--brand);
  color: #fff;
  box-shadow: var(--shadow);
  text-decoration: none;
}
.ad-slot__house b {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.ad-slot__house span {
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  opacity: .85;
}

/* Short units have no room to stack the two lines. */
.ad-slot--leaderboard .ad-slot__house,
.ad-slot--footer .ad-slot__house { flex-direction: row; gap: 10px; }

/* The scaffolding box is a link too, so the rate card can be reached from any
   page while the site is being built. */
.ad-slot__ph:hover { border-color: var(--brand); text-decoration: none; }

/* ------------------------------------------------------------- sell page -- */

.sell-hero {
  display: flex;
  flex-wrap: wrap;
  gap: 30px;
  align-items: center;
  margin-bottom: 34px;
  padding: 34px 30px;
  border-radius: var(--radius);
  background: var(--header-bg);
  color: var(--header-ink);
}
.sell-hero__copy { flex: 2 1 420px; min-width: 280px; }
.sell-hero__copy h1 {
  margin: 8px 0 0;
  font-size: 36px;
  line-height: 1.15;
  letter-spacing: -.02em;
}
.sell-hero__copy p { margin: 14px 0 0; font-size: 15px; line-height: 1.6; color: #d7dbe0; }
.sell-hero__copy .muted { color: #98a0aa; }
.sell-hero__cta { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 22px; }

/* The hero ground is near-black in both themes, but --brand is not: in the
   light theme it is the deep red, which on this panel is 2.7:1 and unreadable.
   Both of these name their own colour rather than taking the token. */
.sell-hero .sell-eyebrow { color: #f2837d; }
.sell-hero .btn--ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, .45);
}
.sell-hero .btn--ghost:hover {
  background: rgba(255, 255, 255, .13);
  border-color: rgba(255, 255, 255, .7);
}

.sell-eyebrow {
  display: inline-block;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand);
}
/* On the red panel. A tint of the brand would go muddy against the lighter red
   the dark theme uses, so this is white at reduced opacity, which holds up on
   both. */
.sell-eyebrow--light { color: rgba(255, 255, 255, .78); }

/* Four numbers, and the only place on the page where a figure is allowed to be
   this large. A media buyer reads these first and everything after them is
   justification. */
.sell-hero__stats {
  flex: 1 1 260px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin: 0;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.sell-hero__stats div { padding: 16px 14px; background: var(--header-bg); }
.sell-hero__stats dt {
  font-size: 11px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: #98a0aa;
}
.sell-hero__stats dd {
  margin: 4px 0 0;
  font-size: 24px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}

.sell-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 18px;
  margin-bottom: 34px;
}
.sell-grid .card + .card { margin-top: 0; }
.sell-point { padding: 18px; }
.sell-point h3 { margin: 0 0 8px; font-size: 15px; }
.sell-point p { margin: 0; font-size: 13px; line-height: 1.6; color: var(--ink-2); }

/* ------------------------------------------------------------- audience -- */

.sell-demo {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 18px;
}
.sell-demo .card + .card { margin-top: 0; }

/* Bars rather than a pie or a table. Four panels of five rows each is a lot of
   numbers to compare, and the only comparison anyone actually makes is "which
   is biggest" — which a bar answers without being read. */
.bars { list-style: none; margin: 0; padding: 12px 16px 14px; }
.bars li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 90px 34px;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
}
.bars__label { font-size: 12px; color: var(--ink-2); }
.bars__track {
  height: 7px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  overflow: hidden;
}
.bars__track i { display: block; height: 100%; background: var(--brand); }
.bars__value {
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--ink-2);
}

.sell-affinity { margin-top: 18px; }
.sell-affinity__body { padding: 14px 16px 16px; }
.sell-affinity__body p { margin: 0 0 12px; }
.chips--static { list-style: none; margin: 0; padding: 0; }

.sell-source { margin: 12px 0 34px; }

/* ---------------------------------------------------------------- rates -- */

.sell-table-card { margin-bottom: 18px; }

.sell-rates {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.sell-rates th, .sell-rates td {
  padding: 14px;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--border);
}
.sell-rates thead th {
  background: var(--surface-2);
  border-bottom: 2px solid var(--border-strong);
  color: var(--ink-3);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  white-space: nowrap;
}
.sell-rates .num { text-align: right; }
.sell-rates tbody tr:last-child td { border-bottom: 0; }
.sell-rates tbody tr:hover { background: var(--surface-2); }
.sell-rates td strong { display: block; font-size: 14px; }
.sell-rates__where {
  display: block;
  margin-top: 4px;
  max-width: 42ch;
  color: var(--ink-3);
  font-size: 12px;
  line-height: 1.5;
}
.sell-rates__pitch {
  display: block;
  margin-top: 6px;
  max-width: 42ch;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1.5;
  font-style: italic;
}
.sell-rates__size {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.sell-rates__size span { display: block; font-weight: 400; }
.sell-rates__price {
  display: block;
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.sell-rates__price + span { display: block; white-space: nowrap; }

/* The takeover row is a different product from the five above it, and it is
   the one we would rather sell. */
.sell-rates__row--feature { background: var(--brand-tint); }
.sell-rates__row--feature:hover { background: var(--brand-tint) !important; }
.sell-rates__row--feature strong { color: var(--brand); }

.sell-terms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin-bottom: 34px;
}
.sell-terms .card + .card { margin-top: 0; }
.sell-term { padding: 16px; text-align: center; }
.sell-term h3 { margin: 0; font-size: 14px; }
.sell-term__discount {
  margin: 6px 0 4px;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.02em;
  color: var(--brand);
}
.sell-term.is-best { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-tint); }

/* ---------------------------------------------------------------- specs -- */

.sell-specs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 18px;
}
.sell-specs .card + .card { margin-top: 0; }

/* A 728-wide unit in a half-width card is a 728-wide unit with 300px of it
   hidden behind a scrollbar — which shows the buyer the opposite of what the
   section promises. The wide units take the whole row and are drawn whole; the
   300s pair up beside each other, where they fit. */
.sell-spec--wide { grid-column: 1 / -1; }

/* Given the whole row, the wide cards would otherwise put a 90px-tall box above
   a 1200px-wide list of eight facts. Side by side instead: box left at its true
   size, spec list filling what is left. */
@media (min-width: 900px) {
  .sell-spec--wide {
    display: grid;
    grid-template-columns: auto minmax(320px, 1fr);
  }
  .sell-spec--wide .card__head { grid-column: 1 / -1; }
  .sell-spec--wide .sell-spec__demo {
    display: flex;
    align-items: center;
    border-bottom: 0;
    border-right: 1px solid var(--border);
  }
  .sell-spec--wide .sell-spec__facts { padding-top: 12px; }
}

/* The demo box is drawn at the unit's real pixel dimensions, which is the whole
   point of it — a buyer should see how much of the page 300x600 is before they
   book it, not after. It scrolls inside its own box rather than pushing the
   card wide on a narrow screen. */
/* Block, not flex. A flex box centred with justify-content clips its own left
   edge the moment the content is wider than the track — which is exactly the
   case here on a narrow screen. Auto margins centre it when it fits and refuse
   to go negative when it does not, so nothing is ever cut off the front. */
.sell-spec__demo {
  padding: 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}
.sell-spec__box {
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  /* Deliberately not capped at 100%. A 728-wide unit shown 330 wide is a
     picture of the wrong product — the demo exists so a buyer can see the real
     footprint, so it keeps its width and the container scrolls instead. */
  flex: none;
  background-color: var(--surface);
  background-image: repeating-linear-gradient(
    45deg,
    var(--ad-hatch) 0, var(--ad-hatch) 1px,
    transparent 1px, transparent 9px
  );
  border: 2px dashed var(--ink-4);
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  text-align: center;
}
.sell-spec__box b {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  background: var(--surface);
  padding: 2px 10px;
  border-radius: var(--radius-sm);
}
.sell-spec__box span {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  background: var(--surface);
  padding: 1px 8px;
  border-radius: var(--radius-sm);
}

.sell-spec__facts { list-style: none; margin: 0; padding: 6px 16px 14px; }
.sell-spec__facts li {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  line-height: 1.5;
}
.sell-spec__facts li:last-child { border-bottom: 0; }
.sell-spec__facts li span:first-child {
  color: var(--ink-3);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: .05em;
}
.sell-spec__facts li span:last-child { color: var(--ink-2); }

.sell-specnotes { margin-top: 18px; margin-bottom: 34px; }
.sell-specnotes__body { padding: 14px 16px 16px; }
.sell-specnotes__body ul { margin: 0 0 12px; padding-left: 20px; font-size: 13px; line-height: 1.7; }
.sell-specnotes__body p { margin: 0; line-height: 1.6; }

/* --------------------------------------------------------------- upsell -- */

/* Given its own ground because it is a second product, not a footnote to the
   rate card. The people who need it are the ones who were about to stop
   reading — they have a budget and no artwork. */
.sell-upsell {
  margin-bottom: 34px;
  padding: 30px;
  border-radius: var(--radius);
  background: var(--brand);
  color: #fff;
}
.sell-upsell__head { max-width: 70ch; }
.sell-upsell__head h2 { margin: 8px 0 0; font-size: 28px; letter-spacing: -.02em; }
.sell-upsell__head p { margin: 12px 0 0; font-size: 15px; line-height: 1.6; color: rgba(255, 255, 255, .88); }
.sell-upsell__free {
  display: inline-block;
  margin-top: 16px !important;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, .22);
  color: #fff !important;
  font-size: 14px !important;
}
.sell-upsell__foot { margin: 18px 0 0; color: rgba(255, 255, 255, .88); max-width: 80ch; line-height: 1.6; }

.sell-services {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
  margin-top: 24px;
}
.sell-services .card + .card { margin-top: 0; }

/* The cards sit on the red panel, which sets colour: #fff for its own copy.
   Everything inside them that does not name a colour inherits that — white
   text on a white card, invisible in the light theme and only readable in the
   dark one by accident. They are ordinary cards on an ordinary surface, so
   they take the ordinary ink back. */
.sell-service {
  position: relative;
  padding: 18px 16px;
  color: var(--ink);
}
.sell-service h3 { margin: 0; font-size: 14px; }
.sell-service p { margin: 8px 0 0; line-height: 1.55; }
.sell-service__price {
  font-size: 24px;
  font-weight: 800;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.sell-service__price span { display: block; font-weight: 400; letter-spacing: 0; }
.sell-service__turn { margin-top: 12px !important; }
.sell-service.is-flagged { border-color: var(--brand); }
.sell-service__flag {
  position: absolute;
  top: 0;
  right: 0;
  padding: 3px 9px;
  border-radius: 0 0 0 var(--radius-sm);
  background: var(--brand);
  color: #fff;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .09em;
  text-transform: uppercase;
}

/* -------------------------------------------------------------- process -- */

.sell-steps { margin-bottom: 34px; }
.sell-steps ol {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 18px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.sell-steps li {
  padding: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.sell-steps h3 { margin: 10px 0 6px; font-size: 14px; }
.sell-steps p { margin: 0; font-size: 13px; line-height: 1.6; color: var(--ink-2); }
.sell-steps__n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: var(--brand-tint);
  color: var(--brand);
  font-size: 13px;
  font-weight: 800;
}

/* ------------------------------------------------------------------ faq -- */

.sell-faq { margin-bottom: 34px; }
.sell-faq dl { margin: 0; padding: 6px 18px 14px; }
.sell-faq dt {
  margin-top: 14px;
  font-size: 14px;
  font-weight: 700;
}
.sell-faq dd {
  margin: 6px 0 0;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  line-height: 1.65;
  color: var(--ink-2);
}
.sell-faq dd:last-child { border-bottom: 0; padding-bottom: 0; }

/* --------------------------------------------------------------- closer -- */

.sell-closer {
  padding: 34px 30px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  text-align: center;
}
.sell-closer h2 { margin: 0; font-size: 26px; letter-spacing: -.02em; }
.sell-closer p {
  margin: 12px auto 0;
  max-width: 60ch;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-2);
}
.sell-closer__cta {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 22px;
}

@media (max-width: 720px) {
  .sell-hero { padding: 24px 18px; }
  .sell-hero__copy h1 { font-size: 27px; }
  .sell-upsell { padding: 22px 18px; }
  .sell-upsell__head h2 { font-size: 23px; }
  .sell-closer { padding: 24px 18px; }
  .sell-closer h2 { font-size: 21px; }
  .bars li { grid-template-columns: minmax(0, 1fr) 60px 34px; }
}

/* ------------------------------------------------------------ theme switch --
   Sits at the end of the masthead, in the same visual register as the search
   box beside it: a hairline box on the dark header, not a coloured control.
   Nobody comes to the site to change the theme, and the one person who wants
   it will find it next to the search.

   Which icon shows is driven by data-mode, written by the script — the sun
   while the page is dark (press it for light), the moon while it is light. */
.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, .08);
  color: rgba(255, 255, 255, .82);
  cursor: pointer;
  transition: background-color .15s, border-color .15s, color .15s;
}
.theme-toggle:hover {
  background: rgba(255, 255, 255, .16);
  border-color: rgba(255, 255, 255, .34);
  color: #fff;
}
.theme-toggle:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* Default to the moon, so a reader with JavaScript off — where data-mode is
   never written — still gets a sensible-looking button rather than both icons
   stacked on top of each other. */
.theme-toggle__sun { display: none; }
.theme-toggle[data-mode="dark"] .theme-toggle__sun { display: block; }
.theme-toggle[data-mode="dark"] .theme-toggle__moon { display: none; }

/* The search box takes the free space with margin-left:auto, which would leave
   the button pinned against it; this keeps a gap without disturbing that. */
.masthead__search + .theme-toggle { margin-left: 10px; }

@media (max-width: 620px) {
  .masthead__search { margin-left: 0; flex: 1; }
  .masthead__search input { width: 100%; }
}

/* ------------------------------------------------------------------ lede --
   The sentence above a board. Set slightly larger than body copy and given
   room of its own: it is the answer to the question the page ranks for, and
   the reader who came from a search result should land on it before anything
   else on the page competes for attention. The first sentence is bolded in the
   markup, which is also the fragment a snippet generator tends to lift. */
.lede {
  margin: -2px 0 18px;
  max-width: 78ch;
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-2);
}
.lede strong { color: var(--ink); }

/* --------------------------------------------------------------- related --
   Link blocks at the foot of a board. Quiet by design — this is the page's
   exit, not its subject — but present on every deep page, which is what turns
   a hundred thousand leaf pages into something a crawler can walk. */
.related {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px 24px;
  margin: 26px 0 8px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.related__heading {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-3);
}
.related__list { margin: 0; padding: 0; list-style: none; }
.related__list li { margin: 0 0 5px; }
.related__list a { font-size: 13.5px; color: var(--ink-2); }
.related__list a:hover { color: var(--brand); }

/* --------------------------------------------------------------- compare --
   A career per column instead of a player per row, so the first cell of each
   row is a label and wants the same treatment a header does. */
table.stats--compare td.col-text {
  text-align: left;
  color: var(--ink-2);
  white-space: nowrap;
}
table.stats--compare th.col-player { text-align: center; }
table.stats--compare th.col-player .player-cell {
  flex-direction: column;
  gap: 6px;
  justify-content: center;
}
/* The best figure in a row, where the site is willing to say which one that
   is. See SPORT_UNRANKED_COLUMNS — rows whose top value is not a credit are
   left unmarked rather than decorated. */
table.stats--compare td.is-best {
  background: var(--brand-tint);
  color: var(--brand);
  font-weight: 700;
}
table.stats--compare tbody tr:hover td.is-best { background: var(--brand-tint); }

/* ==========================================================================
   Admin — traffic panel
   Bars drawn in CSS from an inline height or width. A panel that counts its
   own traffic rather than depending on somebody else's script has no business
   pulling in somebody else's script to draw the result, and a bar chart is
   two rules.
   ========================================================================== */

/* Day-by-day columns. The track is a fixed height so a quiet day is visibly
   short rather than the chart rescaling around it; the column count comes in
   as a custom property so ninety days and seven days both fill the width. */
.tchart {
  display: grid;
  grid-template-columns: repeat(var(--tchart-cols, 30), 1fr);
  align-items: end;
  gap: 2px;
  height: 160px;
}
.tchart__col { height: 100%; display: flex; align-items: flex-end; }
.tchart__bar {
  width: 100%;
  min-height: 1px;
  background: var(--brand);
  border-radius: 2px 2px 0 0;
  display: flex;
  align-items: flex-end;
  /* Visits sit inside the page-view bar, so the darker block is always a
     subset of the lighter one and cannot be misread as a separate series. */
  opacity: .35;
  position: relative;
}
.tchart__bar-inner {
  position: absolute;
  inset: auto 0 0 0;
  background: var(--brand);
  border-radius: 2px 2px 0 0;
}
.tchart__col:hover .tchart__bar { opacity: .55; }

/* Dated ticks under the bars: evenly spread across the span drawn, ends
   flush with the first and last column, so a bar can be read back to a date
   by eye. Thinned in PHP rather than here — six labels is what fits, and a
   label the width of a 3px column would be unreadable at any count. */
.tchart__ticks {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 6px;
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tchart__axis {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--ink-3);
}
.tchart__key { display: flex; align-items: center; gap: 6px; }
.tchart__swatch {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 2px;
  background: var(--brand);
}
.tchart__swatch--views  { opacity: .35; }
.tchart__swatch--visits { opacity: 1; margin-left: 6px; }

/* A labelled horizontal bar: channel, screen, league. Three columns so the
   labels line up down the left and the figures down the right whatever is
   in the middle. */
.bar-row {
  display: grid;
  grid-template-columns: minmax(96px, 34%) 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  font-size: 13px;
}
.bar-row__label { color: var(--ink-2); }
.bar-row__track {
  height: 9px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  overflow: hidden;
}
.bar-row__fill {
  display: block;
  height: 100%;
  background: var(--brand);
  opacity: .5;
  border-radius: 5px;
}
.bar-row__value {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
}
/* The absolute count, kept subordinate to the percentage beside it — the
   share is what an advertiser is being told, the count is the evidence. */
.bar-row__value em {
  font-style: normal;
  font-weight: 400;
  color: var(--ink-4);
  margin-left: 6px;
}

/* The media-kit block: values to copy into advertise.php, so it is shown as
   the code it is going to become. */
.code-block {
  margin: 0 0 12px;
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow-x: auto;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-2);
  white-space: pre;
}


/* ==========================================================================
   The focused leaderboard

   A leaderboard is not a table that happens to be sorted. The page names one
   statistic, so the page shows one statistic: the leader said out loud above
   the board, the category in its own column with a bar scaled to the leader's
   mark, and beside it only the stats that give that category meaning. The
   full stat line is one click away for the reader who wants the spreadsheet.
   ========================================================================== */

/* -------------------------------------------------------------- the leader */

/* The card and the medium rectangle share one row. The card takes what is
   left, which on a 1200px page is about 880px — enough that the name and the
   number sit at comfortable reading distance instead of at opposite ends of a
   near-empty band. Both stretch to the ad's 250px so the board below starts on
   one straight edge; a card that stopped short of the ad would read as a
   layout fault rather than as a decision. */
.hero-row {
  display: flex;
  align-items: stretch;
  gap: 20px;
  margin-bottom: 16px;
}

.hero-row .leader-hero { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }

/* The slot carries its own rhythm elsewhere; in this row the row owns it. */
.hero-row .ad-slot--rail_small { flex: 0 0 300px; margin: 0; }

.leader-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  justify-content: space-between;
  gap: 0 24px;
  margin-bottom: 16px;
  min-height: 172px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--brand);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  /* So the portrait's corners are the card's corners. */
  overflow: hidden;
}

.leader-hero__player {
  display: flex;
  align-items: stretch;
  gap: 20px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

/* The portrait is flush to the card on three sides, meeting the red spine.
   A photo inset in padding reads as an illustration sitting beside the fact;
   a photo that reaches the edges reads as the subject of the card. Width is
   capped near the 200px stored file, past which it visibly upscales. */
.leader-hero .player-photo--tile {
  width: 150px;
  height: auto;
  align-self: stretch;
  border: 0;
  border-radius: 0;
  object-fit: cover;
}

.leader-hero__names {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: 18px 0;
}

.leader-hero__eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* The date a live board is good to. Set in the accent so it reads as the one
   changing thing on a card of settled facts, and kept on the eyebrow line so
   "Leads all of MLB in 2026" and "through August 20" are one statement. */
.leader-hero__asof {
  display: inline-block;
  margin-left: .5em;
  padding: 1px 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent-text);
  letter-spacing: .04em;
}

.leader-hero__name {
  font-size: 26px;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -.015em;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
}

.leader-hero__player:hover .leader-hero__name { color: var(--brand); }

.leader-hero__team { font-size: 13px; color: var(--ink-3); }

/* The number is the point of the page, so it is the largest thing on it. */
.leader-hero__mark {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-end;
  text-align: right;
  margin-left: auto;
  padding: 18px 22px 18px 0;
}

.leader-hero__value {
  font-family: var(--mono);
  font-size: 46px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}

.leader-hero__stat {
  margin-top: 4px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* The margin is what makes a leaderboard an argument rather than a lookup. */
.leader-hero__margin { margin-top: 6px; font-size: 12px; color: var(--ink-3); }

@media (max-width: 1080px) {
  .hero-row { display: block; }
}

@media (max-width: 560px) {
  /* The mark drops below the portrait rather than beside it, but the portrait
     keeps a name next to it — a full-width photo would push the number, which
     is the point of the card, off the screen. */
  .leader-hero { flex-direction: column; align-items: stretch; min-height: 0; }
  .leader-hero .player-photo--tile { width: 112px; min-height: 146px; }
  .leader-hero__names { padding: 14px 14px 14px 0; }
  .leader-hero__mark {
    align-items: flex-start;
    text-align: left;
    margin-left: 0;
    padding: 0 18px 18px 18px;
  }
  .leader-hero__name { font-size: 22px; }
  .leader-hero__value { font-size: 38px; }
}

/* ----------------------------------------------- focused / full-line switch */

.board-switch {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}

.board-switch__label { font-size: 12px; color: var(--ink-3); }

.btn--sm { padding: 4px 10px; font-size: 12px; }

/* ------------------------------------------------ the category's own column */

table.stats--board td.col-value,
table.stats--board th.col-value {
  position: relative;
  min-width: 92px;
  text-align: right;
}

/* Scaled to the leader's mark, so the shape of the season is legible before a
   single digit is read: 60 next to 47 is two numbers, and a bar three-quarters
   the length of another bar is a picture of the 1927 American League. */
.statbar {
  position: absolute;
  left: 0;
  top: 3px;
  bottom: 3px;
  width: var(--bar, 0%);
  background: var(--bar-fill);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  pointer-events: none;
}

.col-value__num {
  position: relative;
  font-family: var(--mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--brand);
}

/* The tint is doing the bar's job now, and the two together are muddy. */
table.stats--board td.col-value.is-sorted { background: transparent; }
table.stats--board tbody tr:hover td.col-value.is-sorted { background: transparent; }

/* Leaderboards on a phone.

   The desktop board is a spreadsheet: the category plus the stats that give it
   context, in a table that scrolls sideways. At phone width that put the one
   number the reader came for off the right edge, behind G and AB. So below
   640px a board is four things that always fit: rank, player, team (or the
   years, on the all-time and club boards) and the amount. The context columns
   and the switch that adds more of them are not shown; nothing above 640px
   changes. Fixed layout is what guarantees the fit: the name column takes
   whatever is left and a long name ends in an ellipsis rather than pushing
   the amount off screen. */
@media (max-width: 640px) {
  table.stats--board { table-layout: fixed; white-space: nowrap; }
  table.stats--board th:not(.col-rank):not(.col-player):not(.col-team):not(.col-text):not(.col-value),
  table.stats--board td:not(.col-rank):not(.col-player):not(.col-team):not(.col-text):not(.col-value) {
    display: none;
  }
  table.stats--board th, table.stats--board td { padding: 9px 6px; }
  table.stats--board th:first-child, table.stats--board td:first-child { padding-left: 10px; }
  table.stats--board th:last-child, table.stats--board td:last-child { padding-right: 12px; }

  table.stats--board .col-rank { width: 36px; text-align: left !important; }
  table.stats--board .col-player { min-width: 0; width: auto; overflow: hidden; }
  table.stats--board .col-team { width: 58px; overflow: hidden; text-overflow: ellipsis; }
  table.stats--board .col-text { width: 84px; overflow: hidden; text-overflow: ellipsis; }
  table.stats--board td.col-team { font-size: 13px; }
  table.stats--board td.col-text { font-size: 12px; }
  /* The season count, "active" and "in progress" notes after the years: the
     years are what has to fit. */
  table.stats--board td.col-text .muted.small { display: none; }
  table.stats--board td.col-value,
  table.stats--board th.col-value { width: 64px; min-width: 0; }
  table.stats--board td.col-value .col-value__num { font-size: 15px; color: var(--value-ink); }
  /* At 64px the bar is a red smear under red digits, not a shape: the number
     alone carries the column. */
  table.stats--board .statbar { display: none; }

  table.stats--board .player-cell { gap: 8px; min-width: 0; }
  table.stats--board .player-cell .player-photo { width: 28px; height: 28px; flex: 0 0 28px; font-size: 11px; }
  /* A long name takes a second line rather than losing its end. */
  table.stats--board .player-cell__name {
    min-width: 0;
    font-size: 14px;
    line-height: 1.25;
    white-space: normal;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }

  /* The rest of the stat line is not on show at this width, so a button that
     adds it would appear to do nothing. */
  .board-switch { display: none; }
}

/* The bar reads as decoration where a reader cannot see it; the number does
   not, so it stays. */
@media (prefers-reduced-motion: no-preference) {
  .statbar { transition: width .18s ease-out; }
}

/* ------------------------------------------------------------- the race -- */

/* Five lines, the leader in the brand red. The palette is five hues far apart
   on the wheel rather than five shades, because the lines cross all summer and
   a reader has to follow one through the crossings. */
.race { margin: 0; padding: 12px 14px 14px; }
.race__plot svg { display: block; width: 100%; height: auto; }
.race__grid { stroke: var(--border); stroke-width: 1; }
.race__tick { fill: var(--ink-4); font-size: 11px; font-family: var(--font); }
.race__line polyline { fill: none; stroke-width: 2.25; stroke-linejoin: round; stroke-linecap: round; }
.race__line circle { stroke: none; }
.race__line--1 polyline { stroke: var(--race-1); stroke-width: 3; }
.race__line--2 polyline { stroke: var(--race-2); }
.race__line--3 polyline { stroke: var(--race-3); }
.race__line--4 polyline { stroke: var(--race-4); }
.race__line--5 polyline { stroke: var(--race-5); }
.race__line--1 circle { fill: var(--race-1); }
.race__line--2 circle { fill: var(--race-2); }
.race__line--3 circle { fill: var(--race-3); }
.race__line--4 circle { fill: var(--race-4); }
.race__line--5 circle { fill: var(--race-5); }

.race__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 10px 0 6px;
  padding: 0;
  list-style: none;
  font-size: 13px;
}
.race__key { display: inline-flex; align-items: center; gap: 6px; }
.race__key i { width: 14px; height: 3px; border-radius: 2px; background: currentColor; }
.race__key a { color: var(--ink); }
.race__key b { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.race__key--1 i { background: var(--race-1); height: 4px; }
.race__key--2 i { background: var(--race-2); }
.race__key--3 i { background: var(--race-3); }
.race__key--4 i { background: var(--race-4); }
.race__key--5 i { background: var(--race-5); }
.race__note { display: block; }

/* ------------------------------------------------------ team record pages -- */

.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 8px;
  margin: 0;
  padding: 12px 14px 14px;
  list-style: none;
}
.team-grid--compact { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.team-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  height: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink);
}
.team-tile:hover { border-color: var(--brand); text-decoration: none; }
.team-tile__name { font-weight: 700; font-size: 13.5px; }
.team-grid--compact .team-tile__name { font-weight: 600; font-size: 13px; }

/* A current club's tile carries its logo to the left of the name and years. */
.team-tile--logo {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: 12px;
  row-gap: 2px;
  align-content: center;
  align-items: center;
}
.team-tile--logo .team-logo { grid-row: 1 / span 2; }
.team-tile--logo .team-tile__name { align-self: end; }
.team-tile--logo .team-tile__years { align-self: start; }

/* The badge strip near the top of a league page: "pick a club".
   Denser than .team-grid, which is a page of its own and can afford a name and
   a founding year per tile. Here the badge does the identifying and the short
   name only confirms it, so thirty clubs fit in a couple of rows without
   pushing the leaderboards below the fold. */
.club-strip { margin: 0 0 22px; }
.club-strip__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.club-strip__head h2 { margin: 0; font-size: 18px; }
.club-strip__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.club-strip__tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 4px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink);
  text-align: center;
}
.club-strip__tile:hover { border-color: var(--brand); text-decoration: none; }
.club-strip__name {
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.2;
  /* A long short_name ("Diamondbacks") must not widen the grid. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* On a phone, five to a row. Thirty-two clubs four across is eight rows of
   badges between the masthead and the first leaderboard, which is too much
   page to scroll past for a reader who did not come for a team. Five across
   and a shorter tile brings it to seven and keeps the badges legible. */
@media (max-width: 640px) {
  /* 58px, not 64: the strip is 335px wide inside the page gutters on a 375px
     phone, and five columns at 64 plus four 5px gaps needs 340. Two pixels
     short bought a whole extra row. */
  .club-strip__list { grid-template-columns: repeat(auto-fill, minmax(58px, 1fr)); gap: 5px; }
  .club-strip__tile { padding: 6px 2px 5px; }
  .club-strip__name { font-size: 10px; }
  .club-strip__tile .team-logo { width: 28px; height: 28px; }
}

/* A club's own page: the logo beside the heading. */
.team-head { display: flex; align-items: center; gap: 16px; min-width: 0; }
/* On a phone the heading needs the full width, so the logo sits above it. */
@media (max-width: 640px) {
  .team-head { flex-direction: column; align-items: flex-start; gap: 10px; }
  .team-head .team-logo { width: 52px; height: 52px; }
}

/* A franchise's top five carry the years beside each name. */
.livegrid__board--years li { grid-template-columns: 22px minmax(0, 1fr) auto auto; }
.livegrid__board--years li > .muted { font-size: 11px; white-space: nowrap; }

/* ---------------------------------------------------------- milestone clubs -- */

.club-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 10px;
  margin: 0;
  padding: 12px 14px 14px;
  list-style: none;
}
.club-tile {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  height: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink);
}
.club-tile:hover { border-color: var(--gold); text-decoration: none; }
.club-tile__name { font-weight: 700; font-size: 13.5px; }
.club-tile__count { font-variant-numeric: tabular-nums; color: var(--ink-3); font-size: 12px; white-space: nowrap; }

.club-contenders { margin: 0; padding: 6px 0; list-style: none; }
.club-contenders li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 12px;
  align-items: baseline;
  padding: 6px 14px;
  font-size: 13px;
}
.club-contenders li + li { border-top: 1px solid var(--border); }
.club-contenders b { font-variant-numeric: tabular-nums; }

.badge--club {
  background: rgba(184, 134, 11, .12);
  color: var(--gold);
  box-shadow: inset 0 0 0 1px rgba(184, 134, 11, .35);
}
.player-honours { margin: 0 0 18px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 0; }
.player-honours__label {
  margin-right: 10px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-4);
}
/* Four columns to a row (rank, name, years, value) need a wider card than the
   season page's three, or the name is the column that gives way. */
.livegrid--teams { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }

/* ---------------------------------------------------------- team boards -- */

/* The page-head's right side: the Players | Teams switch beside the button
   that was there before. Wraps under the title on a phone like the rest of
   the head does. */
.page-head__actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* Two answers to one question, so a segmented control rather than two
   buttons: the active half is a filled block and the other is a link. */
.subject-switch {
  display: inline-flex;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
}
.subject-switch__item {
  padding: 5px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  text-decoration: none;
}
a.subject-switch__item:hover { color: var(--brand); text-decoration: none; }
.subject-switch__item.is-active {
  background: var(--brand);
  color: #fff;
}

/* The leader card, with the club's mark where a player's portrait goes. A
   logo is not a photograph: it sits on the card with room around it rather
   than bleeding to the edges. */
.leader-hero__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  padding: 0 4px 0 22px;
}
.leader-hero__logo .team-logo { width: 88px; height: 88px; }

table.stats--teams .player-cell .team-logo { width: 28px; height: 28px; }

@media (max-width: 560px) {
  .leader-hero--team .leader-hero__logo { padding: 16px 0 0 16px; }
  .leader-hero__logo .team-logo { width: 64px; height: 64px; }
}

/* The average team, as a marked row where it falls on a season board. In the
   accent rather than grey, which read as a disabled row: the line is the
   thing a reader scans for. Not the brand red (the numbers) or gold (the top
   three), so it cannot be mistaken for either. */
table.stats--teams tr.avg-row td {
  border-top: 2px solid var(--accent-text);
  border-bottom: 2px solid var(--accent-text);
  background: color-mix(in srgb, var(--accent-text) 12%, transparent);
}
table.stats--teams tbody tr.avg-row:hover td,
table.stats--teams tr.avg-row td.col-value.is-sorted {
  background: color-mix(in srgb, var(--accent-text) 12%, transparent);
}
.avg-row__label {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent-text);
}
table.stats--teams tr.avg-row .col-value__num { color: var(--accent-text); }

/* A club's standing this season, as a strip of tiles linking to each board. */
.team-standing {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
  margin-bottom: 18px;
}
.team-standing__tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: inherit;
  text-decoration: none;
}
.team-standing__tile:hover { border-color: var(--brand); text-decoration: none; }
.team-standing__label { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.team-standing__rank { font-size: 20px; font-weight: 800; color: var(--ink); }
.team-standing__tile.is-top .team-standing__rank { color: var(--gold); }
.team-standing__value { font-family: var(--mono); font-size: 13px; color: var(--ink-2); }

/* A link riding on a section heading: "Fielding ... Every fielding stat by
   position". Same row as the heading, pushed to its right, in the heading's
   small caps but not its grey. */
.season-group__more {
  float: right;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: none;
}

/* ==========================================================================
   The floating mini player
   --------------------------------------------------------------------------
   The broadcast in the corner of every page, the way a video keeps playing
   when you navigate away from it. Desktop only, dismissible, and the dismissal
   sticks: this site's job is answering a question fast, and a box that came
   back after being closed would be the worst thing on it.

   The frame holds a 1920x1080 page scaled down to fit, so the type inside is
   small by definition. It reads as a moving preview rather than something you
   sit and study — the expand button is there for when it isn't enough.
   ========================================================================== */
.pip {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 90;
  width: 480px;
  max-width: calc(100vw - 36px);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 6px 16px rgba(16, 20, 26, .18), 0 2px 6px rgba(16, 20, 26, .12);
  overflow: hidden;
}
.pip[hidden] { display: none; }

.pip__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px 6px 11px;
  background: var(--header-bg);
  color: var(--header-ink);
}
.pip__dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--brand);
  flex: none;
  box-shadow: 0 0 0 0 rgba(178, 37, 36, .6);
  animation: pip-pulse 1.8s ease-out infinite;
}
@keyframes pip-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(178, 37, 36, .6); }
  100% { box-shadow: 0 0 0 6px rgba(178, 37, 36, 0); }
}
.pip__name {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pip__open,
.pip__close,
.pip__expand {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--header-ink);
  opacity: .72;
  cursor: pointer;
  text-decoration: none;
  line-height: 1;
}
.pip__open { font-size: 13px; }
.pip__expand { display: none; }
.pip__expand-play {
  width: 0; height: 0;
  border-style: solid;
  border-width: 6px 0 6px 10px;
  border-color: transparent transparent transparent currentColor;
}
/* Playing, the same control closes the frame again, so it becomes a chevron
   pointing down at the bar it collapses back into. */
.pip.is-playing .pip__expand-play {
  border-width: 8px 5px 0 5px;
  border-color: currentColor transparent transparent transparent;
}
.pip__close { font-size: 19px; }
.pip__open:hover,
.pip__close:hover,
.pip__expand:hover {
  opacity: 1;
  background: rgba(255, 255, 255, .16);
  color: var(--header-ink);
  text-decoration: none;
}
.pip__open:focus-visible,
.pip__close:focus-visible,
.pip__expand:focus-visible { outline: 2px solid var(--header-ink); outline-offset: -2px; }

/* 16:9, which is what the broadcast page draws. */
.pip__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #0a1630;   /* the broadcast's own navy, so there is no white flash */
}
.pip__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* The still card, shown until the iframe is built. It is what someone with
   reduced motion gets instead of a corner full of moving type. */
.pip__start {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  border: 0;
  background: transparent;
  color: #fff;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
}
.pip.is-playing .pip__start { display: none; }
.pip__play {
  width: 0; height: 0;
  border-style: solid;
  border-width: 11px 0 11px 18px;
  border-color: transparent transparent transparent #fff;
  opacity: .9;
}
.pip__start:hover .pip__play { opacity: 1; }

/* On a phone it stops floating and docks: a full-width bar along the bottom
   edge, collapsed to its own title until it is tapped.

   It used to be hidden outright below this width, on the reasoning that the
   site is one column on a phone and a floating box would sit on top of the
   answer. That reasoning was right about the floating box and wrong about the
   conclusion — most of the traffic is on a phone, so hiding it there hid it
   from nearly everybody. A 36px bar pinned to the bottom edge covers nothing:
   the body is padded by exactly its height, so the end of the page still
   clears it. The video itself only exists once somebody asks. */
@media (max-width: 999px) {
  .pip {
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-width: none;
    border-width: 1px 0 0;
    border-radius: 0;
    box-shadow: 0 -4px 14px rgba(16, 20, 26, .22);
  }
  /* Collapsed is the resting state here, and collapsed means no frame at all
     rather than a frame of dead navy under the bar. */
  .pip:not(.is-playing) .pip__frame { display: none; }
  .pip__expand { display: inline-flex; }
  .pip__bar { padding: 7px 6px 7px 12px; }
  /* Room for the docked bar, so the last line of the footer is not under it.
     Set by the script, which is the only thing that knows whether the bar is
     actually there — it is not there for a reader who closed it. */
  body.has-pip { padding-bottom: 40px; }
}

@media (prefers-reduced-motion: reduce) {
  .pip__dot { animation: none; }
}

/* ------------------------------------------------------ postseason band -- */
/* The October spotlight (src/postseason.php). Always dark, in both themes: it
   is meant to read as the broadcast graphic at the top of the page, and a
   light band here would sit on the page like one more card. It carries its
   own colours rather than the theme's for that reason, all of them checked
   against #14181e at 4.5:1 or better. */
.post-spot {
  margin: 0 0 22px;
  padding: 22px 22px 18px;
  border-radius: var(--radius);
  color: #f3f5f7;
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(200, 16, 46, .38) 0%, rgba(200, 16, 46, 0) 55%),
    linear-gradient(135deg, #14181e 0%, #1c222b 100%);
  border-top: 3px solid #c8102e;
  box-shadow: var(--shadow);
}
.post-spot__kicker {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #ff8a8a;
}
.post-spot__kicker .live-dot { margin: 0 6px 0 0; background: #ff4d5e; }
.post-spot__title {
  margin: 0;
  font-size: clamp(28px, 4.2vw, 40px);
  line-height: 1.05;
  font-weight: 800;
  letter-spacing: -.02em;
  color: #fff;
}
.post-spot__lede { margin: 8px 0 16px; font-size: 15px; color: #c9d0d8; max-width: 62ch; }

.post-spot__tiles {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}
.post-tile {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "stat  stat"
    "photo name"
    "photo team"
    "value value";
  column-gap: 12px;
  align-items: center;
  padding: 12px 14px;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .1);
  color: inherit;
  text-decoration: none;
  transition: background .15s ease, border-color .15s ease, transform .15s ease;
}
.post-tile:hover, .post-tile:focus-visible {
  background: rgba(255, 255, 255, .11);
  border-color: rgba(255, 138, 138, .55);
  transform: translateY(-1px);
}
.post-tile__stat {
  grid-area: stat;
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: #aab4bf;
}
.post-tile .player-photo { grid-area: photo; width: 48px; height: 48px; border-width: 1px; }
.post-tile__name { grid-area: name; align-self: end; font-weight: 700; font-size: 15px; line-height: 1.2; }
.post-tile__tie { font-weight: 600; font-size: 12px; color: #ff8a8a; white-space: nowrap; }
.post-tile__team { grid-area: team; align-self: start; font-size: 12px; color: #aab4bf; }
.post-tile__value {
  grid-area: value;
  margin-top: 8px;
  font-size: 30px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: #fff;
}

.post-spot__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 20px;
  margin-top: 16px;
}
.post-spot__records { margin: 0; font-size: 13px; color: #c9d0d8; }
.post-spot__records a { color: #f3f5f7; text-decoration: underline; text-decoration-color: rgba(255, 255, 255, .35); }
.post-spot__records a:hover { text-decoration-color: #ff8a8a; }
.post-spot__records span[aria-hidden] { margin: 0 6px; color: #6b7682; }
.post-spot__records-label {
  margin-right: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: #aab4bf;
}
.post-spot__links { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.post-spot__links .btn { background: #c8102e; border-color: #c8102e; color: #fff; }
.post-spot__links .btn:hover { background: #a50d26; border-color: #a50d26; }
.post-spot__alt { color: #f3f5f7; font-weight: 600; font-size: 14px; }

@media (max-width: 860px) {
  .post-spot__tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 420px) {
  .post-spot { padding: 18px 16px 16px; }
  .post-tile { padding: 10px 12px; }
  .post-tile__value { font-size: 24px; }
}

/* "Final" beside a league page's board heading between seasons, where the
   live dot sits while a season is being played. */
.tag--final {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  vertical-align: middle;
  color: var(--green);
  background: var(--green-tint);
  border: 1px solid var(--green-line);
}
