/* ==========================================================================
   Laurels — design tokens as CSS custom properties.
   Machine source: design/tokens.json v0.3.0
   Colour SETTLED 2026-08-15 (decisions/0075). Type, space, radius, elevation
   SETTLED 2026-08-15 (decisions/0074). Motion character SETTLED 2026-08-15.

   Rule: a value not in this file is a defect. Sections below mirror
   tokens.json exactly; web-only additions are marked WEB-ONLY and explain
   why the app token could not be used verbatim.
   ========================================================================== */

:root {
  /* ---- Colour · grounds ------------------------------------------------ */
  --dark-ground:        #20122D;
  --dark-surface:       #362B40;
  --dark-raised:        #40334C;

  --light-ground:       #D5D7DA;   /* mist  */
  --light-surface:      #F6F4F5;   /* paper */
  --light-raised:       #FFFFFF;

  /* ---- Colour · text --------------------------------------------------- */
  --on-dark-1:          #F6F4F5;
  --on-dark-2:          #CFC7D8;
  --on-dark-3:          #A99DB8;   /* metadata only — never prose */

  --on-light-1:         #20122D;
  --on-light-2:         #4E4761;
  --on-light-3:         #7B7389;   /* fails AA body — metadata only */

  /* ---- Colour · accents ------------------------------------------------
     cool = EARNED (history, progress, what is already done)
     warm = THE SUBJECT (the one thing asking for attention)
     Neither is ever the button: --cta-* owns the action.               */
  --cool-on-dark:       #8BABC7;
  --warm-on-dark:       #F48754;
  --cool-on-light:      #497397;
  --warm-on-light-fill: #E6530F;   /* fills, borders, strokes only */
  --warm-on-light-text: #C0450C;   /* text grade, paper only */

  /* ---- Colour · panels ------------------------------------------------- */
  --panel-cream:        #F4EFE6;
  --panel-cream-title:  #20122D;
  --panel-cream-body:   #4E4761;

  /* ---- Colour · call to action ----------------------------------------- */
  --cta-on-dark-fill:   #F6F4F5;
  --cta-on-dark-label:  #20122D;
  --cta-on-dark-press:  #DCD6E0;

  --cta-on-light-fill:  #20122D;
  --cta-on-light-label: #F6F4F5;
  --cta-on-light-press: #362B40;

  /* ---- Colour · borders ------------------------------------------------ */
  --hairline-dark:      rgba(246, 244, 245, .14);
  --hairline-light:     rgba(32, 18, 45, .14);

  /* ---- Type · families -------------------------------------------------
     WEB-ONLY. tokens.json names 'Iowan Old Style', which ships with macOS
     and iOS but has no web licence. Apple visitors get the real brand face;
     everyone else falls to Newsreader, chosen 2026-08-20 by rendering Iowan
     against Source Serif 4, Newsreader and Petrona at 60 px: Newsreader
     matched Iowan's set width and colour most closely of the three.
     Body is the platform UI face, as in the app, with Inter standing in
     where there is no good native grotesque.                            */
  --font-display: 'Iowan Old Style', 'Newsreader', 'Iowan Old Style Roman',
                  Charter, Georgia, 'Times New Roman', serif;
  --font-body:    -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI',
                  Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-label:   ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;

  /* ---- Type · scale ----------------------------------------------------
     App sizes are pt on a 390 pt screen. WEB-ONLY: display sizes are fluid
     because a 1440 px page cannot use a phone's 38 pt heading. The ratios,
     weights and line-height rules are the app's.                        */
  --step-display:  clamp(2.75rem, 1.6rem + 4.6vw, 5.25rem);   /*  44 → 84 */
  --step-h1:       clamp(2.25rem, 1.4rem + 3.4vw, 4.00rem);   /*  36 → 64 */
  --step-h2:       clamp(1.75rem, 1.2rem + 2.2vw, 2.75rem);   /*  28 → 44 */
  --step-h3:       clamp(1.25rem, 1.05rem + 0.8vw, 1.625rem); /*  20 → 26 */
  --step-lead:     clamp(1.0625rem, 1rem + 0.5vw, 1.3125rem); /*  17 → 21 */
  --step-body:     1.0625rem;                                 /*  17     */
  --step-small:    0.9375rem;                                 /*  15     */
  --step-caption:  0.8125rem;                                 /*  13     */
  --step-overline: 0.75rem;                                   /*  12 — floor */
  --step-figure:   clamp(4rem, 2rem + 9vw, 9rem);             /*  64 → 144 */

  --leading-tight: 1.06;
  --leading-snug:  1.18;
  --leading-body:  1.55;
  --tracking-tight: -0.02em;
  --tracking-overline: 0.08em;

  /* ---- Space · 4 pt scale ---------------------------------------------- */
  --space-1: 4px;   --space-2: 8px;   --space-3: 12px;  --space-4: 16px;
  --space-5: 20px;  --space-6: 24px;  --space-8: 32px;  --space-10: 40px;
  --space-12: 48px; --space-16: 64px; --space-20: 80px;

  --tap-target-min: 44px;
  --button-height:  52px;
  --card-padding:   var(--space-5);

  /* WEB-ONLY: a phone's 20 px screen padding and a desktop gutter are not
     the same measurement. Both stay on the 4 pt scale.

     --section-gap was clamp(72px, 9vw, 128px) until 2026-08-21, which put
     128 px between two sections at 1440. Measured off the reference at the
     same width: 200 px above a section heading and 96 px below the section
     it opens. The page was running at roughly half the reference's rhythm,
     and on a page this short the air is most of what reads as expensive.
     Both bounds stay on the 4 pt scale.                                 */
  --gutter:         clamp(20px, 4vw, 32px);
  --section-gap:    clamp(96px, 12vw, 192px);
  --measure:        68ch;
  --page-max:       1280px;
  --page-narrow:    900px;

  /* ---- Radius ---------------------------------------------------------- */
  --radius-sm:    12px;   /* thumbnails, inline badges */
  --radius-md:    20px;   /* rows, inputs, image containers */
  --radius-lg:    28px;   /* cards */
  --radius-sheet: 36px;
  --radius-full:  999px;
  /* WEB-ONLY: the hero and closing bands are containers well above card
     scale; 28 px reads tight at 1280 px. Derived by the same rule —
     exceeds half the height of any pill inside it.                      */
  --radius-band:  clamp(24px, 2.2vw, 40px);

  /* ---- Elevation · light always comes from above ----------------------- */
  --elev-card-light:
      0 6px 14px rgba(64, 51, 76, .07),
      0 1px 2px  rgba(32, 18, 45, .06);
  --elev-card-dark:
      0 6px 14px rgba(0, 0, 0, .32),
      0 1px 2px  rgba(0, 0, 0, .35);
  --elev-row-light: 0 2px 4px rgba(32, 18, 45, .05);
  --elev-row-dark:  0 2px 4px rgba(0, 0, 0, .40);
  /* WEB-ONLY: a card that floats over the hero band needs a longer throw
     than a card resting in a list. Same direction, same hue.            */
  --elev-float:
      0 24px 60px rgba(32, 18, 45, .28),
      0 4px 12px  rgba(32, 18, 45, .16);

  --top-gradient-light: rgba(255, 255, 255, .72);
  --top-gradient-dark:  rgba(255, 255, 255, .06);

  /* ---- Motion · character is Weight. Objects have mass. ---------------- */
  --dur-fast: 140ms;   /* press feedback, fill change */
  --dur-mid:  280ms;   /* an element arriving or leaving */
  --dur-slow: 420ms;   /* sheet, modal, screen transition */
  --stagger-tight:  75ms;
  --stagger-staged: 150ms;
  --beat: 200ms;
  --travel: 16px;      /* standard entrance distance — no further */

  --ease-standard: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-staged:   cubic-bezier(0.22, 1, 0.36, 1);

  /* ---- Icon ------------------------------------------------------------ */
  --icon-sm: 16px;  --icon-sm-stroke: 1.25;
  --icon-md: 20px;  --icon-md-stroke: 1.5;
  --icon-lg: 24px;  --icon-lg-stroke: 1.75;
  --icon-xl: 32px;  --icon-xl-stroke: 2.25;
}

