/* styles/components.css */
/* ── Masthead ─────────────────────────────────────────────────────────────────
   Three lockups ship together and CSS reveals the one data-header selects. The
   condensed italic face is the character of the mark: system-ui flattens it. */

.masthead {
  background: var(--header-surface);
  color: var(--header-ink);
  text-shadow: var(--header-shadow);
}
.masthead .wrap { padding-block: 20px 16px; }
.masthead p { margin: 0; max-width: none; }

.mh-kicker, .mh-full, .mh-mark { display: none; }

.mh-full, .mh-mark {
  font-family: "Barlow Condensed", ui-condensed, system-ui, sans-serif;
  font-weight: 800; font-style: italic; text-transform: uppercase;
}
.mh-kicker {
  font-size: 10px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase;
  color: var(--name-ink); margin-bottom: 5px;
}

/* A: the whole name, stacked and oversized. The name is the logo. */
:root[data-header="A"] .mh-full { display: block; font-size: clamp(30px, 11vw, 54px);
  line-height: .87; letter-spacing: -.015em; color: var(--name-ink); }
:root[data-header="A"] .mh-full span { display: block; }

/* B: badge-faithful. Two lines, the second picking up the third accent. */
:root[data-header="B"] .mh-full { display: block; font-style: normal; font-weight: 700;
  font-size: clamp(19px, 6vw, 28px); line-height: 1.04; letter-spacing: .03em;
  color: var(--name-ink); }
:root[data-header="B"] .mh-full span:nth-child(3) { display: block; }

/* C: hierarchy. Small name over an oversized mark. */
:root[data-header="C"] .mh-kicker { display: block; }
:root[data-header="C"] .mh-mark { display: block; font-size: clamp(52px, 19vw, 88px);
  line-height: .82; letter-spacing: -.04em; color: var(--mark-ink); }


/* The tagline sits below the plane, on the page ground, never on the colour itself. In
   the mixed palettes the second accent IS the plane colour, so on the plane one word
   vanishes. On the ground all three read, and each word can keep its own colour, which is
   the whole idea: Football, Friendship and Fun in accents 1, 2 and 3. */
.tagline {
  display: flex; gap: 12px; padding: 12px 16px;
  background: var(--ground); text-shadow: none;
  border-bottom: 1px solid var(--rule);
  font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
}
.tagline span:nth-child(1) { color: var(--accent-1); }
.tagline span:nth-child(2) { color: var(--accent-2); }
.tagline span:nth-child(3) { color: var(--accent-3); }
@media (min-width: 720px) { .tagline { padding-inline: 30px; } }

/* Over a gradient, headers B and C carry the tagline inside the plane. That is what the
   identity picker draws and what the committee is voting on, and the site had been
   showing something else. The comment above still holds as a measurement: on the plane
   Friendship sits at roughly 2:1 against the gradient where on the ground it gets 7:1,
   because accent 2 and the plane are close in brightness. It reads, and it is the
   weakest of the three. Header A keeps its tagline on the ground, as the picker does. */
:root[data-structure="gradient"]:is([data-header="B"], [data-header="C"]) .tagline {
  background: transparent;
  padding-top: 0;
}
/* On the plane the words keep the palette's own accents in both themes. The light theme
   darkens --accent-N for a pale ground, which is not where these sit. */
:root[data-structure="gradient"]:is([data-header="B"], [data-header="C"]) .tagline span:nth-child(1) { color: var(--plane-accent-1, var(--accent-1)); }
:root[data-structure="gradient"]:is([data-header="B"], [data-header="C"]) .tagline span:nth-child(2) { color: var(--plane-accent-2, var(--accent-2)); }
:root[data-structure="gradient"]:is([data-header="B"], [data-header="C"]) .tagline span:nth-child(3) { color: var(--plane-accent-3, var(--accent-3)); }
:root[data-structure="gradient"]:is([data-header="B"], [data-header="C"]) .masthead .wrap {
  padding-bottom: 9px;
}

/* B's second line takes the third accent on the gradient rather than staying white, so
   the name reads as two weights the way the preview shows it. */
:root[data-structure="gradient"][data-header="B"] .mh-full span:nth-child(3) {
  color: var(--plane-accent-3, var(--accent-3));
}

