/* ESCATOYS — design tokens.
 *
 * ONE SYSTEM, TWO GROUNDS.
 *
 * Light is a spec sheet: white, with the graphite of the dark theme returning
 * as the Safety plane and the footer, so the two modes quote each other
 * instead of being two brands.
 *
 * Dark is the equipment powered on: graphite housing, backlit panel legends,
 * recessed bays. It is what makes four empty image slots read as component
 * bays rather than as missing pictures — the reason it earns its place while
 * there is still no photography.
 *
 * Both accents sit on one brand hue, 27 degrees, at the extreme of chroma
 * each ground still permits: the light one is the most saturated value that
 * holds 4.5:1 on the alternating section, the dark one the least bright that
 * holds 6:1. Same colour, two grounds — not amber against red.
 *
 * Platform keys hold their hue across both modes and shift only in lightness,
 * so a given product keeps its hue in either theme.
 *
 * Three states, deliberately: no attribute means follow the operating system,
 * data-mode overrides it in either direction.
 */

/* --- Webfonts ---------------------------------------------------------------
 *
 * Self-hosted on purpose: a Google Fonts request would send the visitor's IP
 * to a third party and take the cookie-banner-free premise with it. IBM Plex
 * Sans and IBM Plex Mono are SIL OFL 1.1; the licence text sits beside the
 * files in static/fonts/, which is what that licence asks for in return.
 *
 * Instrument Sans is the intended display face and its file is not in the
 * repository yet, so its @font-face below is commented out. It has to be:
 * WhiteNoise builds a manifest of every asset a stylesheet references, and a
 * live rule pointing at a missing file makes collectstatic fail — which means
 * the Docker image would not build at all. Until the file lands, --font-display
 * simply falls through to IBM Plex Sans, which is what the page renders in.
 *
 * To enable it: download the 600 weight, put it at
 * static/fonts/instrument-sans-600.woff2, uncomment the block below, and add
 * the preload link in base.html. Three lines, no other change.
 *   curl -sS -A "Mozilla/5.0" \
 *     "https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@600" \
 *   then fetch the woff2 URL it prints.
 *
 * Only the faces the page actually uses are declared. Carrying unused weights
 * costs bandwidth for glyphs nothing renders.
 */

/* The @font-face rule for Instrument Sans deliberately does NOT live here yet.
   WhiteNoise's manifest scans every stylesheet for asset references — comments
   included, since the scan is a regular expression and not a CSS parser — and
   a reference to a file that is absent makes collectstatic fail, which stops
   the Docker image from building at all.

   README.md carries the exact rule to paste in, together with the download
   step and the matching preload for base.html. Until then --font-display falls
   through to IBM Plex Sans and the page is complete as it stands. */

@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-400.5aaadb685d3c.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-600.51d76d33ef85.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibm-plex-mono-400.b51685c998a0.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   DARK — the default when the OS says nothing.

   Contrast ratios (WCAG AA, measured against the section ground):
     --ink on --surface          #EDEEEC / #16181A   ≈ 17.2:1
     --ink-muted on --surface    #9BA0A2 / #16181A   ≈  5.2:1
     --accent on --surface       #FF7504 / #16181A   ≈  6.3:1
     --accent on --surface-alt   #FF7504 / #1E2124   ≈  6.0:1
   ========================================================================== */
:root {
  --surface:       #16181A;
  --surface-alt:   #1E2124;
  --surface-inset: #0F1113;
  --surface-dark:  #0B0D0E;
  --footer-bg:     #08090A;
  --header-bg:     rgba(22, 24, 26, 0.90);
  --ink:           #EDEEEC;
  --ink-muted:     #9BA0A2;
  /* ink-inverse uses the same near-white as ink because it appears on the
     graphite Safety plane in both themes — the plane's colour is --surface-dark
     (#0B0D0E / #16181A), not the main surface, so we need full contrast. */
  --ink-inverse:       #EDEEEC;
  --ink-inverse-muted: rgba(237, 238, 236, 0.72);
  --accent:        #FF7504;
  --accent-deep:   #FFA962;  /* hover state on accent-coloured elements */
  --accent-bright: #FFA962;  /* focus rings on dark/footer surfaces */
  --cta-fg:        #16181A;
  --rule:          rgba(237, 238, 236, 0.12);
  --rule-strong:   rgba(237, 238, 236, 0.24);
  --rule-inverse:  rgba(237, 238, 236, 0.14);
  --slot-ghost:    rgba(255, 117, 4, 0.16);
  /* Key hues. Four verified colours, named for the hue rather than for a
     product: the products they mark have been renamed once already, and a
     token called after a model index goes stale the moment the range moves.
     Only lightness shifts between themes, so a product keeps its colour. */
  --key-flame: #EC6543;
  --key-sky: #4291EC;
  --key-amber: #B98712;
  --key-teal: #119EAD;
  --key-indigo: #9F77FC;
}

