/* Gaffer IQ — base.css
   Reset, CSS variables (design tokens), typography.
   All colour, spacing, radius, font, and band tokens live here.
   Components reference var(--…) only; no raw hex or px literals elsewhere. */

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

/* Ensure the HTML `hidden` attribute wins even when an element has an
   explicit display property (e.g. display:flex on .ranker-loading). */
[hidden] { display: none !important; }

:root {
  /* --- Colour palette ---------------------------------------------------- */
  --color-bg:             #0d1117;
  --color-surface:        #161b22;
  --color-surface-raised: #1c2128;
  --color-border:         #30363d;
  --color-border-subtle:  #21262d;
  --color-text:           #e6edf3;
  --color-muted:          #8b949e;
  --color-accent:         #58a6ff;
  --color-accent-muted:   rgba(88, 166, 255, 0.10);

  /* --- Band colours: PRIMITIVES ------------------------------------------
     A hue, named after itself and nothing else. Nothing outside this block
     should reference one directly unless it genuinely means "this colour"
     rather than "this rating" — the semantic layer below is what components
     read. The split exists so a scale can be re-pointed — either wholesale
     (the five-tier scale became seven by editing the semantics below, not
     every component) or in a scope. A scoped block cannot define --band-good
     in terms of --band-great: both resolve against the scope's OWN values and
     the reference goes circular. Every scale therefore reads from this layer,
     which no scope ever overrides. */
  --band-dark-green: #1f8c48;
  --band-green:      #3fb950;
  /* Down to a single consumer, --band-deep-blue, and therefore to a single
     job: the league table's Champions zone. It is no longer any kind of
     "blue" the reader is asked to interpret — --band-light-blue below is the
     app's blue, on both the 0-100 band scale and the ranker's rank-relative
     chips. Do not reach for this one for anything new. */
  --band-blue:       #1f6feb;
  /* The light blue 'good' reads in. Deliberately the same value as
     --color-accent, and deliberately NOT that token: a rating is not chrome,
     and the day the accent moves this band must not move with it. #1f6feb,
     the blue it replaced, was the darkest hue in the scale and the only one
     that had to be hunted for at chip size — backwards for the second-best
     tier. */
  --band-light-blue: #58a6ff;
  --band-gold:       #ffc83d;
  --band-grey:       #6e7681;
  --band-amber:      #d29922;
  --band-yellow:     #e3b341;
  --band-orange:     #f0883e;
  --band-red:        #f85149;
  --band-dark-red:   #b62324;
  /* Not a hue — a void. Below every surface in the palette (--color-bg is
     #0d1117), so a tile filled with it reads as a hole punched in the page
     rather than as one more coloured chip. It is the bottom tier's fill, the
     mirror of what gold does at the top. */
  --band-black:      #0c0c0c;
  /* Not a rating hue — the INK the top tier's digits are set in, on top of its
     gold. Cooler and brighter than --color-text (#e6edf3) so it reads as
     silver against a warm ground rather than as ordinary body text that
     happens to be sitting there. */
  --band-silver:     #f4f8fd;
  /* Soft/desaturated rather than a true lime — lime read too bright against
     this dark palette. */
  --band-light-green: #6fcf78;

  /* Tints, for the fill behind a chip/tile whose text or border takes the
     solid hue above. Alpha varies by hue, not by accident: the darker the
     colour the more of it is needed before the tint reads at all. */
  --band-dark-green-bg:  rgba(31, 140, 72,  0.15);
  --band-green-bg:       rgba(63, 185, 80,  0.12);
  --band-light-blue-bg:  rgba(88, 166, 255, 0.14);
  --band-gold-bg:        rgba(255, 200, 61, 0.16);
  --band-grey-bg:        rgba(110, 118, 129, 0.10);
  --band-amber-bg:       rgba(210, 153, 34, 0.12);
  --band-yellow-bg:      rgba(227, 179, 65, 0.13);
  --band-orange-bg:      rgba(240, 136, 62, 0.13);
  --band-red-bg:         rgba(248, 81,  73, 0.12);
  --band-dark-red-bg:    rgba(182, 35,  36, 0.20);
  /* Opaque, unlike every other fill here: a tint of black over a dark surface
     is just a slightly darker surface, and the point of this one is that it
     is not a surface at all. */
  --band-black-bg:       #0c0c0c;
  --band-light-green-bg: rgba(111, 207, 120, 0.13);

  /* --- Band colours: SEMANTICS -------------------------------------------
     What a rating MEANS, one definition used everywhere (CONVENTIONS.md
     §5.2). Seven tiers, the whole app (config.js BANDS_V2):

       80+     excellent   gold        65-79  great    green
       57-64   good        light blue  44-56  neutral  grey
       36-43   tough       yellow      21-35  brutal   red
       0-20    extreme     black chrome, dark red ink

     These are re-pointable: a surface that needs a tier in a different hue
     overrides the SEMANTIC token in its own scope rather than writing a rule
     per component. That is only possible because every value here reads from
     the primitive layer above, which no scope overrides. Anything that borrows
     a band colour for something that is NOT a rating must read a primitive
     instead, or it silently changes meaning with the scale. */
  --band-great:   var(--band-green);
  /* A light blue, not the deep #1f6feb this tier started on: that blue read
     as the heaviest, darkest step in a scale where 'good' is meant to be the
     second-best, and it was the one hue that had to be looked for rather than
     seen. Lifting it stays clear of the green above (hue 212 against 132,
     which separates at 14px on the Full Season ribbon, where two adjacent
     greens did not). The ranker's rank-relative chip followed it off the deep
     blue for a different reason — see .score-chip--rank-light-green — reading
     the same PRIMITIVE rather than this semantic, so the two axes stay free
     to move apart while the app still has exactly one blue. --band-blue keeps
     the league table's Champions zone via --band-deep-blue, which never meant
     a rating. */
  --band-good:    var(--band-light-blue);
  --band-neutral: var(--band-grey);
  --band-tough:   var(--band-yellow);
  /* Red, not orange. The two bottom tiers are the ones a reader acts on
     fastest, and orange-then-dark-red asked them to rank two warm tints of
     similar weight; red-then-black is a step change, and it puts the app's
     ordinary "bad" colour on the ordinary bad band. --band-orange is
     untouched and still carries its non-rating jobs (the Europa zone, the
     Triple Captain rail, the armband delta), which is exactly what the
     primitive/semantic split is for. */
  --band-brutal:  var(--band-red);

  --band-great-bg:   var(--band-green-bg);
  --band-good-bg:    var(--band-light-blue-bg);
  --band-neutral-bg: var(--band-grey-bg);
  --band-tough-bg:   var(--band-yellow-bg);
  --band-brutal-bg:  var(--band-red-bg);

  /* The two tiers the seven-tier scale added at the ends. Gold is deliberately
     outside the green family: "exceptional" is not "one tick greener than
     great", and at 14px on the Full Season ribbon a fourth green would simply
     lose to the third. Checked against --band-yellow beside it — measurably
     brighter and more saturated, so the two never blur. */
  --band-excellent:       var(--band-gold);
  --band-excellent-bg:    var(--band-gold-bg);
  /* The top tier is the one place the scale splits chrome from ink. Gold on
     gold is the lowest-contrast text on the page — the tint that makes the
     tier unmistakable at a glance is the same thing that dims the number
     inside it, and the number is what is actually being read. So the border,
     fill and glow stay gold and the digits go silver, lit by their own glow so
     they read as part of the same lamp rather than as plain white text
     dropped on top. No other tier needs this: none of the other six put their
     text on a tint of its own colour at this weight. */
  --band-excellent-ink: var(--band-silver);
  /* The bottom tier splits fill from ink for the same reason the top one
     does, and mirrors its shape: a fill that names the tier at a glance and
     an ink that is not the fill. Where gold is a lamp, this is a void — the
     fill goes black and the digits are the darkest red in the palette, with
     the border drawn in that same dark red so the black reads as bounded
     rather than as a hole in the card. That border is the mirror of the one
     gold carries where the middle five tiers have none. No glow: the top tier
     glows because it is the thing to look for, and the bottom tier is not.
     Dark red on black is a deliberate ~3:1 read — it is the one tier meant to
     look like somewhere you do not want to be.

     --band-extreme is now black, so it is the fill and nothing else. A surface
     that paints a bare band-coloured mark with no fill behind it — a bar, a
     card's accent stripe — must read the INK instead, or it paints black on
     near-black and shows nothing. */
  --band-extreme:      var(--band-black);
  --band-extreme-bg:   var(--band-black-bg);
  --band-extreme-ink:  var(--band-dark-red);

  /* --- Non-rating band colours -------------------------------------------
     Held to the --band-… prefix per CONVENTIONS.md §5.3 rather than opening a
     new one, but these are NOT points on the 0-100 scale and must not be
     re-pointed with it. --band-light-green above is the rank-relative
     top-20%-percentile tier (FEATURE_ENGINE.md §13); the two below are the
     league table's Champions and Europa zones (Conference takes the primitive
     --band-green directly, so the table carries one green instead of three
     meaning nothing in particular). --band-elite lived here too — the Full
     Season strip's gold — and is gone: the seven-tier scale gave that gold a
     band of its own, so the strip reads --band-excellent like everything else
     and the alias had no consumers left. */
  --band-deep-blue: var(--band-blue);

  /* --- Spacing scale (4-point grid) -------------------------------------- */
  --space-1:  4px;
  --space-2:  8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  /* Rungs 5, 7 and the 40px+ page-scale steps were absent because nothing in
     the app shell needed them — the landing page does (section padding, hero
     cluster offset, card padding). Same 4-point grid, no new system. */
  --space-5:  20px;
  --space-7:  28px;
  --space-10: 40px;
  --space-20: 80px;
  --space-24: 96px;

  /* --- Typography -------------------------------------------------------- */
  --font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'Cascadia Code', 'Fira Code', Consolas, monospace;
  /* Display face for the landing hero headline, and nothing else. The app
     proper is system-fonts-only by design; this is the single deliberate
     exception, loaded from Google Fonts in index.html. Anton ships one weight
     (400) and is already heavy — never stack a font-weight on top of it, or
     the browser synthesises a bold and the letterforms smear. Falls back to
     --font-sans's stack if the request fails. */
  --font-display: 'Anton', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-size-xs:  0.75rem;
  --font-size-sm:  0.875rem;
  --font-size-md:  1rem;
  --font-size-lg:  1.25rem;
  --font-size-xl:  1.5rem;
  --font-size-2xl: 2rem;
  --font-size-3xl: 2.25rem;
  /* Landing hero only. Fluid rather than a fixed rung because it is the one
     piece of type on the site that has to span phone to ultrawide. Set larger
     than the sans figure it replaced: Anton is a condensed face, so the same
     nominal size reads noticeably smaller across a line. */
  --font-size-hero: clamp(3rem, 7vw, 5.5rem);

  /* --- Border radius ----------------------------------------------------- */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  /* Capsule. Already used as a raw 999px literal by the planner's mini
     projection bars and several badges; named here so new code stops
     re-typing it. */
  --radius-pill: 999px;

  /* --- Layout metrics ---------------------------------------------------- */
  /* Height of the sticky app nav. Was a 52px literal in three places — the nav
     itself, its items, and the offset the matchup navigators stick below it.
     Named because a fourth consumer now needs it as an arithmetic input: the
     team navigator's list is capped at the viewport height MINUS this, so the
     whole panel stays on screen and the list scrolls inside it. Three literals
     that must agree is a convention; four, one of which is doing sums with the
     other three, is a bug waiting to happen. */
  --app-header-height: 52px;

  /* --- Elevation --------------------------------------------------------- */
  /* First --shadow-* tokens in the system. Two raw drop-shadow recipes
     already exist inline (.dash-search-results, .squad-import-panel); those
     are left alone deliberately — retrofitting them is a separate change
     with its own visual review. See CONVENTIONS.md §5.3. */
  --shadow-float:      0 16px 40px rgba(0, 0, 0, 0.45);
  --shadow-float-soft: 0 16px 40px rgba(0, 0, 0, 0.40);
  --shadow-raised:     0 24px 60px rgba(0, 0, 0, 0.50);
  --shadow-accent:     0 16px 40px rgba(88, 166, 255, 0.35);

  /* --- Estimated / provisional score tokens -------------------------------- */
  /* Used everywhere a score's confidence is below CONFIDENCE_FLOOR.          */
  --color-estimated:        #7a8390;   /* muted, slightly desaturated neutral */
  --estimated-border-style: dashed;    /* applied as border-style for estimated indicators */

  /* --- Skeleton placeholders --------------------------------------------- */
  /* Shown in place of any value that is still being computed — most of all a
     CompositeScore whose counter-matchup component is waiting on an Understat
     team payload. Deliberately DARKER than --color-surface-raised: a skeleton
     has to read as an absence, so it recedes rather than competing with the
     real chips and pills beside it. The highlight is the shimmer's crest and
     the only part that rises above the surrounding surface. */
  --color-skeleton:           #1b2027;
  --color-skeleton-highlight: #2b323b;
  --skeleton-shimmer-duration: 1500ms;

  /* --- Position badge colours (ranker, dashboard, planner) --------------- */
  --pos-gkp: #f0c040;   /* golden yellow */
  --pos-def: #58a6ff;   /* sky blue  */
  --pos-mid: #a371f7;   /* purple    */
  --pos-fwd: #ff9f5b;   /* orange    */
}


body {
  font-family: var(--font-sans);
  font-size: var(--font-size-md);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.5;
}