/* The stripe echoes the tagline, in the same order. Flat structure only: over a gradient
   it would be a second, competing colour event. */
.stripe { display: flex; height: 4px; }
.stripe i { flex: 1; }
.stripe i:nth-child(1) { background: var(--plane-accent-1, var(--accent-1)); }
.stripe i:nth-child(2) { background: var(--plane-accent-2, var(--accent-2)); }
.stripe i:nth-child(3) { background: var(--plane-accent-3, var(--accent-3)); }
:root[data-structure="gradient"] .stripe { display: none; }

/* The page title band, below the masthead and deliberately quiet. */
.page-head { border-bottom: 1px solid var(--rule); }
.page-head .wrap { padding-block: 14px; }
.page-head h1 { font-size: 26px; }
.page-head .kicker {
  display: block; font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--fg-dim);
}

/* Bottom nav on a phone: at most four targets, the fourth being More. Every route in is
   a WhatsApp link on a mobile, so navigation belongs where a thumb reaches. Reverts to a
   full bar under the header at 720px and up, where More is unnecessary. */
.site-nav {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 50;
  display: flex; flex-wrap: wrap;
  background: var(--ground); border-top: 1px solid var(--rule);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.site-nav a, .nav-more {
  flex: 1 1 25%; min-width: 0; min-height: var(--tap);
  display: flex; align-items: center; justify-content: center;
  padding: 10px 4px; text-decoration: none; color: var(--fg-dim);
  background: none; border: 0; font: inherit;
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.site-nav a[aria-current="page"], .nav-more[data-within] {
  color: var(--accent-1); box-shadow: inset 0 2px 0 var(--accent-1);
}

/* The secondary routes are the More panel. Hidden until it is opened, then stacked above
   the bar rather than replacing it, so the bar never moves under the thumb. */
.site-nav a[data-secondary] { display: none; }
.site-nav[data-open] { flex-direction: column; align-items: stretch; }
.site-nav[data-open] a { flex: 0 0 auto; justify-content: flex-start; padding-inline: 20px;
  border-bottom: 1px solid var(--rule); font-size: 13px; }
.site-nav[data-open] a[data-secondary] { display: flex; }
.site-nav[data-open] .nav-more { flex: 0 0 auto; justify-content: flex-start; padding-inline: 20px; }

/* Clear the fixed bar so the last of the page is reachable. */
body { padding-bottom: calc(var(--tap) + 22px + env(safe-area-inset-bottom, 0px)); }

@media (min-width: 720px) {
  .site-nav {
    position: static; flex-wrap: nowrap; gap: 2px; overflow-x: auto;
    border-top: 0; border-block: 1px solid var(--rule); padding-bottom: 0;
  }
  .site-nav a, .site-nav a[data-secondary] {
    display: flex; flex: 0 0 auto; padding: 12px 14px; font-size: 13px; letter-spacing: .06em;
  }
  .site-nav a[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--accent-1); }
  .nav-more { display: none; }
  body { padding-bottom: 0; }
}

/* ── League table ─────────────────────────────────────────────────────────────
   Ten numeric columns do not fit a phone. The club, what it has played, its goal
   difference, its points and its form are what a reader actually came for; W/D/L and
   GF/GA are the detail and appear when there is room. The column classes are shared with
   ladderHeadHtml so a hidden column can never be hidden in the body alone. */

.ladder { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.ladder th, .ladder td { padding: 10px 5px; border-bottom: 1px solid var(--rule); text-align: right; }
.ladder th { font-size: 12px; color: var(--fg-dim); font-weight: 600; }
/* .grow is whichever column should absorb the spare width. On the league table that is
   the club; on a club's own Recent finishes table it is the season, and without it the
   columns spread evenly and the table reads as a row of unrelated numbers. */
.ladder .club, .ladder .grow { text-align: left; width: 99%; }
.ladder td.club a { text-decoration: none; }
.ladder td.club a:hover { text-decoration: underline; }
.ladder .pos { color: var(--fg-num); white-space: nowrap; }
.ladder .pts { font-weight: 700; }
.ladder tr[data-pos="1"] .pos, .ladder tr[data-pos="1"] .pts { color: var(--accent-1); }
.ladder-wrap { overflow-x: auto; }

.ladder .c-wdl, .ladder .c-g { display: none; }
@media (min-width: 720px) { .ladder .c-wdl, .ladder .c-g { display: table-cell; } }

/* The chip is the club's own colour, so the branding is present on the league's table
   without the table itself changing colour club by club. */
/* inline-block, not flex: display:flex on a td takes the cell out of the table's own box
   model and the columns stop lining up. */
.ladder .chip {
  display: inline-block; vertical-align: -3px; margin-right: 8px;
  width: 4px; height: 17px;
  background: var(--club-1, var(--accent-1));
}

/* Against the previous gameweek. At gameweek one there is no previous table, so every
   club is "new" and nothing is drawn rather than a column of meaningless dashes. */
.move { display: inline-block; width: 1em; margin-right: 2px; font-size: 9px; color: var(--fg-dim); }
.move[data-move="up"] { color: var(--accent-1); }
.move[data-move="down"] { color: var(--accent-2); }
.move[data-move="same"] { opacity: .4; }

.ladder .c-form { white-space: nowrap; padding-left: 10px; }
.ladder .c-form .mark { width: 18px; height: 18px; font-size: 10px; margin-left: 2px; }
/* Five marks do not fit beside a club name on a narrow phone. The three most recent do,
   and they are the three that matter; the full five return when there is room. */
.ladder .c-form .mark:nth-last-child(n+4) { display: none; }
@media (min-width: 560px) {
  .ladder .c-form .mark:nth-last-child(n+4) { display: inline-grid; }
  .ladder .c-form .mark { width: 22px; height: 22px; font-size: 11px; }
}

/* ── Gameweek scrubber ────────────────────────────────────────────────────────
   Twenty gameweeks is nineteen taps on a chevron. The chevrons stay for stepping a week
   at a time; the slider is how you get across a season. */
.gw-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding-block: 6px; }
.gw-nav button { min-width: var(--tap); background: none; border: 1px solid var(--rule); color: var(--fg-1); }
.gw-nav button[disabled] { opacity: .35; }
.gw-nav #gw-label { font-size: 13px; color: var(--fg-dim); flex: 1 0 100%; order: 3; }
.gw-nav input[type="range"] {
  flex: 1 1 120px; min-width: 0; accent-color: var(--accent-1);
  height: var(--tap); margin: 0; background: none;
}

/* ── Results ──────────────────────────────────────────────────────────────────
   Grouped by gameweek. A flat list repeated the gameweek on every row and still left the
   reader working out where one week ended. */
.gw-groups { list-style: none; padding: 0; }
.gw-group { padding-block: 6px 14px; }
.gw-group h2 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .12em; color: var(--fg-dim);
  padding-block: 10px 4px; border-bottom: 1px solid var(--rule);
}

