/*
 * Design tokens.
 *
 * Everything atomic lives here and nowhere else. A component file that writes a
 * raw hex or a raw pixel value has found a gap in this file — fill the gap
 * rather than the component. This is not style preference: style.css once
 * carried its own :root with older values, loaded second, and silently won the
 * cascade, so a commit that fixed two measured contrast failures shipped
 * without changing a single rendered colour.
 *
 * ---------------------------------------------------------------------------
 * WHERE THESE CAME FROM
 *
 * Two sources, and they disagreed usefully.
 *
 * The bundled design data (.claude/skills/ui-ux-pro-max) profiles a football
 * club as "Vibrant & Block-based + Motion-Driven, team colours and energetic
 * accents", and a financial dashboard as "Dark Mode (OLED) + Data-Dense, dark
 * ground with red/green alerts". This product is genuinely both: football
 * subject matter, trading-desk density. That is the two registers below.
 *
 * It also names the Dark-OLED palette as #000000, #121212 and #0A0E27 — which
 * is the confirmation, not the instruction. Polymarket is #000, Stake #0F212E,
 * FotMob pure black. A survey of twenty products in this category found every
 * credible one blue-cast or neutral. Being handed the category default in
 * writing is a reason to go somewhere else with the axis, not to take it.
 *
 * So: the data decides the things it is authoritative about — contrast floors,
 * touch targets, motion timing, the density model — and the palette is chosen
 * against it.
 */