/* ==========================================================================
   LIGHT — when the OS asks for it and the visitor has not overridden.

   Contrast ratios:
     --ink on --surface          #101418 / #FFFFFF   ≈ 19.6:1
     --ink-muted on --surface    #565E66 / #FFFFFF   ≈  7.5:1
     --accent on --surface       #AC5209 / #FFFFFF   ≈  4.8:1
     --accent on --surface-alt   #AC5209 / #F1F2F3   ≈  4.6:1
   ========================================================================== */
@media (prefers-color-scheme: light) {
  :root:not([data-mode="dark"]) {
    --surface:       #FFFFFF;
    --surface-alt:   #F1F2F3;
    --surface-inset: #FFFFFF;
    --surface-dark:  #16181A;
    --footer-bg:     #0B0D0E;
    --header-bg:     rgba(255, 255, 255, 0.92);
    --ink:           #101418;
    --ink-muted:     #565E66;
    --ink-inverse:       #EDEEEC;
    --ink-inverse-muted: rgba(237, 238, 236, 0.72);
    --accent:        #AC5209;
    --accent-deep:   #823E07;
    /* accent-bright is the value that still clears 3:1 on the graphite Safety
       plane (#16181A), where the light-mode accent #AC5209 disappears. */
    --accent-bright: #C45800;
    --cta-fg:        #FFFFFF;
    --rule:          rgba(16, 20, 24, 0.10);
    --rule-strong:   rgba(16, 20, 24, 0.20);
    --rule-inverse:  rgba(237, 238, 236, 0.14);
    --slot-ghost:    rgba(16, 20, 24, 0.10);
    --key-flame: #F04217;
    --key-sky: #2081F1;
    --key-amber: #AA7A0B;
    --key-teal: #0A909F;
    --key-indigo: #9265FC;
  }
}

/* LIGHT — chosen explicitly. Wins over any OS preference. */
:root[data-mode="light"] {
  --surface:       #FFFFFF;
  --surface-alt:   #F1F2F3;
  --surface-inset: #FFFFFF;
  --surface-dark:  #16181A;
  --footer-bg:     #0B0D0E;
  --header-bg:     rgba(255, 255, 255, 0.92);
  --ink:           #101418;
  --ink-muted:     #565E66;
  --ink-inverse:       #EDEEEC;
  --ink-inverse-muted: rgba(237, 238, 236, 0.72);
  --accent:        #AC5209;
  --accent-deep:   #823E07;
  --accent-bright: #C45800;
  --cta-fg:        #FFFFFF;
  --rule:          rgba(16, 20, 24, 0.10);
  --rule-strong:   rgba(16, 20, 24, 0.20);
  --rule-inverse:  rgba(237, 238, 236, 0.14);
  --slot-ghost:    rgba(16, 20, 24, 0.10);
  --key-flame: #F04217;
  --key-sky: #2081F1;
  --key-amber: #AA7A0B;
  --key-teal: #0A909F;
  --key-indigo: #9265FC;
}

/* DARK — chosen explicitly. Beats the light media query when the visitor has
   toggled dark on an OS set to light. The :not([data-mode="dark"]) guard on the
   media query above already blocks the bleed, but repeating the values here
   makes the explicit choice explicit in the source too. */
:root[data-mode="dark"] {
  --surface:       #16181A;
  --surface-alt:   #1E2124;
  --surface-inset: #0F1113;
  --surface-dark:  #0B0D0E;
  --footer-bg:     #08090A;
  --header-bg:     rgba(22, 24, 26, 0.90);
  --ink:           #EDEEEC;
  --ink-muted:     #9BA0A2;
  --ink-inverse:       #EDEEEC;
  --ink-inverse-muted: rgba(237, 238, 236, 0.72);
  --accent:        #FF7504;
  --accent-deep:   #FFA962;
  --accent-bright: #FFA962;
  --cta-fg:        #16181A;
  --rule:          rgba(237, 238, 236, 0.12);
  --rule-strong:   rgba(237, 238, 236, 0.24);
  --rule-inverse:  rgba(237, 238, 236, 0.14);
  --slot-ghost:    rgba(255, 117, 4, 0.16);
  --key-flame: #EC6543;
  --key-sky: #4291EC;
  --key-amber: #B98712;
  --key-teal: #119EAD;
  --key-indigo: #9F77FC;
}