.card { border: 1px solid var(--rule); padding: 16px; }
.cta { background: var(--accent-1); color: var(--cta-ink); padding: 14px 20px;
       display: inline-flex; min-height: var(--tap); align-items: center;
       text-decoration: none; font-weight: 600; border: 0; }

.countdown { display: flex; gap: 14px; font-variant-numeric: tabular-nums; }
.countdown .n { font-size: 40px; color: var(--accent-1); line-height: 1; }
.countdown .u { font-size: 11px; text-transform: uppercase; color: var(--fg-dim); }

/* The squad ask. Uniform across every club and the scorers page, so it reads as one
   deliberate pattern rather than as missing content. It must never look like real data. */
.squad-ask { position: relative; }
.squad-ask .sample { filter: blur(6px); opacity: .35; pointer-events: none; user-select: none; }
.squad-ask .ask { position: absolute; inset: 0; display: grid; place-content: center;
                  text-align: center; gap: 10px; padding: 16px; }

.site-footer { padding: 40px 16px; border-top: 1px solid var(--rule); color: var(--fg-dim); }
.site-footer .wordmark { font-size: 28px; font-weight: 800; color: var(--accent-1); cursor: default; }

.identity-bar {
  position: fixed; inset-inline: 0; z-index: 99;
  bottom: calc(var(--tap) + 18px + env(safe-area-inset-bottom, 0px));
  display: flex; gap: 8px; align-items: center; justify-content: center;
  padding: 10px; background: var(--ground); border-top: 1px solid var(--rule);
  font-size: 12px; font-variant-numeric: tabular-nums;
}
.identity-bar button { background: none; border: 1px solid var(--rule); color: var(--fg-1); padding: 6px 10px; }

