/* Design tokens — lifted from the Figma "HB / homepage" frame (1512px reference width).
   Everything visual (color, radius, shadow, spacing) lives here; typography.css builds
   the type scale on top, global.css / sections.css consume both. */

:root {
  /* Palette — Figma uses hard-coded hexes, no variables; these are the ones that repeat */
  --ink: #141414;          /* headings, primary buttons, body on light */
  --ink-2: #222222;        /* big stat numbers */
  --text: #585858;         /* descriptive body copy */
  /* WCAG 1.4.3 (2026-09): #65666b was 5.73:1 on white but only 3.94:1 on --scene-bg
     (#d4d6dc), and every eyebrow / .small / .caption / team role sits on that ground.
     Darkened by the smallest step that clears 4.5:1 there: 4.52:1 on the scene, 6.57:1
     on white. Do not lighten it back past #5c5d62. */
  --muted: #5c5d62;        /* eyebrows, captions, inactive tabs */
  --line: #acafb7;         /* hairlines, scroll track */
  --bar: #aaacb1;          /* waveform / ring ticks (unplayed) */
  --bar-light: #e3e5eb;
  /* The grey plate an image or a mark stands on before its own picture wipes down over it
     (works tiles, team portraits, the quote portrait, the "what we do" slot) */
  --plate-grey: #d9dade;
  --error: #c9463d;        /* an invalid form field: its rule, its label and its message */
  /* Opaque white curtain behind the closing section. */
  --footer-bg: #ffffff;
  --white: #ffffff;
  /* The ground a cut-out portrait stands on: the scene's own grey, lit from above so the
     head reads against it instead of floating on white */
  --ava-ground: radial-gradient(120% 108% at 50% 112%, #cdd0d8 0%, #dfe1e7 52%, #f1f2f5 100%);

  --scene-bg: #d4d6dc; /* the page ground under the canvas (what shows until the first WebGL frame); scene.background in main.js is #dde0f2, tone-mapped it lands here */
  --scene-webgl: #dde0f2; /* the raw scene.background the composer maps to --scene-bg; the direct (mobile) path uses --scene-bg itself, see main.js */
  --blue: #0055ff;        /* the story's particle blue (dune-story.js pointColor): the office callouts */

  /* Scale unit: 1 Figma px at the 1512 reference width. Sizes that must track the
     mock proportionally are written as calc(N * var(--u)); fixed UI (buttons, pills)
     stays in px. */
  --u: calc(100vw / 1512);
  /* Height unit for the hero (mock frame is 982 tall): on short laptop screens the
     width-based scale alone leaves the 3-line title eating half the viewport. */
  --uh: calc(100vh / 982);

  /* Page gutters — 80px in the mock (hero, testimonials pill), 120px for the wide
     stats/why-us blocks. Full-bleed cards and the footer set their own. */
  --page-x: clamp(24px, calc(80 * var(--u)), 80px);
  --page-x-lg: clamp(32px, calc(120 * var(--u)), 120px);

  /* Radii */
  --r-pill: 999px;
  --wordmark-fs: clamp(64px, calc(255 * var(--u)), 255px); /* footer wordmark; the rule's pull-up is a share of it */
  --sheet-r: 0px;         /* the content sheet's bottom corners, where it rests on the footer */

  /* Shadows */
  --shadow-btn: 0 4px 8px rgba(20, 20, 20, 0.07);
  --shadow-btn-hover: 0 12px 24px rgba(20, 20, 20, 0.13), 0 4px 9px rgba(20, 20, 20, 0.07);
  --shadow-btn-active: 0 5px 12px rgba(20, 20, 20, 0.11), 0 2px 5px rgba(20, 20, 20, 0.06);
  /* White pills on the white sheet (.plate) need more separation than the page default */
  --shadow-plate: 0 10px 24px rgba(20, 20, 20, 0.1), 0 3px 8px rgba(20, 20, 20, 0.06);
  --shadow-plate-hover: 0 16px 32px rgba(20, 20, 20, 0.14), 0 6px 12px rgba(20, 20, 20, 0.08);
  --shadow-plate-active: 0 6px 14px rgba(20, 20, 20, 0.12), 0 2px 6px rgba(20, 20, 20, 0.08);

  /* One hover for every button on the page: it lifts, and its shadow deepens by a step.
     The step is relative -- these three say where a button rests and where it goes, and a
     surface that needs a different pair (the white plate, the drawer's card) redefines
     them for its own subtree. Written as absolute values instead, a hover tuned against
     the page's small resting shadow is no change at all against the plate's large one. */
  --lift-rest: var(--shadow-btn);
  --lift-hover: var(--shadow-btn-hover);
  --lift-active: var(--shadow-btn-active);
  --lift-up: -3px;   /* how far it rises... */
  --lift-down: -1px; /* ...and where it sits while pressed */
  /* Figma's 4-layer float shadow (124px offset / 83px blur) painted a visible band
     over the waveform; a tighter stack reads the same and stays under the pill. */
  --shadow-float:
    0 16px 40px rgba(0, 0, 0, 0.1),
    0 4px 12px rgba(0, 0, 0, 0.06),
    0 1px 3px rgba(0, 0, 0, 0.05);

  /* Display-text fill: a black→transparent sweep over a solid ink layer, so the glyphs
     run #000 at the top-left to #141414 at the bottom-right (very subtle, per mock). */
  --text-gradient:
    linear-gradient(157deg, #000 8.3%, rgba(102, 102, 102, 0) 81.9%),
    linear-gradient(90deg, var(--ink), var(--ink));

  /* Motion — one token per curve the page uses more than once. The keyword easings
     (`ease`, `linear`, `ease-in-out`) stay literal: they are the browser's, not ours.
     Curves used exactly once keep their literal cubic-bezier at the rule that needs it
     (the cursor's spring, the player disc's flip, the odometer roll, the stack mark's
     drift) -- naming a one-off only hides where it belongs.
     No JS file hard-codes these curves: the scripts that animate (dune-story.js,
     presence-story.js, team-flight.js, legacy-hero.js, hand-weave.js) drive their own
     scroll-bound smoothstep / easeOutCubic in numbers, so there is nothing to keep in
     sync here. Motion that must match a CSS curve is written in CSS.
     Reduced motion is NOT handled here: 14 `prefers-reduced-motion` blocks across
     global.css / sections.css / dune-story.css / team-flight.css switch the affected
     rules to `transition: none`, which is stronger than shortening a duration token. */
  --ease-out: cubic-bezier(0.2, 0.75, 0.15, 1);      /* the drawer, the pills, the meters: settles into place */
  --ease-out-soft: cubic-bezier(0.2, 0.7, 0.15, 1);  /* the line masks' rise, and the tracks that follow the scroll */
  --ease-in: cubic-bezier(0.5, 0, 0.75, 0.3);        /* leaving: text pulled up out of its mask */
  --ease-io: cubic-bezier(0.45, 0, 0.25, 1);         /* the long clip-path wipes (a picture arriving over its grey plate) */
  --ease-out-2: cubic-bezier(0.25, 0.8, 0.2, 1);     /* the hero's own exit, and the burger turning into the cross */
  --ease-dip: cubic-bezier(0.3, 0, 0.6, 1);          /* the anticipation dip before the numbers leave */
  --ease-drift: cubic-bezier(0.22, 0.7, 0.15, 1);    /* a case tile's image scaling under the cursor */

  /* Durations — the four the page actually repeats. Anything else (0.34s, 0.45s, 1.6s...)
     is tuned to its own gesture and stays written out: never round a duration to a token. */
  --dur-fast: 0.2s;
  --dur-base: 0.3s;
  --dur-slow: 0.5s;
  --dur-reveal: 0.7s;

  /* Header */
  --header-h: 72px;

  /* z-index ladder */
  --z-canvas: 0;
  /* Above the front canvas (legacy hero, --z-canvas-front: 7): a stray chunk over the
     opaque dark plane reads as a glowing speck, not as depth. */
  --z-footer: 8;
  --z-page: 10;
  --z-header: 100;
  --z-menu: 500;           /* the menu pop-up and its blurred backdrop: over everything but the dev panel */

  /* Hero pin: extra scroll the hero stays on screen while chunks peel off the hand
     (main.js reads it from .hero-stage height, ui.js too) */
  --hero-pin: 160vh; /* 0 when the hand does not disperse (main.js EXIT_MODE 'none', smooth-scroll HERO_DRIVE false) */
  --z-dev: 1000;
}

/* Karaoke fill fraction on why-us words (sections.css) — registered so it transitions */
@property --f {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
