/* ============================================================================
   TOKENS — the one system.

   Every value the site uses lives here. No component file invents a colour, a
   step of space, a duration or an easing curve. If something needs a value
   that is not in this file, the answer is to add it here with a reason, not to
   hard-code it downstream.

   SURFACE  Warm cream paper, warm near-black ink. The paper is warm on
            purpose: this site carries several hundred pieces of full-colour
            character art, and a clinical #fff makes that artwork read as
            clip-art pasted onto a spec sheet. Cream makes it read as printed.

   COLOUR   The shell is paper + ink + one accent. Violet means "this responds
            to you" and appears at rest almost nowhere. The two marker colours
            are not UI colours at all — they only ever appear as hand-drawn
            strokes and inside the night panel.

   MOTION   There is no ambient motion on this site. Nothing moves unless the
            visitor did something: moved a pointer across the hero stage,
            pressed a control, or scrolled a section into view for the first
            and only time. The hero field was the last exception and it is one
            no longer — it answers a pointer inside a declared frame and rests
            the moment that pointer leaves.

            Anything that moves on its own is a bug, not a flourish. If it
            cannot be traced back to something the reader did, take it out.

            Transform and opacity only. Nothing animates a property that
            triggers layout. If you find yourself transitioning height, width,
            top, left, margin or padding, the design is wrong, not the CSS.
   ========================================================================== */

