/* ==========================================================================
   Design tokens — gameweek38
   --------------------------------------------------------------------------
   INSTRUMENT: the table as a precision reference tool.

   Two rules govern everything here:

   1. Nothing is drawn that isn't separating two things. Structure is 1px
      hairlines — no 2px frames, no fills, no shadows. The table is the only
      thing with visual weight because it is the only thing anyone came for.
   2. Figures are mono. A league table is a readout, and IBM Plex Mono makes
      every column align by construction rather than by luck.

   Colour is near-monochrome with a single signal blue. The four qualification
   hues are the only other colour in the system, and they are meaning, not
   decoration.
   ========================================================================== */

/* ==========================================================================
   The typeface, SELF-HOSTED. It used to come from Google Fonts, which meant
   Google received every visitor's IP address before anything else on the page
   loaded — on all three pages, the privacy policy included. Nothing else on the
   site talked to a third party at load. Now nothing does.

   IBM Plex is SIL Open Font License 1.1: self-hosting and redistributing it is
   explicitly allowed, and `assets/fonts/OFL.txt` is the licence the OFL requires
   to travel with the files. Don't delete it.

   THE SANS IS ONE VARIABLE FONT COVERING 400-700, and that is not a guess: the
   four static weights Google served for `wght@400;500;600;700` were byte-for-byte
   the SAME FILE, md5 and all. Four weights, one download — so `font-weight` here
   is a RANGE, and asking for 500 or 700 instantiates the axis rather than
   synthesising a fake bold. The Mono is genuinely static: its three weights have
   three different checksums, so it takes three files.

   WHY THE SUBSETS AND THEIR unicode-range ARE COPIED VERBATIM from Google's own
   CSS: the range is what stops a browser fetching `latin-ext` for a page that
   never uses it. Most visitors need `latin` alone — 40KB for the whole Sans —
   and pull the extended file only when a club name reaches past it. Delete the
   ranges and every visitor downloads both. The greek, cyrillic and vietnamese
   subsets Google also offers are NOT here; five European leagues do not reach
   them, and they were 190KB of the 314KB the naive copy came to.

   `font-display: swap` is kept from the old link: text paints immediately in the
   fallback rather than leaving the page blank if a font is slow.
   ========================================================================== */
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/ibm-plex-sans-var-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/ibm-plex-sans-var-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-500-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-600-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ---- Raw palette ---- */
  --sheet-100: #FCFCFB;   /* table + panels */
  /* The page ground is deliberately a step darker than the panels. With the
     rules removed from under the header and the control bar, TONE is the only
     thing left separating a panel from the page — and the sticky bar needs the
     table to read as a different plane as it scrolls beneath. At #F6F6F4 the
     two were nearly identical and everything merged. */
  --sheet-200: #EFEFEC;   /* page ground */
  --sheet-300: #F3F3F0;   /* row hover */
  --sheet-400: #E2E4E1;   /* hairlines */

  --graphite-800: #101213;  /* text and structure */
  /* Darkened from #6A6F73 when the page ground went from #F6F6F4 to #EFEFEC.
     Muted text sits on FOUR grounds — surface, hover, selected row and the page
     itself — and on the new ground it measured 4.41:1, under the floor. Worst
     case is now 4.89:1. Deepening the ground means deepening this with it. */
  --graphite-500: #63686C;  /* muted text */
  --graphite-400: #8A9094;

  /* The accent. #0047FF was pure-channel blue — chroma 255, the maximum a
     screen can produce — which vibrated wherever it appeared as a fill: the
     active view segment and, worst, the twenty checkboxes in the club list all
     at once. #2451C8 keeps the same confident blue at chroma 164, a third less,
     and every ratio it has to clear went UP rather than down. */
  --signal-700: #1C40A0;
  --signal-600: #2451C8;    /* the accent */
  --signal-300: #7FA5F0;
  --signal-050: #EDF1FB;

  /* Data colours: readable as text first, coloured second. */
  --data-pos: #00734A;
  --data-neg: #C4102A;

  /* ---- Semantic (light) ---- */
  --bg:         var(--sheet-200);
  --surface:    var(--sheet-100);
  --surface-2:  var(--sheet-300);
  /* The ground of a segmented track sitting on the PAGE — the view switcher and
     the theme switch. It is a token rather than a flat `--surface` because the
     two themes want opposite ends of the ramp, and picking one for both makes
     the control vanish in the other.

     A track has one job here: to read as an object ON the page. Measured against
     `--bg`, light goes 1.036 -> 1.122 moving from `--surface-2` up to the panel
     white, and dark goes 1.114 -> 1.021 making the same move — because dark's
     `--surface` is only three values off its `--bg` where light's is thirteen.
     So light takes `--surface` and dark keeps `--surface-2`; both are "one step
     away from the page", which is the actual rule.

     NOT for a track inside a panel — `.segmented--rail` sits on `--surface` and
     sets its own ground. */
  --track:      var(--surface);
  --fg:         var(--graphite-800);
  --fg-muted:   var(--graphite-500);
  --fg-faint:   var(--graphite-400);

  --accent:      var(--signal-600);
  --accent-hover:var(--signal-700);
  --on-accent:   #FFFFFF;


  --rule:      var(--sheet-400);   /* structural hairlines — 1px, not 2px */
  --rule-strong: var(--graphite-800);  /* the one heavy rule, under the thead */
  --rule-soft: var(--sheet-400);
  --focus:     var(--signal-600);

  --pos-fg: var(--data-pos);
  --neg-fg: var(--data-neg);

  /* ---- Qualification zones ----
     Each competition's own colour so the bar is recognisable without the
     legend. Every value clears 3:1 against --surface, --surface-2 AND
     --row-selected in its own theme, because the bar is non-text content
     carrying meaning and it sits on all three grounds.

     The three European hues follow the competitions' own bracket graphics —
     UCL's violet-leaning blue, UEL's red-orange, UECL's pure green — taken
     down in brightness from the broadcast values, which sit at 1.6-2.8:1 on a
     white ground and fail outright. Hue is the reference's; lightness is
     whatever the 3:1 floor allows.

     UEL is at hue 26 rather than the reference's 19: at 19 it lands 24.9 dE
     from --zone-rel, and orange beside red is the one pair in this palette
     that can be confused. 26 is still the Europa orange and opens the gap to
     34.2. UECL is set lower in HSL lightness than the other two because green
     at equal lightness is far brighter; 30% is what brings it level. */
  --zone-ucl:  #1313AF;
  --zone-uel:  #B7550B;
  --zone-uecl: #0B8E12;
  --zone-rel:  #C4102A;

  /* SECOND-TIER zones, for the Championship. A league below the top flight has
     no European places at all — its table is about going up — so its bars
     needed ids of their own rather than a `ucl` bar labelled "Champions
     League" on a division that plays for none.

     THE VALUES ARE DELIBERATELY THE MEASURED ONES ABOVE: promotion takes
     UECL's green, the play-offs take UCL's blue. Green for going up and blue
     for the play-offs is the convention every English table uses, and reusing
     values that already clear the 3:1 floor on all three grounds in both
     themes means no new colour needed deriving. They also already sit far
     enough apart in dE to be told apart, because they co-occur in a Premier
     League table.

     COPIED, NOT ALIASED. `var(--zone-uecl)` would look tidier and would mean a
     future retune of the Conference League's bar silently moved what promotion
     looks like. These are separate facts that happen to agree today. */
  --zone-pro:  #0B8E12;
  --zone-po:   #1313AF;

  /* Row selection. A muted figure landing on this tint needs its own colour:
     at #E4EBFF the muted grey measured 4.26:1, under the floor. Checked at
     #EDF2FF — 4.53:1. Any new colour on a selected row is checked against
     --row-selected, never --surface. */
  --row-selected: var(--signal-050);
  --pos-on-selected: #005638;
  --neg-on-selected: #960C20;
  --ovr-on-selected: #4E5457;

  /* ---- Type ----
     Plex Sans for language, Plex Mono for every figure. */
  --font-display: "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --font-ui:      "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --font-figure:  "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;

  /* A real scale, ~1.2 between steps.
     The previous one had two faults: step-0 and step-1 were 16px and 17px —
     a 1.06 ratio, which is a rounding error rather than a step — and step-3
     and step-4 both capped at 2.25rem, so they collided at wide viewports. */
  --step--2: 0.6875rem;  /* 11px — micro labels, uppercase only */
  --step--1: 0.8125rem;  /* 13px — table figures, controls */
  --step-0:  0.9375rem;  /* 15px — club names, headings, body */
  /* -1, -2 and -4 are currently unclaimed by any rule. They stay: this scale is
     published in design-system/MASTER.md and a ladder with rungs missing is
     worse than a ladder with spare ones. Their old comments named uses that had
     moved on — the share card's title and headings are drawn on canvas, in
     share.js, in px, because canvas reads no CSS. */
  --step-1:  1.125rem;   /* 18px */
  --step-2:  1.375rem;   /* 22px */
  --step-3:  1.75rem;    /* 28px — the nameplate */
  --step-4:  clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem);  /* 28–40px */

  /* ---- Space ---- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;

  --border-w: 1px;

  /* ---- Radius ----
     The design was radius 0 everywhere until 2026-08-20, enforced by never
     SETTING a radius. It is a scale now: panels are tiles, controls are soft,
     the two segmented controls are pills. Three steps, no more — a fourth
     invites a page where nothing shares an edge with anything else. */
  --r-card: 16px;   /* panels, table shells, chart frames */
  --r-ctl: 10px;    /* buttons, inputs, popovers */
  --r-pill: 999px;  /* segmented tracks and their thumbs */

  /* ---- Elevation ----
     Two steps. `--shadow` lifts a tile off the page; `--shadow-lift` is for the
     things that sit above the page proper — popovers, and the segmented thumb.

     DARK CANNOT USE BLACK SHADOWS: on a near-black ground they are invisible,
     so the dark variants lead with a light top hairline and keep the blur only
     to soften the edge. Every dark UI that reads as layered does this. */
  --shadow: 0 1px 2px rgb(0 0 0 / 0.05), 0 6px 20px rgb(0 0 0 / 0.05);
  --shadow-lift: 0 2px 4px rgb(0 0 0 / 0.07), 0 12px 32px rgb(0 0 0 / 0.08);
  --shell-max: 1320px;
  /* Width of the filter rail — and therefore of the league selector directly
     above it, so the page has one vertical edge running down its left side.
     One token, so the two cannot drift apart. */
  --rail-w: 260px;

  /* Band height for the two section heads, so FILTERS and the table heading
     stay on one line together. */
  --head-h: 30px;

  --row-h: 36px;
  --thead-h: 30px;
  /* Height of the bar controls. 44px was applied at every width, which is what
     made the mobile control bar 184px tall. Target size is a property of the
     INPUT DEVICE, so the 44px floor is restored under `pointer: coarse` below
     and nowhere else. */
  --control-h: 32px;

  --dur-fast: 120ms;
  --dur: 200ms;
  --dur-slow: 360ms;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-out-back: cubic-bezier(0.22, 1.15, 0.36, 1);
}