:root {
  /* ---------------------------------------------------------------- ground */

  /*
   * NEUTRAL, AND WITH REAL STEPS BETWEEN THE LEVELS.
   *
   * The old ground was warm-cast near-black -- #0c0b09 page, #15130f surface,
   * #201c17 raised -- chosen to differentiate from a category that is all
   * blue-blacks. Two things were wrong with it, and both were visible the
   * moment the page was looked at rather than reasoned about.
   *
   * The steps were about four per cent apart, which is invisible. A row, the
   * page under it and the panel around it were the same colour, so nothing had
   * an edge and everything read as one grey field. Every book with a usable
   * board puts a clear step between page and row: Stake runs #0F212E against
   * #213743, and you can see which is which from across a room.
   *
   * And warm greys on a warm black is how you get mud. The brown cast that was
   * meant to read as sodium and concrete just desaturated everything on top of
   * it. The differentiation is the violet, which is doing that job on its own.
   */
  /* The two clubs' colours on a match page. Set inline per fixture from
     get_fixture's `colors`; transparent anywhere else. */
  --home-c: transparent;
  --away-c: transparent;
  --glow-c: transparent;
  --glow-dy: 0px;
  --pitch:     #0a0a0c;
  --stand:     #16171b;
  --terrace:   #202329;
  --stand-hi:  #2c3038;

  /* ------------------------------------------------------------------- ink */

  /* Brighter, and cool to match the ground. The old warm whites sat down into
     it; these come off it. All three clear 4.5:1 on every surface above. */
  --chalk:     #f4f6fa;
  --chalk-2:   #c3c8d2;
  --chalk-3:   #8d94a3;

  /* ---------------------------------------------------------------- accent */

  /* Violet is still unclaimed in football -- bet365 green, FanDuel blue,
     DraftKings orange, OneFootball lime, Sofascore royal blue. It is now the
     only thing carrying the identity, so it is used as a fill rather than a
     tint wherever something is meant to be pressed. */
  --floodlight:     #7a5af8;
  --floodlight-hi:  #9e86ff;
  --floodlight-dim: rgba(122, 90, 248, 0.16);

  /* A second note, for anything imminent rather than live. */
  --sodium:    #f5a524;

  /* --------------------------------------------------------------- borders */

  /* Percentages of the ink rather than grey hexes, so they hold across every
     surface. The firm one clears 3:1 for anything interactive. */
  --hairline:  rgba(244, 246, 250, 0.09);
  --rule:      rgba(244, 246, 250, 0.16);
  --rule-firm: rgba(244, 246, 250, 0.32);

  /* -------------------------------------------------------------- semantic */

  /* Muted on purpose: these are states, not brand. Saturated green is spent —
     bet365, Betway, Paddy Power and every tipster site own it, so it reads as
     gambling promo. It means won here and nothing else. */
  --won:       #2fbf71;
  --lost:      #f0435a;
  --void:      #7b8596;
  --warn:      #f5a524;

  /* Price movement is a different meaning from a settled result and gets its
     own tokens, even where the colour currently agrees. */
  --shorten:   #2fbf71;
  --drift:     #f0435a;

  /* ------------------------------------------------------------ typography */

  /*
   * BIG SHOULDERS DISPLAY FOR THE SCOREBOARD, GEIST FOR THE UI.
   *
   * Two wrong answers preceded this one and both were wrong the same way.
   * Bricolage Grotesque is an editorial display face, drawn for magazine
   * covers, and it is a reason this site read as editorial. Archivo is a
   * competent workhorse grotesque with no opinion at all -- the safe pick, and
   * on a product that is meant to feel like a Saturday afternoon, safe is the
   * failure mode.
   *
   * Big Shoulders Display was drawn by Patric King for Chicago's public design
   * initiative and is made for signage: extremely tall, extremely narrow,
   * squared terminals, no warmth in it whatsoever. It is the register of a
   * stadium board and a tunnel sign, its numerals are unmistakable at speed,
   * and a column of odds set in it looks like a price board rather than a
   * table. It carries weight 400-800 and no width axis, which it does not need
   * because narrow is what it already is.
   *
   * Geist takes the UI. Inter is the most-defaulted typeface on the web and
   * using it is a decision nobody made; Geist is cleaner in the small sizes
   * this interface mostly lives at and its tabular figures are properly drawn.
   */
  /*
   * The faces are self-hosted (public/fonts, declared at the top of
   * base.css): no third-party request before first paint, and the two that
   * matter are preloaded from the HTML.
   *
   * OFFSIDE FIGURES leads --display-figures. It is Big Shoulders'
   * own digits and price punctuation, respaced so every figure is one width
   * (built once with fontTools; see public/fonts/README.md). Big
   * Shoulders ships proportional figures and no tabular feature at all, so
   * `tabular-nums` on a column of odds set in it did nothing: the "1" is half
   * the width of the "0", and 1.18 over 2.35 never lined up. Stadium boards
   * use equal-width figures for the same reason we need them. Its
   * unicode-range is digits and price punctuation only, so letters in the
   * same element fall through to Big Shoulders itself.
   */
  --display: 'Big Shoulders Display', 'Big Shoulders Fallback', 'Arial Narrow', sans-serif;
  /* The same face with equal-width figures, for numbers that stack in a
     column or tick in place: odds, kick-off times, scores, clocks. A number
     standing alone keeps Big Shoulders' own proportional figures, which
     look better on their own ("11", not "1 1"). */
  --display-figures: 'Offside Figures', 'Big Shoulders Display', 'Big Shoulders Fallback', 'Arial Narrow', sans-serif;
  --body:    Geist, 'Geist Fallback', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /*
   * THE THIRD FACE IS THE BRAND.
   *
   * Caveat, a marker hand: the telestrator, a pundit drawing on the screen.
   * Rationed to the brand's own asides and sign-offs, never a number, a
   * price, a scoreline or a control.
   */
  --hand: Caveat, 'Bradley Hand', 'Segoe Script', cursive;

  /* No width axis on the display face; kept because rules still name them. */
  --wide:      100;
  --condensed: 100;
  --tight:     100;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-bold:   700;
  --weight-black:  800;

  /*
   * THE SCALE.
   *
   * Interface sizes are fixed steps, because a label that grows with the
   * window stops lining up with the control beside it. Reading and display
   * sizes are fluid: each is a clamp() between a phone size and a desk size
   * on a modular ratio, 1.2 at 390px widening to 1.333 at 1440px, so a
   * headline gains presence on a big screen without the body copy doing the
   * same. Big Shoulders is signage type and reads about a third smaller than
   * a grotesque at the same size, which is why the display steps sit high.
   */
  --text-2xs: 0.6875rem;
  --text-xs:  0.75rem;
  --text-sm:  0.8125rem;
  --text-md:  clamp(0.875rem, 0.85rem + 0.1vw, 0.9375rem);
  --text-lg:  clamp(1rem, 0.96rem + 0.15vw, 1.0625rem);
  /* Long-form reading: the analysis, the why, the legal pages. */
  --text-read: clamp(1rem, 0.95rem + 0.22vw, 1.125rem);

  --text-xl:  clamp(1.5rem, 1.32rem + 0.75vw, 1.875rem);
  --text-2xl: clamp(1.875rem, 1.6rem + 1.15vw, 2.5rem);
  --text-3xl: clamp(2.25rem, 1.8rem + 1.9vw, 3.25rem);
  --text-4xl: clamp(2.75rem, 2.1rem + 2.8vw, 4.25rem);
  /* The matchup on a masthead, and nothing else on the site. */
  --text-hero: clamp(2.5rem, 1.85rem + 2.9vw, 4.25rem);
  /* The scoreboard: a scoreline, total odds, a strike count. */
  --text-board: clamp(3rem, 1.9rem + 4.8vw, 5.75rem);

  /*
   * LEADING, BY JOB.
   *
   * Tall condensed capitals want almost none; interface text wants a little;
   * prose a reader is meant to get through wants a lot, and more on a dark
   * ground, where light type on black blooms and the lines seem closer than
   * they are.
   */
  --leading-display: 0.94;
  --leading-tight:   1.02;
  --leading-snug:    1.25;
  --leading-normal:  1.5;
  --leading-read:    1.65;

  /* The measure. 60 to 70 characters is where a line is easiest to follow. */
  --measure:       66ch;
  --measure-short: 46ch;

  /*
   * TRACKING. Tightens as size grows on the grotesque, which is designed
   * for text sizes; stays near zero on the display face, which is already
   * tight; opens for capitals, which are spaced for sitting next to lower
   * case and crowd each other when set on their own.
   */
  --tracking-hero: -0.005em;
  --tracking-4xl: -0.005em;
  --tracking-3xl: 0;
  --tracking-2xl: 0;
  --tracking-xl:  0.005em;
  --tracking-md:  -0.006em;
  --tracking-sm:  0;
  --tracking-wide: 0.04em;
  --tracking-caps: 0.08em;
  --tracking-num: -0.02em;

  /*
   * FEATURES. Only ones the faces actually have (checked with fontTools):
   * Geist carries kern, liga, tnum, pnum and frac; Big Shoulders kern and
   * liga; Caveat calt, whose contextual alternates are what stop a run of
   * the same letter looking stamped.
   */
  --features-text: 'kern' 1, 'liga' 1, 'calt' 1;
  --features-data: 'kern' 1, 'tnum' 1;

  /* ----------------------------------------------------------------- space */

  --space-1:  4px;
  --space-2:  6px;
  --space-3:  8px;
  --space-4:  12px;
  --space-5:  16px;
  --space-6:  20px;
  --space-7:  24px;
  --space-8:  32px;
  --space-9:  40px;
  --space-10: 48px;
  --space-11: 64px;
  --space-12: 80px;
  --space-13: 96px;

  /*
   * The board's outer columns are fixed rather than content-sized.
   *
   * Each row is its own grid, so an `auto` column resolves per row: "£10
   * returns £11.40" is wider than "£10 returns £11", and that difference
   * pushed the call column a few pixels left or right on every line. A board
   * a reader scans down has to have one geometry, not one per row.
   */
  --col-when:  86px;
  --col-price: 124px;
  /* The right-hand rail: a dense list beside the main column, as the reference
     runs its news down the side of everything. */
  --col-side: 340px;

  --gutter: clamp(16px, 3vw, 32px);
  /* Capped. Full-bleed data is a dashboard smell; Polymarket holds at 1168px
     despite being a data product. */
  --maxw:   1180px;
  --maxw-read: 680px;

  /* ---------------------------------------------------------------- shape */

  /* Three values and no more. A long radius vocabulary is what Bootstrap gave
     everyone and it shows. */
  /*
   * Buttons are rounded rectangles, not pills.
   *
   * Everything on this site was a 999px pill, which is the shape a marketing
   * page uses. The reference reserves the pill for the navigation and for
   * status chips, and gives every actual button an 8px corner. That one change
   * does more to make a page look like a product than any amount of colour.
   */
  --radius-sm: 4px;
  --radius:    8px;
  --radius-lg: 12px;
  /*
   * `--radius-pill` is for things that are actually round -- a crest, a status
   * dot, a progress track. It is NOT for labels. Every tag, chip, badge and
   * navigation item on this site was a 999px lozenge, which is the shape a
   * marketing page uses for a feature list, and thirteen of them on one screen
   * is what "generically styled" looks like. Labels are square now.
   */
  --radius-pill: 999px;

  --border: 1px;

  /* ------------------------------------------------------------ elevation */

  /* An inset ring plus a shallow offset, never a single heavy drop. Identical
     rounded cards each wearing the same soft grey shadow is the SaaS-card tell
     — depth here comes from the 4% surface steps and the hairlines. */
  --ring-inset: inset 0 1px 0 rgba(247, 244, 237, 0.045);
  --elev-1: var(--ring-inset), 0 1px 2px rgba(0, 0, 0, 0.3);
  --elev-2: var(--ring-inset), 0 8px 16px rgba(0, 0, 0, 0.32);
  --elev-3: var(--ring-inset), 0 20px 48px rgba(0, 0, 0, 0.44);

  --focus-ring: 0 0 0 2px var(--pitch), 0 0 0 4px var(--floodlight);

  /* --------------------------------------------------------------- motion */

  /* The data's block-based register specifies 200–300ms for deliberate
     transitions; anything a finger is waiting on stays under 150. */
  --dur-instant: 80ms;
  --dur-fast:    140ms;
  --dur-normal:  220ms;
  --dur-slow:    420ms;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  /* ----------------------------------------------------------------- misc */

  /* 44px, and the data adds the part everyone forgets: adjacent targets need
     8px of clear space between them, not just size of their own. */
  --tap: 44px;
  --tap-gap: var(--space-3);

  /* The sticky header's height, needed in three places that are not the header
     itself: the mobile nav's top edge, scroll-padding for in-page anchors, and
     the sticky filter bar on the board. */
  --header-h: 56px;
  /* The colours a reader can put behind their initials (account page). Eight,
     all with white initials legible on them, none of them green or red, which
     are the site's won and lost. */
  --avatar-c1: #7a5af8;
  --avatar-c2: #1f8f8a;
  --avatar-c3: #c07b1e;
  --avatar-c4: #3a6fd1;
  --avatar-c5: #b0478f;
  --avatar-c6: #5a6474;
  --avatar-c7: #8a5a3c;
  --avatar-c8: #3f4bb0;

  --z-header: 100;
  --z-overlay: 300;
}

/* Numerals everywhere. Tabular figures are the single highest ratio of effort
   to perceived quality in a product full of prices: every digit takes the same
   width, so columns align and a price moving from 1.90 to 2.05 does not shift
   the layout. Non-tabular figures make a live board jitter on every tick. */
html {
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: 'cv01' 1, 'ss03' 1;
}

/* A condensed cut from the display family, for anything that has to survive
   a long club name or a column of prices. */
.condensed {
  font-family: var(--display);
  font-variation-settings: 'wdth' var(--condensed);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 0ms;
    --dur-fast: 0ms;
    --dur-normal: 0ms;
    --dur-slow: 0ms;
  }
}
