/* ═══════════════════════════════════════════════════════════════════════
   DEVMARK LIBRARY — design tokens
   ═══════════════════════════════════════════════════════════════════════

   POSITION
   A reading room, not a screen. The ground is warm paper, the shelves are
   oak, the ink is a soft charcoal that never reaches pure black. Light falls
   from the upper left, so every ledge carries a warm top edge and a cool
   shadow beneath it, and every book casts contact shadow where it meets the
   plank.

   The colour in this library still comes from the books — 281 of the 283
   carry their real cover art, and the interface stays deliberately quiet so
   that the covers are the only saturated thing on the page.

   NAMING
   The tokens below are semantic: --ground, --surface, --ink-1, --oak. The
   older --ink-900 / --paper names are kept underneath as aliases so that the
   stylesheets written against them keep working. New work should use the
   semantic names; the aliases exist to avoid a rename across 1,800 lines of
   CSS that would risk the validated baseline for no visual gain.

   CONTRAST
   Every text pair is measured against every ground in scripts/validate.py,
   which fails the build under WCAG AA (4.5:1 body, 3:1 large). The warm
   palette was chosen against that gate, not eyeballed and checked after:

     Measured against the WORST of the five surfaces, not the best:
     ink-1 #1C1814  10.46 : 1     ink-3 #574E41   4.84 : 1
     ink-2 #3B342B   7.27 : 1     ink-4 #6F6455   3.43 : 1  (large only)
     accent #7A4223  4.73 : 1 — passes as body text, not only as accent
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Ground & surfaces ─────────────────────────────────────────────────
     Five warm papers on a deliberate ladder. An earlier version kept these
     within a hair of each other, on the theory that a reading room is not a
     high-contrast interface — and the result was cream cards dissolving into
     a cream page. Every adjacent pair now differs by at least 1.12:1, which
     is enough to read as a step without anything looking like a grey box:

       surface -> ground  1.13      band   -> raised  1.15
       ground  -> band    1.13      raised -> sunk    1.13
       surface -> sunk    1.66  (the full range)

     A card is the LIGHTEST surface and the page sits below it, so a card
     reads as lifted rather than cut out. */
  --surface:  #FFFDF8;   /* card, popover — the lightest thing on screen   */
  --ground:   #F4EFE4;   /* page                                           */
  --band:     #E9E1D2;   /* section band                                   */
  --raised:   #DCD2BF;   /* chip, input well, pressed state                */
  --sunk:     #D2C6B0;   /* shelf recess — the wall the books stand against */

  /* ── Oak ───────────────────────────────────────────────────────────────
     The shelf itself. Three tones: the lit top edge of a plank, the face
     the books stand against, and the shadowed front lip. */
  --oak-lit:  #C89A63;
  --oak:      #A97C4E;
  --oak-deep: #7D5733;
  --oak-edge: #5C3E22;

  /* ── Ink ───────────────────────────────────────────────────────────────
     Warm charcoal rather than black — a printed page has never been #000. */
  --ink-1: #1C1814;   /* 15.79:1 on ground — headings, titles              */
  --ink-2: #3B342B;   /* 10.98:1           — body copy                     */
  --ink-3: #574E41;   /*  6.64:1           — metadata, captions            */
  --ink-4: #6F6455;   /*  4.46:1           — LARGE TEXT / rules ONLY       */

  /* ── Accent ────────────────────────────────────────────────────────────
     Terracotta carries small-caps labels, counts and rules — the warm
     editorial note in the references. It clears AA as body text, so it is
     never a decorative colour applied to unreadable text. */
  --accent:      #7A4223;

  /* ── Display accent ────────────────────────────────────────────────────
     For the italic clause in the hero and nothing else. The signal green
     measures 1.00:1 against these creams — literally invisible as text —
     so it was doing the opposite of emphasis on the one line that matters
     most. Oxblood is the bookbinding colour this library is already dressed
     in: it belongs beside the oak and the cream, and it clears AA on every
     surface at 6.09:1. */
  --display-accent: #6E2B2B;
  --accent-soft: rgba(122, 66, 35, 0.13);
  --accent-line: rgba(122, 66, 35, 0.34);

  /* ── Signal ────────────────────────────────────────────────────────────
     Devmark's mark green is unchanged and stays the brand's own colour. On
     a light ground it cannot carry text, so it is used as a FILL with dark
     ink on top — the mark, focus rings, verification state — never as a
     foreground colour on paper. */
  --signal:      #D6FF3D;
  --signal-ink:  #1C1814;
  --signal-dim:  rgba(214, 255, 61, 0.30);
  --signal-line: rgba(122, 66, 35, 0.55);

  /* ── Lines & shadow ────────────────────────────────────────────────────
     On paper a shadow is a real shadow. These are warm-tinted rather than
     neutral grey, because a neutral shadow on a warm ground reads as dirt. */
  --hair:   rgba(74, 48, 24, 0.17);
  --hair-2: rgba(74, 48, 24, 0.27);
  --hair-3: rgba(74, 48, 24, 0.40);

  --lift-1: 0 1px 2px rgba(64, 42, 20, .13);
  --lift-2: 0 5px 14px rgba(64, 42, 20, .17), 0 1px 3px rgba(64, 42, 20, .12);
  --lift-3: 0 16px 38px rgba(64, 42, 20, .22), 0 5px 12px rgba(64, 42, 20, .14);
  --lift-4: 0 44px 96px rgba(64, 42, 20, .28), 0 12px 30px rgba(64, 42, 20, .18);

  /* Contact shadow: what a book casts where it meets the plank. Tight,
     dark and close, which is what sells an object as resting on a surface. */
  --contact: 0 2px 3px rgba(60, 38, 18, .40), 0 6px 14px rgba(60, 38, 18, .22);

  /* ── Aliases ───────────────────────────────────────────────────────────
     The previous dark-theme names, re-pointed at the warm palette so that
     existing rules keep working unchanged. --ink-900 now means "the page",
     and --paper now means "ink on the page", which is the reverse of what
     those words suggest; that is the cost of not renaming, and the reason
     new rules should use the semantic names above. */
  --ink-900: var(--ground);
  --ink-850: var(--band);
  --ink-800: var(--surface);
  --ink-750: var(--surface);
  --ink-700: var(--raised);
  --ink-650: var(--sunk);
  --ink-600: var(--hair-3);
  --paper:   var(--ink-1);
  --paper-2: var(--ink-2);
  --paper-3: var(--ink-3);
  --paper-4: var(--ink-4);

  /* ── Radius ────────────────────────────────────────────────────────────
     Deliberately tight. The reference's signature is a very large curve;
     ours is a near-square corner, because the object on screen is a book. */
  --r-1: 2px;
  --r-2: 4px;
  --r-3: 8px;
  --r-4: 14px;
  --r-pill: 999px;

  /* ── Type ──────────────────────────────────────────────────────────────
     Two families, both self-hosted.
       Zodiak  (ITF, Fontshare, ITF Free Font License) — display serif with a
               true italic; carries titles and section numerals.
       Satoshi (ITF, already licensed and self-hosted by Devmark) — every
               piece of interface text, metadata and body copy. */
  --font-display: 'Zodiak', 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  --font-ui: 'Satoshi', -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, system-ui, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;

  /* A modular scale at 1.25, clamped so the extremes stay usable. Named by
     role, not by size, so a change of scale does not require a rename. */
  --t-hero:    clamp(2.75rem, 7.2vw, 6.25rem);
  --t-display: clamp(2rem, 4.4vw, 3.5rem);
  --t-h2:      clamp(1.5rem, 2.6vw, 2.25rem);
  --t-h3:      clamp(1.15rem, 1.5vw, 1.4rem);
  --t-lead:    clamp(1.05rem, 1.25vw, 1.2rem);
  --t-body:    clamp(0.95rem, 1.02vw, 1.0rem);
  --t-read:    clamp(1.02rem, 1.12vw, 1.125rem);  /* long-form summary body */
  --t-small:   0.8125rem;
  --t-micro:   0.6875rem;

  --lh-tight: 1.04;
  --lh-snug:  1.22;
  --lh-body:  1.58;
  --lh-read:  1.72;

  /* Letterspacing. Uppercase micro-labels need generous tracking; the display
     serif needs slightly negative tracking at large sizes. */
  --ls-label:   0.14em;
  --ls-display: -0.022em;
  --ls-hero:    -0.032em;

  /* ── Space ─────────────────────────────────────────────────────────────
     A 4px base with a deliberate jump at --s-7 so that section rhythm is
     obviously different from component rhythm. */
  --s-1: 4px;   --s-2: 8px;   --s-3: 12px;  --s-4: 16px;
  --s-5: 24px;  --s-6: 32px;  --s-7: 48px;  --s-8: 64px;
  --s-9: 96px;  --s-10: 128px;

  --gutter: clamp(18px, 4vw, 56px);
  --maxw: 1440px;
  --maxw-read: 68ch;        /* long-form measure                          */
  --nav-h: 62px;

  --section-y: clamp(64px, 9vw, 132px);

  /* ── Motion ────────────────────────────────────────────────────────────
     One curve family. The three `linear()` values are genuine damped-spring
     solutions (mass 1) sampled to 26 points — computed, not eyeballed:

       spring-soft   k=170 c=26   no overshoot, 710ms natural
       spring-snap   k=320 c=26   3.5% overshoot, 560ms natural
       spring-pop    k=420 c=22   13% overshoot, 620ms natural

     Use `pop` only where something should feel physically thrown — a book
     leaving the shelf. Everything else is `soft` or the plain ease-out. */
  --e-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --e-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --e-in:     cubic-bezier(0.5, 0, 0.75, 0);

  --e-spring-soft: linear(0.0000, 0.0538, 0.1702, 0.3054, 0.4366, 0.5533, 0.6519, 0.7324, 0.7965, 0.8466, 0.8853, 0.9148, 0.9370, 0.9537, 0.9661, 0.9753, 0.9820, 0.9870, 0.9906, 0.9932, 0.9951, 0.9965, 0.9975, 0.9982, 0.9987, 1.0000);
  --e-spring-snap: linear(0.0000, 0.0659, 0.2148, 0.3923, 0.5645, 0.7129, 0.8303, 0.9162, 0.9743, 1.0098, 1.0285, 1.0355, 1.0351, 1.0307, 1.0246, 1.0182, 1.0124, 1.0077, 1.0042, 1.0017, 1.0001, 0.9992, 0.9988, 0.9987, 0.9988, 1.0000);
  --e-spring-pop:  linear(0.0000, 0.1063, 0.3421, 0.6069, 0.8370, 1.0021, 1.0973, 1.1336, 1.1285, 1.1006, 1.0648, 1.0314, 1.0060, 0.9900, 0.9828, 0.9819, 0.9849, 0.9896, 0.9944, 0.9982, 1.0008, 1.0021, 1.0025, 1.0022, 1.0016, 1.0000);

  /* Duration hierarchy. A control must answer within --d-micro or it feels
     broken; a page may take --d-signature because the user asked for it. */
  --d-micro: 140ms;
  --d-fast:  220ms;
  --d-ui:    340ms;
  --d-content: 560ms;
  --d-signature: 880ms;

  /* Stagger step for grids. Capped in JS at 10 items so a 300-card grid
     never accumulates a two-second delay. */
  --stagger: 38ms;

  --z-shelf: 10;
  --z-nav: 80;
  --z-overlay: 120;
  --z-toast: 200;
}

/* ── Spine colour families ───────────────────────────────────────────────
   Each shelf owns three hues. A book's spine picks one deterministically
   from its id, with lightness and chroma jittered inside a narrow band so a
   shelf looks like a run of real cloth bindings rather than a swatch chart.
   Generated per-book as inline custom properties by the build; these are the
   bounds it works within. */
:root {
  --spine-l: 38%;          /* base lightness — cloth, readable on oak     */
  --spine-l-range: 14%;
  --spine-c: 0.062;        /* chroma — muted, never saturated             */
  --spine-foot: rgba(40, 24, 10, 0.42);
  --spine-head: rgba(255, 246, 232, 0.16);
}

/* ── Reduced motion ──────────────────────────────────────────────────────
   Motion is removed, not merely shortened: transforms that convey meaning
   (a book leaving a shelf) are replaced by an opacity change, and every
   scroll-linked effect is disabled at source in motion.js. Layout never
   depends on an animation having run. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --d-micro: 1ms; --d-fast: 1ms; --d-ui: 1ms;
    --d-content: 1ms; --d-signature: 1ms; --stagger: 0ms;
    --e-spring-soft: linear(0, 1);
    --e-spring-snap: linear(0, 1);
    --e-spring-pop:  linear(0, 1);
  }
}