:root {
  /* ---------------------------------------------------------------- surface */
  --paper:        #F7F8FC;   /* the page */
  --paper-2:      #EEF1F6;   /* recessed wells, tile beds, input rests */
  --paper-3:      #E3E8F0;   /* pressed / active state of the above */
  --night:        #090C12;   /* the contact reveal, and dark-artwork beds */
  --night-2:      #121722;   /* raised surfaces inside the night */

  /* Home's light-only sky is a contained art direction, not a second colour
     system. These values exist here so the hero never invents palette
     literals of its own. */
  --sky-top:      #A9D3EA;
  --sky-mid:      #D4EAF4;
  --sky-glow:     rgba(255, 255, 255, .72);

  --ink:          #11141A;   /* body text, headlines */
  --ink-soft:     #343B47;   /* secondary headings on paper */

  /* The quiet end of the ramp is arithmetic, not taste. Cream is as light as
     this page ever gets and the recessed surfaces are darker still, so there
     is only so much room underneath it for steps that are still text. Both of
     these are the lightest value that clears 4.5:1 on --paper-2 with a little
     to spare — 5.52:1 and 4.67:1, sampled off the rendered page rather than
     computed off the token, because half the beds on this site are artwork
     under a translucent surface and no token can tell you what those measure.

     --dim is darker than the 4.80:1 it used to manage because two of its beds
     are not paper: the archive's clear button sits on --paper-3 at 4.31:1, and
     its live result count sits on a frosted bar over the index at 4.01:1. It
     now measures 4.95:1 and 4.61:1 there.

     --faint was #A2998A and meant "switched off". It measured 2.42:1, and what
     it was switching off included the archive's search placeholder, the hero's
     cue, the meta line under every prev/next case, and the piece count on all
     29 packs — none of which are decoration. A token cannot be both a disabled
     tone and a legible one, so this one stopped being a disabled tone. All the
     room left below --dim is a single step, which is what this is: quieter,
     not absent. Anything that genuinely has to read as unavailable needs a
     state now, not a lighter grey. */
  --dim:          #5C6675;   /* metadata and captions */
  --faint:        #6C7685;   /* counters, hints, the quietest label */
  --line:         #DDE2EA;   /* hairlines on paper */
  --line-2:       #C7CFDB;   /* hairlines that need to be seen */

  --on-night:     #F4F6FB;   /* text on the night surface */
  --dim-night:    #AAB2C2;
  --line-night:   #29313D;

  /* ----------------------------------------------------------------- accent
     One interactive colour. It is not decorative: if something is violet, it
     did something or is about to. */
  --accent:       #5B21F5;
  --accent-lift:  #7442FF;   /* hover on an already-violet surface */
  --accent-wash:  #ECE8FF;   /* violet at wash strength over cool paper */
  --on-accent:    #FFFFFF;

  /* ---------------------------------------------------------------- markers
     Hand-drawn strokes only. Never a background, never a border, never text.
     Three of them so a page of scribbles doesn't read as one repeated stamp. */
  --marker-1:     #FF4D2E;   /* coral */
  --marker-2:     #5B21F5;   /* violet, doubles as the accent */
  --marker-3:     #0E9F6E;   /* green */

  /* ------------------------------------------------------------------ meter */
  --page:         1320px;    /* the standard reading/grid column */
  --page-wide:    1560px;    /* full-bleed-ish sections: slabs, marquees */
  --page-text:    58ch;      /* prose never exceeds this */
  --gutter:       clamp(20px, 5vw, 72px);

  /* Header controls paint at the compact desktop size while retaining a
     slightly larger, forgiving target around that visible surface. */
  --control-h:    40px;
  --control-hit:  44px;

  /* The shared portfolio masthead is 88px tall plus its scrolled hairline. It
     lives here because anchor clearance, the case rail and the archive search
     bar all need the same fixed-header measurement. */
  --hd-h:         calc(var(--s6) + var(--s4) + 1px);

  /* ------------------------------------------------------------------ space
     A single ladder. Sections use --s7/--s8 for their rhythm; components use
     --s1..--s5. Nothing between the rungs. */
  --s1: 4px;   --s2: 8px;    --s3: 16px;   --s4: 24px;
  --s5: 40px;  --s6: 64px;   --s7: 96px;   --s8: 144px;   --s9: 200px;

  /* ------------------------------------------------------------------ radii
     Slabs are generously round because they are objects you want to pick up.
     The dense archive stays nearly square because it is an index, not a toy. */
  --r-1:    10px;
  --r-2:    20px;
  --r-3:    32px;
  --r-pill: 999px;

  /* ------------------------------------------------------------------- type */
  --display: 'Bricolage Grotesque', 'Inter', system-ui, sans-serif;
  --body:    'Inter', system-ui, -apple-system, sans-serif;
  /* Metadata now shares the body face. A separate monospace register made
     ordinary labels and counts read like developer tooling. */
  --mono:    'Inter', system-ui, -apple-system, sans-serif;
  --hand:    'Shantell Sans', 'Bricolage Grotesque', cursive;

  /* Fluid scale. Every size on the site is one of these — there is no
     "just this once" font-size anywhere downstream. */
  /* Sized so the hero's four lines, its lead AND both buttons clear a 900px
     laptop viewport with air to spare. The first pass ran 11vw/168px, which
     looked magnificent in isolation and pushed the primary call to action onto
     the second screen — a headline that eats its own conversion. */
  --t-mega:  clamp(40px, 7.4vw, 116px);  /* hero only */
  --t-xl:    clamp(32px, 4.6vw,  68px);  /* section openers, night panel */
  --t-lg:    clamp(26px, 3.2vw,  46px);  /* slab titles, case headers */
  --t-md:    clamp(21px, 2.1vw,  30px);  /* sub-heads, lead paragraphs */
  --t-sm:    17px;                       /* body */
  --t-xs:    14.5px;                     /* secondary body, captions */
  --t-mono:  13px;                       /* metadata and captions */

  --lh-tight:  0.94;
  --lh-snug:   1.08;
  --lh-normal: 1.55;
  --tr-tight:  -0.035em;   /* mega + xl */
  --tr-snug:   -0.022em;   /* lg + md */
  --tr-mono:    0.01em;

  /* ----------------------------------------------------------------- motion
     Theme switching covers, swaps and reveals. The original control keeps its
     appearance but uses a shorter travel time so it lands with the veil. */
  --t-theme-in:  .09s;
  --t-theme-out: .10s;
  --t-toggle:    .20s;
  --theme-veil-peak: .985; /* visually opaque without triggering paint culling */
  --t-micro:   .14s;   /* colour, opacity, tiny nudges */
  --t-hover:   .22s;   /* the standard hover response */
  --t-move:    .42s;   /* something travels across the screen */
  --t-reveal:  .78s;   /* a section arriving, once */
  --t-theatre: .95s;   /* the night panel. Used exactly once. */

  --ease-out:    cubic-bezier(.22, .80, .24, 1);    /* default: decisive stop */
  --ease-io:     cubic-bezier(.65, 0, .35, 1);      /* things that travel */
  --ease-spring: cubic-bezier(.34, 1.42, .50, 1);   /* stickers ONLY */

  /* Stagger unit for revealing a row of things. Multiply by index, cap at 6. */
  --stagger: 55ms;

  /* ------------------------------------------------------------------ depth
     Warm shadows. A neutral grey shadow on cream looks like dirt. */
  --lift-1: 0 1px 2px rgba(40, 30, 12, .05), 0 2px 8px rgba(40, 30, 12, .04);
  --lift-2: 0 2px 6px rgba(40, 30, 12, .06), 0 12px 32px rgba(40, 30, 12, .08);
  --lift-3: 0 6px 14px rgba(40, 30, 12, .08), 0 28px 64px rgba(40, 30, 12, .12);

  /* ------------------------------------------------------------------ layer
     Named so nothing downstream has to guess a number. */
  --z-art:      1;
  --z-content:  10;
  --z-sticky:   60;
  --z-float:    80;
  --z-overlay: 110;
  --z-night:   120;
  --z-cursor:  200;
}