/* --------------------------------------------------------------------------
   Ground contexts. Everything on the page sits on exactly one layer, and
   body copy never sits on layer 0 (tokens.json color.layer). Setting a
   context switches the whole text and border palette in one move, so a
   component never has to know which ground it landed on.
   -------------------------------------------------------------------------- */

.on-light {
  --ground:   var(--light-ground);
  --surface:  var(--light-surface);
  --raised:   var(--light-raised);
  --text-1:   var(--on-light-1);
  --text-2:   var(--on-light-2);
  --text-3:   var(--on-light-3);
  --cool:     var(--cool-on-light);
  --warm:     var(--warm-on-light-text);
  --warm-fill:var(--warm-on-light-fill);
  --hairline: var(--hairline-light);
  --elev-card:var(--elev-card-light);
  --elev-row: var(--elev-row-light);
  --top-gradient: var(--top-gradient-light);
  --cta-fill: var(--cta-on-light-fill);
  --cta-label:var(--cta-on-light-label);
  --cta-press:var(--cta-on-light-press);
}

.on-dark {
  --ground:   var(--dark-ground);
  --surface:  var(--dark-surface);
  --raised:   var(--dark-raised);
  --text-1:   var(--on-dark-1);
  --text-2:   var(--on-dark-2);
  --text-3:   var(--on-dark-3);
  --cool:     var(--cool-on-dark);
  --warm:     var(--warm-on-dark);
  --warm-fill:var(--warm-on-dark);
  --hairline: var(--hairline-dark);
  --elev-card:var(--elev-card-dark);
  --elev-row: var(--elev-row-dark);
  --top-gradient: var(--top-gradient-dark);
  --cta-fill: var(--cta-on-dark-fill);
  --cta-label:var(--cta-on-dark-label);
  --cta-press:var(--cta-on-dark-press);
}