/* Touch targets are a property of the input device, not the viewport. */
@media (pointer: coarse) {
  :root { --head-h: 44px; --thead-h: 44px; --row-h: 44px; --control-h: 44px; }
}

/* ---- Dark ----
   The signal blue is unreadable on a dark ground, so it lightens and the text
   on it darkens. Same role, inverted execution. Declared twice on purpose:
   the media query covers the "system" default, the attribute covers an
   explicit choice, and the toggle has to win in both directions. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
  /* Black shadows vanish on a near-black ground — elevation here leads with a
     light top hairline and keeps the blur only to soften the edge. */
  --shadow: 0 1px 0 rgb(255 255 255 / 0.04), 0 8px 24px rgb(0 0 0 / 0.5);
  --shadow-lift: 0 1px 0 rgb(255 255 255 / 0.07), 0 14px 36px rgb(0 0 0 / 0.6);

    --bg:        #0B0D0E;
    --surface:   #0E1011;
    --surface-2: #171A1C;
    /* See the note at `--track` in the light block: dark's `--surface` is too
       near its `--bg` to read as a track, so the step goes the other way. */
    --track:     var(--surface-2);
    --fg:        #ECEEEC;
    --fg-muted:  #949A9E;
    --fg-faint:  #6E7478;

    --accent:       var(--signal-300);
    --accent-hover: #96B8FF;
    --on-accent:  #06142E;

    --rule:        #262A2C;
    --rule-strong: #4A5052;
    --rule-soft:   #1F2325;
    --focus:       var(--signal-300);

    --pos-fg: #4FC894;
    --neg-fg: #FF6B7E;

    /* Same three reference hues as light, lightened to clear 3:1 from the
       other side. --row-selected (#1B2740) is the binding ground here, not
       --surface. */
    --zone-ucl:  #7373F0;
    --zone-uel:  #E76C0D;
    --zone-uecl: #0FBA18;
    --zone-rel:  #FF6B7E;
    --zone-pro:  #0FBA18;
    --zone-po:   #7373F0;

    --row-selected: #1B2740;
    --pos-on-selected: #6FDCA9;
    --neg-on-selected: #FF8B9A;
    --ovr-on-selected: #A6ACB0;
  }
}