.filters { display: flex; gap: 12px; flex-wrap: wrap; padding-block: 16px; }
.filters select { min-height: var(--tap); background: var(--ground); color: var(--fg-1); border: 1px solid var(--rule); }
.results { list-style: none; padding: 0; }
.result { display: grid; grid-template-columns: 1fr auto 1fr minmax(52px, auto); gap: 10px;
          align-items: center; padding: 11px 0; border-bottom: 1px solid var(--rule); }
.result .gw { color: var(--fg-num); font-size: 12px; }
.result .score { font-variant-numeric: tabular-nums; color: var(--accent-1); font-weight: 700;
                 white-space: nowrap; }
/* The winner is the one thing a reader looks for. The loser is not struck through or
   greyed out, only left at normal weight: a 1-0 loss is still a result, not a failure. */
.result .side { text-decoration: none; min-width: 0; }
.result .side:hover { text-decoration: underline; }
.result .side.won { font-weight: 700; }
.result .side:nth-of-type(2) { text-align: right; }
/* The same chip as the table, so a club carries one colour wherever its name is listed.
   The anchor holds data-club itself, so the chip reads that club's colour even on another
   club's page. */
.result .side::before, .bye a::before {
  content: ''; display: inline-block; vertical-align: -2px; margin-right: 8px;
  width: 4px; height: 14px; background: var(--club-1, var(--accent-1));
}
.result .match-report:empty { min-height: 1px; }
.result .match-report {
  font-size: 11px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--accent-1); text-decoration: none; white-space: nowrap;
}
.result .match-report:hover { text-decoration: underline; }
.empty { color: var(--fg-dim); padding: 20px 0; }

.club-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.club-tile { display: flex; align-items: center; min-height: 84px; padding: 14px;
             border: 1px solid var(--rule); text-decoration: none; font-weight: 600; }
.club-tile:hover { border-color: var(--accent-1); }
.form { letter-spacing: .3em; font-weight: 700; }
.note { color: var(--fg-dim); font-size: 13px; }
.squad-ask .sample { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; min-height: 220px; }
.squad-ask .sample span { background: var(--rule); min-height: 42px; }

.interest { display: grid; gap: 12px; max-width: 34rem; }
.interest label { display: grid; gap: 4px; font-size: 13px; color: var(--fg-dim); }
.interest input, .interest textarea {
  background: var(--ground); color: var(--fg-1); border: 1px solid var(--rule);
  padding: 10px; min-height: var(--tap); font: inherit;
}
.interest .hp { position: absolute; left: -9999px; }
.interest button { justify-self: start; }

/* Club detail */
.club-line { display: flex; flex-wrap: wrap; gap: 18px; padding-block: 14px;
             border-bottom: 1px solid var(--rule); }
.club-line div { display: grid; gap: 2px; }
.club-line dt { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--fg-dim); }
.club-line dd { margin: 0; font-variant-numeric: tabular-nums; font-size: 18px; }
.club-line dd.big { font-size: 30px; line-height: 1; color: var(--accent-1); }

.mark { display: inline-grid; place-content: center; width: 22px; height: 22px;
        font-size: 11px; font-weight: 700; border: 1px solid var(--rule); }
/* --ground, not --block-ink: in the "-mark" palettes block-ink equals accent-1, so a
   win marker painted with it was teal on teal and the letter disappeared. */
.mark[data-r="W"] { background: var(--accent-1); color: var(--ground); border-color: var(--accent-1); }
.mark[data-r="D"] { color: var(--fg-dim); }
.mark[data-r="L"] { color: var(--fg-num); opacity: .6; }
.form-marks { display: flex; gap: 4px; padding-block: 14px; }

.pos-chart { width: 100%; height: auto; max-width: 480px; display: block; padding-block: 8px; }