/* ------------------------------------------------------------------- theme
   Dark mode remaps the same semantic tokens instead of restyling components.
   Full-colour portfolio artwork is never filtered or recoloured. */
html[data-theme="dark"] {
  --paper:        #0D1016;
  --paper-2:      #151A22;
  --paper-3:      #202733;
  --night:        #090C12;
  --night-2:      #121722;

  --ink:          #F4F6FB;
  --ink-soft:     #D7DCE7;
  --dim:          #AAB2C2;
  --faint:        #8993A5;
  --line:         #252C38;
  --line-2:       #3A4453;

  --on-night:     #F4F6FB;
  --dim-night:    #AAB2C2;
  --line-night:   #29313D;

  /* Brand violet does not change with the surrounding theme. */
  --accent:       #5B21F5;
  --accent-lift:  #7442FF;
  --accent-wash:  color-mix(in srgb, var(--accent) 14%, var(--paper-2));
  --on-accent:    #FFFFFF;

  --sky-top:      #0B1220;
  --sky-mid:      #101722;
  --sky-glow:     rgba(91, 33, 245, .12);

  --lift-1: 0 1px 2px rgba(0, 0, 0, .18), 0 2px 8px rgba(0, 0, 0, .16);
  --lift-2: 0 2px 6px rgba(0, 0, 0, .22), 0 12px 32px rgba(0, 0, 0, .25);
  --lift-3: 0 6px 14px rgba(0, 0, 0, .25), 0 28px 64px rgba(0, 0, 0, .34);
}

/* The veil owns a theme change. Letting every card, border, shadow and control
   run its own transition beneath it would keep doing hidden paint work. */
html.theme-changing {
  --t-micro: .01ms;
  --t-hover: .01ms;
  --t-move:  .01ms;
}

/* Motion is opt-out at the system level, not per-component. Every animated
   thing on this site keys off this one class, which motion.js sets on <html>
   from the media query. Doing it with a class rather than the media query
   alone means JS-driven motion (stickers, cursor, parallax) can check the
   same single source of truth. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --t-theme-in: .01ms; --t-theme-out: .01ms; --t-toggle: .01ms;
    --t-micro: .01ms; --t-hover: .01ms; --t-move: .01ms;
    --t-reveal: .01ms; --t-theatre: .01ms; --stagger: 0ms;
  }
}