:root[data-theme="dark"] {
  /* Black shadows vanish on a near-black ground — elevation here leads with a
     light top hairline and keeps the blur only to soften the edge. */
  --shadow: 0 1px 0 rgb(255 255 255 / 0.04), 0 8px 24px rgb(0 0 0 / 0.5);
  --shadow-lift: 0 1px 0 rgb(255 255 255 / 0.07), 0 14px 36px rgb(0 0 0 / 0.6);

  --bg:        #0B0D0E;
  --surface:   #0E1011;
  --surface-2: #171A1C;
  /* See the note at `--track` in the light block: dark's `--surface` is too near
     its `--bg` to read as a track, so the step goes the other way. */
  --track:     var(--surface-2);
  --fg:        #ECEEEC;
  --fg-muted:  #949A9E;
  --fg-faint:  #6E7478;

  --accent:       var(--signal-300);
  --accent-hover: #96B8FF;
  --on-accent:    #06142E;

  --rule:        #262A2C;
  --rule-strong: #4A5052;
  --rule-soft:   #1F2325;
  --focus:       var(--signal-300);

  --pos-fg: #4FC894;
  --neg-fg: #FF6B7E;

  --zone-ucl:  #7373F0;
  --zone-uel:  #E76C0D;
  --zone-uecl: #0FBA18;
  --zone-rel:  #FF6B7E;
  --zone-pro:  #0FBA18;
  --zone-po:   #7373F0;

  --row-selected: #1B2740;
  --pos-on-selected: #6FDCA9;
  --neg-on-selected: #FF8B9A;
  --ovr-on-selected: #A6ACB0;
}