.club-result { grid-template-columns: auto auto 1fr auto auto; gap: 10px; }
.club-result .opp { font-weight: 600; }
.club-result .venue { color: var(--fg-num); font-size: 11px; border: 1px solid var(--rule); padding: 1px 5px; }
.club-line .sep { color: var(--fg-dim); padding-inline: 2px; }

@media (min-width: 720px) { .identity-bar { bottom: 0; } }

/* Season tabs. Rendered from seasons.json, so a backfilled season adds a tab by itself. */
.season-tabs { display: flex; gap: 4px; padding-block: 14px; overflow-x: auto; }
.season-tab {
  min-height: var(--tap); display: flex; align-items: center; padding: 0 14px;
  text-decoration: none; color: var(--fg-dim); border: 1px solid var(--rule);
  white-space: nowrap; font-size: 13px;
}
.season-tab[aria-selected="true"] {
  color: var(--ground); background: var(--accent-1); border-color: var(--accent-1);
  font-weight: 600;
}
.ladder-empty { padding: 28px 0; color: var(--fg-dim); border-block: 1px solid var(--rule); }
.ladder-empty a { color: var(--accent-1); }

/* Games: the table and the match list as two sections under one season switch. The section
   titles are larger than the round headings inside the list, so the two levels read apart. */
.games-section { padding-block: 8px 20px; }
.games-section + .games-section { border-top: 1px solid var(--rule); margin-top: 12px; padding-top: 18px; }
.games-section > h2, .games-section-head h2 { font-size: 21px; }
.games-section-head { display: flex; align-items: baseline; justify-content: space-between;
                      gap: 12px; flex-wrap: wrap; padding-bottom: 6px; }
.race-link { margin: 0; }
.race-link a { color: var(--accent-1); font-weight: 600; text-decoration: none;
               display: inline-flex; align-items: center; min-height: var(--tap); }
.race-link a::after { content: "\25B6"; font-size: 10px; margin-left: 6px; }
.race-link a:hover { text-decoration: underline; }

/* Editorial: reports and recaps */
.latest { border: 1px solid var(--rule); padding: 16px; margin-block: 18px; }
.latest h2 { font-size: 21px; margin-top: 4px; }
.latest a { color: var(--accent-1); text-decoration: none; }
.latest a:hover { text-decoration: underline; }
.article { padding-block: 8px 24px; }
.article h2 { font-size: 20px; margin-top: 22px; }
.article h3 { font-size: 16px; margin-top: 18px; }
.article p { margin-top: 12px; }
.article ul { margin-top: 12px; padding-left: 20px; }
.article li { margin-top: 4px; }
.article a { color: var(--accent-1); }
.article-back { padding-block: 8px 24px; }
.report-list { list-style: none; padding: 0; }
.report-list li { padding: 12px 0; border-bottom: 1px solid var(--rule); display: grid; gap: 2px; }
.report-list a { color: var(--accent-1); text-decoration: none; font-weight: 600; }

/* The ask block. Used wherever the site is waiting on people rather than on code, so it
   reads the same everywhere and never as an error. */
.ask-block { border: 1px solid var(--rule); padding: 22px 18px; display: grid; gap: 12px;
             justify-items: start; margin-block: 18px; }
.ask-block p { color: var(--fg-dim); }
.club-facts { color: var(--fg-dim); font-size: 13px; padding-bottom: 10px; }

/* Club profile */
.club-header { display: flex; gap: 16px; align-items: flex-start; padding-block: 18px; }
/* A crest sits on a faint plate. DO IT F.C.'s is a dark shield with gold detail, which
   on a dark page reads as empty space, and we do not control what other clubs will send.
   The plate costs nothing on a light crest and rescues a dark one. */
.club-header .crest {
  width: 108px; height: auto; flex: 0 0 auto; object-fit: contain;
  background: var(--rule-weak); padding: 8px;
}
.club-header h1 { font-size: 28px; }
.club-names { color: var(--fg-dim); font-size: 13px; margin-top: 2px; }
.club-id { min-width: 0; }
/* Honours sit under the name as a wrapping run of short items, so they stay a line or two
   beside the crest on a phone instead of growing into a section of their own. */