/* --- Platform key ----------------------------------------------------------
 *
 * --key is a per-element computed token. Set it on every element that carries
 * a data-model attribute — product cards, hero chips and the hero figure alike.
 * The slot ::before and the hero progress span read it.
 *
 * One table, not two. The hero figure used to key off its own data-active
 * attribute and had its own enumeration further down, which drifted the moment
 * the catalogue changed: it still listed a product that had been removed and
 * had never gained one that was added.
 *
 * Only an element that codes a product or a category sets --key; everything else leaves it
 * transparent so the bar never appears on unkeyed elements.
 */
[data-model="cr1"],
[data-model="df1"] { --key: var(--key-flame, transparent); }
[data-model="pl1"] { --key: var(--key-sky, transparent); }
[data-model="bt1"] { --key: var(--key-teal, transparent); }

/* The range grew past the original four, and the four hues were the only ones
   whose contrast was actually measured against both grounds. Rather than mint
   new colours nobody has verified, the later products borrow a verified hue:
   the drones take the air colour, everything with a wheel under it takes the
   ground colour. Powered mobility is the exception and has its own. When a
   photographer and a designer settle the expanded palette, these mappings are
   the single place it changes. */
[data-model="mc1"],
[data-model="cm1"],
[data-model="fp1"],
[data-model="lr1"] { --key: var(--key-sky, transparent); }

/* Powered mobility gets its own hue rather than borrowing one. It is the fifth
   category and the only one whose products share a page with nothing else, so
   a reused colour would read as a filing error. The value was solved to sit in
   the same contrast band as the other four, not picked by eye. */
[data-model="pw1"],
[data-model="pw2"] { --key: var(--key-indigo, transparent); }

[data-model="ks1"],
[data-model="sc1"],
[data-model="eb1"],
[data-model="uc1"],
[data-model="bd1"] { --key: var(--key-amber, transparent); }

/* Category-level keys, used by the hub entries and the page headers. The two
   service pages are not product categories and take the brand accent instead
   of a product hue — they are not a fourth thing to buy. */
[data-category="rc"]        { --key: var(--key-flame, transparent); }
[data-category="drones"]    { --key: var(--key-sky, transparent); }
[data-category="rides"]     { --key: var(--key-amber, transparent); }
[data-category="big-kids"]  { --key: var(--key-teal, transparent); }
[data-category="mobility"]  { --key: var(--key-indigo, transparent); }
[data-category="training"]  { --key: var(--accent, transparent); }

/* The hero figure needs no rules of its own: it carries data-model like every
   other keyed element, so the table above already covers whatever the rotation
   lands on. Do not reintroduce a per-key list here. */

/* --- Structural tokens -----------------------------------------------------
 *
 * These do not change between themes — they are geometry, not colour.
 */
:root {
  /* Fallback for any element outside a [data-model] context. */
  --key: transparent;

  /* Font stacks. Instrument Sans is declared above but its file is absent
     until the owner drops it in; IBM Plex Sans is the immediate fallback. */
  --font-display: "Instrument Sans", "IBM Plex Sans", system-ui, sans-serif;
  --font-body: "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --font-data: "IBM Plex Mono", ui-monospace, "SF Mono", monospace;

  --measure:   1240px;
  --gutter:    clamp(1.25rem, 5vw, 3.5rem);
  --section-y: clamp(4.5rem, 9vw, 8.5rem);
  --radius:    2px;

  --t-hover:  160ms;
  --t-reveal: 760ms;
  --ease:     cubic-bezier(0.16, 1, 0.3, 1);
}

/* Silence the timing tokens under reduced motion. The animation properties in
   main.css are clamped to 1ms there too, but zeroing the tokens also silences
   anything that reads them directly (e.g. JS-driven inline transitions). */
@media (prefers-reduced-motion: reduce) {
  :root {
    --t-hover:  0ms;
    --t-reveal: 0ms;
  }
}
