/* ============================================================================
   Aptura demo — derived tokens.  Build 6, Phase 2 (Skeleton).  Owner: R2.

   This file adds NOTHING to the brand. It imports the canonical palette and
   type stack from packages/tokens/design-tokens.css and derives only what the
   demo's component layer needs on top: a type scale, a motion scale, a space
   scale, contrast-safe accent variants, and the brand-personalization slots.

   Rules this file is bound by (docs/decisions/0001, 0002, 0003 and
   docs/build-6/design-brief-template.md §9, which is binding, not a template):

   1. No brand hex, no font literal, no periwinkle, no DM Sans, no DM Mono.
      Every value below either is a layout/motion number or resolves through a
      canonical token via var() / color-mix().
   2. THE PROSPECT'S BRAND COLOR NEVER CARRIES TYPE, AT ANY SIZE. It is a
      fill, a rule, a plate, or a ramp. Its hex is user supplied and cannot be
      contrast-checked in advance, so every use here is decorative and never
      the sole carrier of meaning. That is what makes ANY hex safe (AC10).
   3. --text-soft (#48544F) is a LIGHT-surface token and never crosses onto a
      dark surface. Dark surfaces use --text-soft-on-dark.
   4. Signal is never a large fill on Bone. Text on dark is Bone, never white.
   5. Every contrast pair introduced here is computed, not estimated, and is
      stated in a comment beside it.

   DEPLOY NOTE (coordination with F1): the @import below points at the
   canonical file from the repo root, which is correct for local dev served
   from the repo root. The Cloudflare Pages build for apps/demo must either
   (a) copy packages/tokens/design-tokens.css to apps/demo/styles/ and swap
   the import for the sibling path, or (b) inline in this order:
   design-tokens.css -> tokens.css -> components.css.
   Matching apps/landing, which keeps a copy and inlines at build.
   NEVER fork the values into a second file.
   ========================================================================= */

/* Local copy of the canonical token file, matching the apps/landing precedent.
   The repo-root-relative path 404s SILENTLY under an apps/demo-rooted Pages
   deploy, which would ship the whole app unstyled with no error. Resync with
   `npm run sync-tokens` after editing packages/tokens/design-tokens.css; CI
   fails if this copy drifts. DO NOT EDIT design-tokens.css here. */
@import url("./design-tokens.css");