.club-honours { margin-top: 4px; }
.club-honours ul { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap;
                   gap: 4px 14px; font-size: 13px; font-weight: 600; color: var(--fg-1); }
.club-honours li { display: flex; align-items: center; gap: 6px; }
.club-honours li::before { content: ""; width: 6px; height: 6px; flex: 0 0 auto;
                           background: var(--accent-1); }
.club-honours p { color: var(--fg-dim); font-size: 11px; margin: 4px 0 0; }

.crest-ask { width: 84px; min-height: 84px; display: grid; place-content: center;
             border: 1px dashed var(--rule); padding: 8px; text-align: center; }
.crest-ask p { font-size: 10px; }

.ask-inline p { color: var(--fg-dim); font-size: 12px; margin: 0; }
.ask-inline strong { color: var(--fg-1); }

.squad-photo { margin: 0 0 18px; }
.squad-photo img { width: 100%; height: auto; display: block; }
.squad-photo-ask { min-height: 160px; display: grid; place-content: center; text-align: center;
                   border: 1px dashed var(--rule); padding: 20px; }

.highlights { list-style: none; padding: 0; display: grid; gap: 6px; }
.highlights li { padding: 8px 12px; border-left: 3px solid var(--accent-1); background: var(--rule-weak); }


/* ── Club branding ────────────────────────────────────────────────────────────
   Every rule here reads var(--club-1, var(--accent-1)), so a club with no colours of its
   own falls back to the league accent and looks unchanged. Nothing in the shared chrome
   above reads a --club- token, which is the whole scoping rule: see tokens.css. */

.club-header { border-bottom: 3px solid var(--club-1, var(--accent-1)); margin-bottom: 4px; }
/* img.crest, not .crest: the "no crest yet" placeholder shares the class, and Jakarta
   Vikings' white plate put dim grey text on white. The plate is for artwork we did not
   draw and cannot recolour; the placeholder is ours and belongs on the page ground. */
.club-header img.crest { background: var(--club-2, var(--rule-weak)); }
.club-header h1 { color: var(--fg-1); }

.club-colours { display: flex; align-items: center; gap: 8px; padding-block: 10px;
                color: var(--fg-dim); font-size: 12px; }
.club-colours i { width: 16px; height: 16px; flex: 0 0 auto; border: 1px solid var(--rule); }
.club-colours i:nth-child(1) { background: var(--club-1, var(--accent-1)); }
.club-colours i:nth-child(2) { background: var(--club-2, var(--rule-weak)); }

.highlights li { border-left-color: var(--club-1, var(--accent-1)); }
.club-honours li::before { background: var(--club-1, var(--accent-1)); }
.club-line dd.big { color: var(--club-1, var(--accent-1)); }
[data-club] .mark[data-r="W"] {
  background: var(--club-1, var(--accent-1)); border-color: var(--club-1, var(--accent-1));
}
[data-club] .result .score { color: var(--club-1, var(--accent-1)); }
[data-club] .report-list a, [data-club] .article a { color: var(--club-1, var(--accent-1)); }

/* On the index a tile carries its club's colour as an edge, so the branding is visible
   before you open anything and an unbranded club simply has the league accent. */
.club-tile { border-left: 3px solid var(--club-1, var(--accent-1)); }
.club-tile:hover { border-color: var(--club-1, var(--accent-1)); }


/* ── Sponsors ─────────────────────────────────────────────────────────────────
   A sponsor logo is almost always dark artwork drawn for a white page, so it sits on a
   pale plate rather than on the site ground. That is a plate for the logo, not a club or
   league colour, which is why it is one token used everywhere and not an accent. */

.sponsor-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; padding-block: 6px;
}
.sponsor {
  display: grid; place-items: center; gap: 6px; min-height: 84px; padding: 12px;
  background: var(--plate); border: 1px solid var(--rule);
  text-decoration: none; text-align: center;
}
.sponsor img { max-height: 52px; width: auto; object-fit: contain; }
/* Sponsor names sit on the pale plate, so they take the plate's ink, never the page's. */
.sponsor .sponsor-name {
  font-family: "Barlow Condensed", ui-condensed, system-ui, sans-serif;
  font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  font-size: 17px; line-height: 1.1; color: var(--plate-ink);
}
.sponsor .sponsor-tier {
  font-size: 10px; text-transform: uppercase; letter-spacing: .12em; color: var(--plate-dim);
}

