/* ==========================================================================
   Blokes vs Bookies — design tokens.

   Source of truth: the website design handoff (../../design-handoff/), whose
   README is the spec and wins over anything else. Two themes, and only two:

     [data-theme="light"]  electric blue #2438F5 on white  — CANONICAL
     [data-theme="cyan"]   cyan #00E5FF on near-black      — dark mode

   Light is the default and is deliberately NOT derived from
   prefers-color-scheme: the locked brand palette does not change because of
   the viewer's OS. Dark is opt-in, persisted under localStorage "bvb-theme".

   The apple-green "Identity v1" and the earlier tech variant are RETIRED.
   Do not reintroduce either or surface them as options.

   Every colour is consumed through a ROLE (--ground, --raised, --accent,
   --bone …). Nothing in site.css or a page may hardcode a colour, size or
   radius — which is what makes one attribute swap the whole site.
   ========================================================================== */

/* --- Fonts: bundled woff2, never a CDN ---------------------------------
   Two families, no exceptions. Oswald ships as the family "BvB Oswald" so a
   system Oswald can never silently substitute for it.                     */
@font-face { font-family: "BvB Oswald"; src: url("../fonts/oswald.woff2") format("woff2"); font-weight: 500 700; font-display: swap; }
@font-face { font-family: "Space Grotesk"; src: url("../fonts/space-grotesk-300.woff2") format("woff2"); font-weight: 300; font-display: swap; }
@font-face { font-family: "Space Grotesk"; src: url("../fonts/space-grotesk-400.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Space Grotesk"; src: url("../fonts/space-grotesk-500.woff2") format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "Space Grotesk"; src: url("../fonts/space-grotesk-600.woff2") format("woff2"); font-weight: 600; font-display: swap; }
@font-face { font-family: "Space Grotesk"; src: url("../fonts/space-grotesk-700.woff2") format("woff2"); font-weight: 700; font-display: swap; }

/* ==========================================================================
   BASE ROLE LAYER — not a selectable theme.
   Role scaffolding every theme scope builds on. These values only show
   through if a scope forgets to override something.
   ========================================================================== */

:root {
  /* --- Type ------------------------------------------------------------- */
  --display: "BvB Oswald", "Arial Narrow", sans-serif;
  --body:    "Space Grotesk", system-ui, sans-serif;
  /* Legacy aliases: page markup and site.css still speak these names. */
  --font-heading: var(--display);
  --font-body:    var(--body);
  --font-weight-bold: 700;

  /* Display sizes are the spec's clamps — fluid, so there is no breakpoint
     step to keep in sync. */
  --text-h1: clamp(44px, 4.8vw, 70px);  --text-h1-lh: 0.92; --text-h1-ls: -0.015em;
  --text-h2: clamp(34px, 3.5vw, 52px);  --text-h2-lh: 0.92; --text-h2-ls: -0.015em;
  --text-h3: clamp(27px, 2.5vw, 37px);  --text-h3-lh: 0.92; --text-h3-ls: -0.015em;
  --text-h4: 27px;                      --text-h4-lh: 0.92; --text-h4-ls: -0.015em;
  --text-h5: 22px;                      --text-h5-lh: 0.92; --text-h5-ls: -0.015em;
  --text-h6: 19px;                      --text-h6-lh: 0.92; --text-h6-ls: -0.015em;

  /* Display scale, used once — the home hero. The h1 clamp tops out at 70px,
     which is a headline size; this is a poster size. It is deliberately not a
     new step on the type scale, because a second thing set this big would stop
     it being the loudest thing on the site.

     Sized against viewport HEIGHT as well as width. A vw-only clamp looks
     right on a wide monitor and then pushes the climb off the bottom of a
     laptop screen — and the whole composition depends on the horizon being in
     the opening frame, so whichever dimension is scarcer wins.

     The outer max() is a floor. min() alone has no lower bound, so a very
     short window drives the headline toward zero; the floor keeps it a
     headline no matter what.                                               */
  --text-hero:    max(42px, min(9.5vw, 12.5vh, 160px));
  --text-hero-lh: 0.84;
  --text-hero-ls: -0.035em;

  --text-large:   18px;
  --text-medium:  16px;
  --text-regular: 14.5px;
  --text-small:   13.5px;
  --text-tiny:    12.5px;
  --text-lh:      1.5;
  --lede-size:    18px;
  --lede-lh:      1.58;

  /* --- Shape -------------------------------------------------------------
     Pills at 100px; everything else square. There is not a single box-shadow
     in this system — depth is the ground -> raised colour step plus 1px
     hairlines. --panel-shadow survives as `none` so any straggler that still
     reads it stays flat.                                                   */
  --radius-button: 100px;
  --radius-badge:  100px;
  --radius-card:   0;
  --radius-image:  0;
  --radius-form:   12px;
  --radius-check:  4px;

  --card-border-width:  1px;
  --card-divider-width: 1px;
  --panel-shadow: none;

  /* --- Spacing & layout --------------------------------------------------- */
  --section-px: clamp(20px, 5vw, 64px);
  --section-py: 56px;
  --section-py-tight: 40px;
  --nav-h: 76px;
  --footer-h: 70px;

  --container-sm:  30rem;
  --container-md:  35rem;
  --container-lg:  48rem;
  --container-xl:  64rem;
  --container-xxl: 1240px;

  /* --- Motion --------------------------------------------------------------
     Restrained and mechanical. No bounces, no springs, no overshoot — an
     ease-out never passes its target and comes back. Still no scroll reveals:
     one was built on a scroll-driven timeline and reverted because it renders
     the course hub blank (the reasoning is kept in site.css, under MOTION).

     Motion may only ever change how something ARRIVES. Nothing in this system
     is allowed to decide WHETHER content is visible.                        */
  --dur-fast: 200ms;
  --dur-accordion: 300ms;
  --dur-tabs: 600ms;
  --dur-page: 260ms;              /* route + theme cross-fade */
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);  /* decisive, no overshoot */
  --drift: 48s;
  --pulse: 2.6s;

  /* The hero opening is the one place this system takes its time, so its
     tempo is tunable from here rather than buried in delays. The shape is:
     the room comes up first and slowest, a beat is held, then each line
     arrives on its own count. Scale these together to speed the whole
     opening up or slow it down without changing its rhythm.

     `--ease-hold` starts almost stationary. It is what lets the climb plot
     itself late WITHOUT an animation-delay — a delay would need a backwards
     fill to avoid flashing the finished line first, and a backwards fill is
     what leaves the chart blank if the animation is scheduled but never
     ticks. Easing buys the same late start with none of that risk.        */
  --dur-room:       2600ms;   /* the market field behind the hero */
  --enter-hold:      420ms;   /* held beat before the first line lands */
  --dur-enter:       950ms;   /* one element's wipe */
  --dur-enter-line: 1200ms;   /* a headline line, which travels further */
  --dur-draw:       2200ms;   /* the climb plotting itself */
  --ease-hold: cubic-bezier(0.85, 0, 0.15, 1);

  /* --- Ground (overridden by both themes) --------------------------------- */
  --ink:      #070600;
  --ground:   #0d0b00;
  --raised:   #151309;
  --raised-2: #1d1a0f;
  --feature:  #0f3d0f;
  --wash:     var(--ground);

  --bone: #ede4d0;
  --w60:  rgba(255, 255, 255, 0.60);
  --w40:  rgba(255, 255, 255, 0.40);
  --w20:  rgba(255, 255, 255, 0.20);
  --hair:      rgba(255, 255, 255, 0.14);
  --hair-soft: rgba(255, 255, 255, 0.07);

  --accent:    #2438f5;
  --accent-lt: #1a28c4;
  --accent-dp: #131e94;
  --gold:      #b07d00;

  /* Win / loss on graded results. Never decorative, never a validation
     state, never a CTA. */
  --field-up:   #0f9d4f;
  --field-down: #e0243a;

  /* Signature textures — a 64px vertical hairline rule on every section, and
     the bloom above hero sections. Do not drop them.

     --rule is the horizontal counterpart, deliberately fainter than the
     verticals so the field still reads as a column ruling with a floor under
     it, not as graph paper. --ambient is a slow-drifting wash; --grain is a
     fixed film grain over the whole page. Both are set per theme.          */
  --grid:  repeating-linear-gradient(90deg, rgba(255,255,255,.035) 0 1px, rgba(0,0,0,0) 1px 64px);
  --rule:  repeating-linear-gradient(0deg,  rgba(255,255,255,.018) 0 1px, rgba(0,0,0,0) 1px 64px);
  --bloom: radial-gradient(120% 85% at 50% -15%, rgba(255,255,255,.12), rgba(0,0,0,0) 62%);
  --ambient: radial-gradient(46% 46% at 28% 22%, rgba(255,255,255,.09), rgba(0,0,0,0) 70%);
  --grain-opacity: 0.035;
  --wander: 42s;

  /* One tile of fractal noise, inlined so it costs no request. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Theme: LIGHT — electric blue #2438F5 on white. The canonical identity.

   Every step above the white page carries the blue: the tints are struck
   from #2438F5 rather than from grey, so the stack reads as one family
   instead of "blue accents on a neutral site".
   ========================================================================== */

[data-theme="light"] {
  --ground:   #ffffff;
  --ink:      #eff2ff;   /* nav + footer — noticeably blue, not off-white */
  --raised:   #e9edff;   /* cards */
  --raised-2: #dde3ff;   /* nested / hover */
  --feature:  #2438f5;   /* full-flood blue panel */
  --feature-text: #ffffff;
  --wash:     #f5f7ff;   /* alternating section ground */

  /* Ink — role-inverted. --bone is the primary text colour in this scope. */
  --bone: #0e1330;
  --w60:  rgba(14, 19, 48, 0.66);
  --w40:  rgba(14, 19, 48, 0.46);
  --w20:  rgba(14, 19, 48, 0.22);

  /* --accent-lt DARKENS here: on a light ground the hover state has to gain
     weight, not lose it. The dark theme inverts this. */
  --accent:    #2438f5;
  --accent-lt: #1a28c4;
  --accent-dp: #131e94;
  --gold:      #b07d00;

  /* Market field — sized for white, so both hold their own on the page
     without going fluorescent. */
  --field-up:   #0f9d4f;
  --field-down: #e0243a;

  /* Blue hairlines on white read better than grey. */
  --hair:      rgba(36, 56, 245, 0.30);
  --hair-soft: rgba(36, 56, 245, 0.14);

  --grid:  repeating-linear-gradient(90deg, rgba(36,56,245,.075) 0 1px, rgba(0,0,0,0) 1px 64px);
  /* A third of the vertical alpha, not half. A blue hairline on white carries
     much further than a cyan one on near-black, and at parity the two sets
     resolve into graph paper — which is a different, busier idea than the
     column ruling this is meant to be. */
  --rule:  repeating-linear-gradient(0deg,  rgba(36,56,245,.022) 0 1px, rgba(0,0,0,0) 1px 64px);
  --bloom: radial-gradient(120% 85% at 50% -15%, rgba(36,56,245,.22), rgba(0,0,0,0) 64%);
  /* Lighter touch on white: the same alpha that reads as atmosphere on a dark
     ground reads as a smudge on a white one. */
  --ambient: radial-gradient(46% 46% at 28% 22%, rgba(36,56,245,.07), rgba(0,0,0,0) 70%);
  --grain-opacity: 0.022;
}

/* ==========================================================================
   Theme: CYAN — the dark mode.
   ========================================================================== */

[data-theme="cyan"] {
  --ground:   #070d16;
  --ink:      #03060b;
  --raised:   #0f1826;
  --raised-2: #16233a;
  --feature:  #062b38;
  --wash:     var(--ground);

  --bone: #e6eef2;
  --w60:  rgba(255, 255, 255, 0.60);
  --w40:  rgba(255, 255, 255, 0.40);
  --w20:  rgba(255, 255, 255, 0.20);

  /* Hover LIGHTENS on dark. --accent-dp has no dark value in the spec, so it
     tracks the hover shade rather than inventing a pressed colour. */
  --accent:    #00e5ff;
  --accent-lt: #5cf3ff;
  --accent-dp: #5cf3ff;
  --gold:      #ffd700;

  --field-up:   #2fe08a;
  --field-down: #ff5566;

  --hair:      rgba(0, 229, 255, 0.16);
  --hair-soft: rgba(0, 229, 255, 0.07);

  --grid:  repeating-linear-gradient(90deg, rgba(0,229,255,.045) 0 1px, rgba(0,0,0,0) 1px 64px);
  --rule:  repeating-linear-gradient(0deg,  rgba(0,229,255,.022) 0 1px, rgba(0,0,0,0) 1px 64px);
  --bloom: radial-gradient(120% 85% at 50% -15%, rgba(0,229,255,.18), rgba(0,0,0,0) 62%);
  --ambient: radial-gradient(46% 46% at 28% 22%, rgba(0,229,255,.11), rgba(0,0,0,0) 70%);
  --grain-opacity: 0.040;
}

/* ==========================================================================
   Legacy aliases.

   The page markup, the JS renderers and the older half of site.css still
   speak the previous token names. They are re-pointed at roles here rather
   than chased through eleven pages — and because they are aliases, a theme
   swap carries them too. New work uses the roles above.
   ========================================================================== */

:root {
  --color-white:      var(--bone);
  --color-white-5:    var(--hair-soft);
  --color-white-8:    var(--hair-soft);
  --color-white-10:   var(--hair-soft);
  --color-white-14:   var(--hair);
  --color-white-20:   var(--hair);
  --color-white-30:   var(--w20);
  --color-white-40:   var(--w40);
  --color-white-60:   var(--w60);
  --color-neutral-darkest: var(--ground);
  --color-ink:        var(--ink);
  --color-ink-raised: var(--raised);

  --color-accent:       var(--accent);
  --color-accent-light: var(--accent-lt);
  --color-accent-text:  var(--feature-text, var(--ground));
  --color-good: var(--field-up);
  --color-bad:  var(--field-down);
  --color-warn: var(--gold);

  --color-scheme-background: var(--ground);
  --color-scheme-foreground: var(--raised);
  --color-scheme-text:       var(--bone);
  --color-scheme-border:     var(--hair);
  --color-scheme-accent:     var(--accent);
  --color-scheme-btn-text:   var(--feature-text, var(--ground));

  --texture-grid: var(--grid);
  --glow-top:     var(--bloom);
  --panel-fill:   none;
  --row-fill:     none;
}