:root {
  /* ==========================================================
     1. TYPE SCALE
     Fraunces display / Inter body / JetBrains Mono for eyebrows,
     labels, counters and step markers ONLY. Hierarchy comes from
     weight and size, never from swapping family. Never body copy
     in mono or serif.
     Sizes are the exploration's 1280x800 frame values, expressed
     as rem with a fluid floor so each beat lands on a small
     laptop without shrinking type (PRD §3).
     ========================================================== */

  /* Display (Fraunces). px targets: 78 / 56 / 38 / 30 / 21 */
  --fs-cover:     clamp(2.25rem, 1.05rem + 5.2vw, 4.875rem);   /*  36 ->  78 */
  --fs-display-1: clamp(2rem,    1.25rem + 3.3vw, 3.5rem);     /*  32 ->  56 */
  --fs-display-2: clamp(1.6rem,  1.24rem + 1.6vw, 2.375rem);   /*  26 ->  38 */
  --fs-display-3: clamp(1.35rem, 1.16rem + 0.8vw, 1.875rem);   /*  22 ->  30 */
  --fs-display-4: clamp(1.15rem, 1.09rem + 0.3vw, 1.3125rem);  /*  18 ->  21 */

  /* Body (Inter). px targets: 17 / 15 / 13 */
  --fs-lead:    clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);      /*  16 ->  17 */
  --fs-body:    0.9375rem;                                     /*  15 */
  --fs-caption: 0.8125rem;                                     /*  13 */

  /* Mono (JetBrains Mono). px targets: 15 / 13 / 11 */
  --fs-mono-lg: 0.9375rem;                                     /*  15 */
  --fs-mono:    0.8125rem;                                     /*  13 */
  --fs-mono-sm: 0.6875rem;                                     /*  11 */

  /* Tracking. Binding rule: -0.028em at 56px+, -0.018em at 30px, 0 below 24px.
     --track-md covers the unspecified 24-29px band by interpolation. */
  --track-xl: -0.028em;   /* >= 56px */
  --track-lg: -0.018em;   /* 30 - 55px */
  --track-md: -0.010em;   /* 24 - 29px, interpolated */
  --track-none: 0;        /* < 24px */
  --track-mono: 0.14em;   /* uppercase mono labels */
  --track-mono-wide: 0.18em; /* eyebrows */

  /* Leading */
  --lh-cover:   1.05;
  --lh-display: 1.14;
  --lh-body:    var(--leading-body);   /* 1.65, canonical */
  --lh-tight:   var(--leading-heading);/* 1.1, canonical */
  --lh-mono:    1.5;

  /* Weight. Fraunces 400 large / 500 mid. Inter 400 body / 600 UI+emphasis.
     Mono 500. Nothing heavier anywhere. */
  --fw-display:      400;
  --fw-display-mid:  500;
  --fw-body:         400;
  --fw-strong:       600;
  --fw-mono:         500;

  /* ==========================================================
     2. SPACE, MEASURE, RADII
     The demo is editorial and square-cornered, matching the
     readout artifact in the explorations. apps/landing uses
     rounded buttons; the demo deliberately does not, because
     these components are the printed member deliverables staged.
     ========================================================== */
  --space-2xs: 0.25rem;
  --space-xs:  0.5rem;
  --space-sm:  0.75rem;
  --space-md:  1.25rem;
  --space-lg:  2rem;
  --space-xl:  3.25rem;
  --space-2xl: 4.5rem;

  --pad-page:  clamp(1.5rem, 4vw, 4.5rem);  /* readout page gutter, 24 -> 72 */
  --measure:   44rem;                        /* body copy max line length */
  --measure-display: 58rem;                  /* cover verdict max width */

  --radius:     0;
  --radius-ring: 2px;   /* focus ring corner only */

  /* ==========================================================
     3. DERIVED, CONTRAST-SAFE COLOR
     Every ratio below is computed against the surface it is used
     on. Requirements: 4.5:1 body text, 3:1 non-text and UI marks
     (WCAG 2.2 AA, 1.4.3 / 1.4.11).
     ========================================================== */

  /* Signal-colored TEXT and value-bearing marks on LIGHT surfaces.
     Canonical --signal-dim (#1FA684) is 2.46:1 on Bone and 2.76:1 on Bone
     Card. It fails 4.5:1 body AND 3:1 non-text. This is the exact failure
     design-brief-template.md §9.4 names, and the sanctioned fix there is
     "darken the light-surface fill". Mixing 55% Signal Dim into Ink yields
     #197460:
       #197460 on --bone      (#E8E6DF) = 4.53:1  PASS body + non-text
       #197460 on --bone-card (#F4F3EE) = 5.10:1  PASS body + non-text
     Use this, never --signal-dim, wherever a signal-colored mark or link
     appears on light. Note that eyebrows on light stay --text-soft per the
     binding rule; this token is for links, underlines and small marks. */
  --signal-on-light: color-mix(in srgb, var(--signal-dim) 55%, var(--ink));

  /* Value-bearing rules, borders and UI marks on LIGHT surfaces.
     Canonical --line (#CBC7BC) is 1.35:1 on Bone / 1.52:1 on Bone Card and is
     DECORATIVE ONLY. Anything a reader must perceive to understand the content
     uses --rule-strong (60% Ink into Line = #5C716A):
       #5C716A on --bone      = 4.18:1  PASS non-text (3:1)
       #5C716A on --bone-card = 4.70:1  PASS non-text (3:1) */
  --rule-strong: color-mix(in srgb, var(--ink) 60%, var(--line));

  /* Value-bearing rules, borders and UI marks on DARK surfaces.
     Bone at 0.40 over --ink-abyss = #626F6C = 3.24:1  PASS non-text (3:1).
     The exploration used 0.32 (2.53:1), which fails; do not go below 0.40. */
  --rule-on-dark: color-mix(in srgb, var(--bone) 40%, transparent);

  /* Decorative separators only. Never the sole carrier of meaning.
     Bone at 0.20 over --ink-abyss = 1.75:1. */
  --hairline-on-dark: color-mix(in srgb, var(--bone) 20%, transparent);

  /* Sample / honesty label (acceptance criterion 9).
     On dark: canonical --label-sample-on-dark, Bone at 0.72 = 7.59:1.
     On light: an Ink chip carrying Bone type = 10.37:1. In both cases the
     label outranks every secondary element on its screen by design. */
  --label-sample-chip-on-light: var(--ink);
  --label-sample-ink-on-light:  var(--bone);

  /* Focus ring. Must be visible; the walkthrough is keyboard-completable.
       --signal on --ink-abyss = 10.21:1
       --ink    on --bone      = 10.37:1 */
  --focus-on-dark:  var(--signal);
  --focus-on-light: var(--ink);
  --focus-width: 2px;
  --focus-offset: 3px;

  /* ==========================================================
     4. THE PROSPECT'S BRAND
     One property, set by JS at runtime on the demo root. Default
     resolves to --ink so the un-personalized path is already
     on-brand and already accessible.
     ========================================================== */
  --brand-accent: var(--ink);

  /* Logo-plate type flip. The plate is a fill carrying one large Fraunces
     initial. Because the plate hex is arbitrary, the initial flips between
     Bone and Ink Abyss by the plate's relative luminance.

     THE MECHANISM: --brand-plate-flip is a 0 or 1 switch. JS sets it when it
     sets --brand-accent, using WCAG relative luminance:
         Y = 0.2126 R + 0.7152 G + 0.0722 B   (linearized sRGB channels)
         --brand-plate-flip = (Y >= 0.178) ? 1 : 0
     0.178 is the exact crossover where Bone and Ink Abyss give equal contrast
     against the plate (sqrt((Y_bone + .05)(Y_abyss + .05)) - .05), i.e. an
     8-bit grey of 118. Above it, Ink Abyss wins; below it, Bone wins.

     WORST CASE, at the crossover itself, is 3.69:1. That clears 3:1 but not
     4.5:1, so THE PLATE INITIAL IS ALWAYS SET AT LARGE-TEXT SCALE
     (>= 24px, or >= 18.66px at 600) where 3:1 is the AA requirement. The
     component layer enforces this; do not shrink it.

     A future one-liner: color: contrast-color(var(--brand-accent)) once that
     lands widely. It returns black or white, not Bone or Ink, so it will
     still need the mix below. */
  --brand-plate-flip: 0;
  --brand-plate-ink: color-mix(
    in srgb,
    var(--ink-abyss) calc(var(--brand-plate-flip) * 100%),
    var(--bone)
  );

  /* ==========================================================
     5. MOTION
     Standard transitions 150-300ms ease-out. Step reveals 240ms
     with 60ms stagger. Linework draw-on 900ms with band stagger.
     One choreographed sequence per experience (S3 -> S4).
     Every animated property has a reduced-motion fallback; the
     durations below collapse to ~0 in that block so a component
     that consumes the tokens is covered even if it forgets.
     ========================================================== */
  --dur-fast:    150ms;
  --dur:         200ms;
  --dur-slow:    300ms;
  --dur-reveal:  240ms;
  --dur-linework: 900ms;
  --stagger:      60ms;
  --stagger-cell: 30ms;   /* grid cells assembling, S3 */

  /* The S3 sequence (direction 1c, "One Thing At A Time"). One element group
     moves at a time; these are the three durations that group can have.
     Storyboard, from the locked exploration:
       0.0s linework draws on, 900ms, bands staggered   --dur-linework
       0.6s transcript lines type in, older ones lift    --dur-beat
       3.0s transcript out, the lanes sweep the centre   --dur-lane
       4.8s the grid assembles cell by cell, 30ms apart  --stagger-cell
       6.6s the overall stage sets left, linework recedes */
  --dur-beat: 320ms;      /* one beat replacing the last */
  --dur-lane: 520ms;      /* one lane bar sweeping out (scaleX) */
  --stagger-lane: 90ms;   /* lane-to-lane offset */

  /* The reduced-motion resolve. Deliberately NOT collapsed below: an opacity
     fade carries no vestibular risk, and decision 0001 turns on the reduced
     path still delivering the beat rather than snapping to a finished frame. */
  --dur-static: 200ms;

  /* How far the fit linework falls back at the S3 resolve, so nothing
     competes with the finding. Multiplies the per-band opacity. */
  --linework-receded: 0.16;

  --ease-out:      cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-emphasis: cubic-bezier(0.16, 0.84, 0.44, 1); /* the S3->S4 signature */

  /* ==========================================================
     6. FIT LINEWORK
     Canonical tokens set the color, the 1px stroke and the
     0.2-0.7 opacity range; --linework-opacity-cover-max caps
     covers at 0.5. Added here: the per-band ramp the component
     layer walks, so a band never exceeds its surface's cap.
     The ramp stays inside the canonical 0.2-0.7 range at every
     step; .d-linework--cover clamps each band to 0.5.
     Linework occupies negative space ONLY, never behind type,
     one instance per screen, 1px at every scale.
     ========================================================== */
  --linework-band-1: 0.60;
  --linework-band-2: 0.48;
  --linework-band-3: 0.38;
  --linework-band-4: 0.30;
  --linework-band-5: 0.24;
  --linework-band-6: 0.20;
}

/* Reduced motion: collapse every duration token. Components still declare
   their own explicit fallbacks; this is the safety net. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 1ms;
    --dur: 1ms;
    --dur-slow: 1ms;
    --dur-reveal: 1ms;
    --dur-linework: 1ms;
    --stagger: 0ms;
    --stagger-cell: 0ms;
    --dur-beat: 1ms;
    --dur-lane: 1ms;
    --stagger-lane: 0ms;
    /* --dur-static is intentionally NOT collapsed. It is the reduced-motion
       path's own 200ms fade, not a transition being suppressed. */
  }
}