/* A sponsor whose artwork is white would vanish on the pale plate. The cell keeps its
   size and border, so a mixed strip still reads as one set. */
.sponsor[data-ink="light"] { background: var(--plate-dark); }
.sponsor[data-ink="light"] .sponsor-name { color: var(--plate-dark-ink); }
.sponsor[data-ink="light"] .sponsor-tier { color: var(--plate-dark-dim); }
.sponsors { padding-block: 8px; }

/* Sitewide, and quieter than the home page strip: it is a credit here, not a section. */
.footer-sponsors { margin-top: 18px; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
.footer-sponsors .sponsor { min-height: 62px; padding: 8px; }
.footer-sponsors .sponsor img { max-height: 38px; }

/* ── Fixtures ─────────────────────────────────────────────────────────────────
   Fixtures and results share one row. A fixture keeps the result's columns, with a plain
   "v" for the score, so a half-played round still lines up. The venue line sits underneath,
   spanning both clubs and the score but not the report cell, so it centres under the score. An unbooked venue is dim rather than hidden: it is a slot the home
   club still has to fill, not a missing value. */
.result:has(.fixture-where) { row-gap: 2px; }
.fixture .score { color: var(--fg-dim); font-weight: 600; }
.result .fixture-where { grid-column: 1 / 4; text-align: center; font-size: 12px; color: var(--fg-num); }
.result .fixture-where.tbc { color: var(--fg-dim); font-style: italic; }
.gw-group .round-date { text-transform: none; letter-spacing: 0; margin-left: 8px; font-weight: 400; }
.bye { font-size: 13px; color: var(--fg-dim); padding: 10px 0; border-bottom: 1px solid var(--rule); max-width: none; }
.bye a { color: var(--fg-1); font-weight: 600; text-decoration: none; }
.bye a:hover { text-decoration: underline; }

/* ── Club tabs ────────────────────────────────────────────────────────────────
   The same control as the standings season tabs, so the site has one tab pattern. */
.club-tabs { margin-top: 8px; border-bottom: 1px solid var(--rule); }
.club-panel { padding-top: 16px; }
.squad td:not(.grow), .squad th:not(.grow) { text-align: left; }

/* ── Theme toggle ─────────────────────────────────────────────────────────────
   Top right of the masthead, over the header plane. It carries its own disc in the page
   ground so it reads on every plane and structure without borrowing the header ink, which
   on the -mark palettes is a colour and not an ink. The disc also previews the ground the
   page is currently on. */
.masthead .wrap { position: relative; }
.theme-toggle {
  position: absolute; top: 10px; right: 10px;
  width: var(--tap); height: var(--tap); padding: 0; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: var(--ground); color: var(--fg-1); border: 1px solid var(--rule);
  text-shadow: none;
}
@media (min-width: 720px) { .theme-toggle { right: 30px; } }
.theme-toggle svg { width: 18px; height: 18px; }
/* Shows where a tap goes: the sun on a dark page, the moon on a light one. */
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }
.theme-toggle:focus-visible { outline: 2px solid var(--fg-1); outline-offset: 2px; }

/* ── Season Race ──────────────────────────────────────────────────────────────
   The board is a stack of absolutely positioned rows, each moved to its slot with a
   transform, so a club slides to its new place instead of the table redrawing. Bars scale
   rather than resize for the same reason: transforms animate without layout. Every club
   colour is read with a fallback: the club's own, else its series slot for the season. */
.race { --race-move: 660ms; --race-slot: 46px; padding-block: 8px 24px; }
.race-counter { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; padding-block: 10px 4px; }
#race-gw {
  font-family: "Barlow Condensed", ui-condensed, system-ui, sans-serif;
  font-size: clamp(40px, 11vw, 60px); font-weight: 800; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--fg-1);
}
.race-of { color: var(--fg-dim); font-size: 14px; }
.race-final {
  font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent-1); border: 1px solid var(--accent-1); padding: 1px 8px; align-self: center;
}

.race-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding-block: 6px; }
.race-controls button, .race-controls select {
  min-width: var(--tap); min-height: var(--tap); padding: 0 12px;
  background: none; border: 1px solid var(--rule); color: var(--fg-1); font: inherit;
}
.race-controls select { background: var(--ground); margin-left: auto; }
.race-controls button[disabled] { opacity: .35; }
.race-controls .race-play {
  min-width: 80px; font-weight: 700;
  background: var(--accent-1); border-color: var(--accent-1); color: var(--cta-ink);
}
.race-range { width: 100%; height: var(--tap); margin: 0; accent-color: var(--accent-1); background: none; }

.race-board {
  position: relative; height: calc(var(--rows, 6) * var(--race-slot));
  margin-block: 8px 20px; border-top: 1px solid var(--rule);
}
.race-row {
  position: absolute; inset-inline: 0; top: 0; height: var(--race-slot);
  display: grid; grid-template-columns: 2ch 4px minmax(0, 11rem) 1fr auto; gap: 10px;
  align-items: center; padding-inline: 2px;
  border-bottom: 1px solid var(--rule); background: var(--ground);
  font-variant-numeric: tabular-nums; cursor: pointer;
  transform: translateY(calc(var(--slot, 0) * var(--race-slot)));
  transition: transform var(--race-move) cubic-bezier(.4, 0, .2, 1), opacity .2s;
}
.race-pos { color: var(--fg-num); text-align: right; }
.race-row[data-pos="1"] .race-pos, .race-row[data-pos="1"] .race-pts { color: var(--accent-1); }
.race-chip { width: 4px; height: 20px; background: var(--club-1, var(--accent-1)); }
.race-name { font-weight: 600; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.race-name:hover { text-decoration: underline; }
.race-bar { height: 8px; background: var(--rule-weak); overflow: hidden; }
.race-bar i {
  display: block; height: 100%; background: var(--club-1, var(--accent-1));
  transform-origin: left; transform: scaleX(var(--fill, 0));
  transition: transform var(--race-move) cubic-bezier(.4, 0, .2, 1);
}
.race-pts { font-weight: 700; min-width: 2.5ch; text-align: right; }
/* Goal difference is detail. It shows where there is room and gives way on a phone. */
.race-gd { display: none; color: var(--fg-dim); font-size: 13px; min-width: 3ch; text-align: right; }
@media (min-width: 560px) {
  .race-row { grid-template-columns: 2ch 4px minmax(0, 13rem) 1fr auto auto; }
  .race-gd { display: block; }
}

.race-sub { font-size: 12px; text-transform: uppercase; letter-spacing: .12em; color: var(--fg-dim);
            padding-block: 6px; border-bottom: 1px solid var(--rule); }
.race-chart { width: 100%; max-width: 640px; height: auto; display: block; padding-block: 10px; overflow: visible; }
.race-grid { stroke: var(--rule); stroke-width: 1; }
.race-axis { font-size: 11px; fill: var(--fg-num); }
.race-line polyline {
  fill: none; stroke: var(--club-1, var(--accent-1)); stroke-width: 2.5;
  stroke-linejoin: round; stroke-linecap: round;
  transition: opacity .2s;
}
/* The cover is the page ground laid over the weeks not yet played. It slides right as the
   season runs, which draws the lines without redrawing the SVG. */
.race-cover { fill: var(--ground); transition: transform var(--race-move) linear; }
.race-dot { transition: transform var(--race-move) cubic-bezier(.4, 0, .2, 1), opacity .2s; }
.race-dot circle { fill: var(--club-1, var(--accent-1)); stroke: var(--ground); stroke-width: 1.5; }
.race-dot.is-off { visibility: hidden; }

/* One club brought forward, the rest faded, while a club is pointed at or pinned. */
.race[data-focus] .race-line:not(.is-focus) polyline,
.race[data-focus] .race-dot:not(.is-focus) { opacity: .18; }
.race[data-focus] .race-row:not(.is-focus) { opacity: .55; }

/* On load and for reduced motion, things are placed rather than moved. */
.race.is-instant *, .race.is-instant { transition: none !important; }
@media (prefers-reduced-motion: reduce) {
  .race *, .race { transition: none !important; }
}
