/* CurtainCall design tokens, assets/tokens.css
   The single source of truth for colour, type, space and depth across every page. Linked first by index.html,
   the four case-study pages, the three legal pages and 404.html; no page declares its own :root any more.

   Two layers, and the rule that makes it a system rather than a list:

     Layer 1, PRIMITIVES (--cc-*, --rgb-*, --alpha-*) name a colour or a number. Nothing outside this file
     uses them, with one exception: a semantic token is defined in terms of a primitive. Since 2026-10-12 no
     stylesheet does (review B8.2: 37 uses had crept into home.css); CLAUDE.md's Verification greps check it.

     Layer 2, SEMANTIC (--surface-*, --text-*, --accent*, --border-*, --focus-*, --feedback-*) name a ROLE.
     Every rule in every stylesheet uses these. If you find yourself wanting a colour that has no role, the
     honest fix is to add the role here, not to write the value at the point of use.

   Why the RGB triples exist: the palette needs many alpha levels and color-mix() is not old enough to lean on
   for a site with no build step, so alphas are composed as rgba(var(--rgb-cyan), var(--alpha-4)).

   Before this file existed (2026-09-23) the 13 colour tokens were copy-pasted into eight documents and had
   already drifted apart, assets/home.css carried 131 raw colour literals across 78 distinct values, and
   changing the cyan meant editing 165 places. Four tokens were declared everywhere and used nowhere.
   Keep it that way: add a role, use the role. */

:root {
  /* ============================================================ LAYER 1: PRIMITIVES */

  /* Brand. These five hex values ARE the brand and do not change without Eric's sign-off. */
  --cc-cyan: #4FCCFA;
  --cc-blue: #7BAAFF;        /* the middle stop of the CTA ramp, cyan into purple */
  --cc-purple: #CFA6FF;
  --cc-cyan-light: #A8EDFF;  /* light cyan: a hovered cyan link (--accent-bright), the comic button's stripes */
  --cc-deep: #2F164D;        /* deep purple, the hero gradient's far tone */

  /* Ink. Three darks, not the six that had accumulated by round 5. */
  --cc-ink: #0C0916;         /* the page itself */
  --cc-ink-sunken: #0A0713;  /* anything recessed: media wells, the intro curtain */
  --cc-ink-raised: #120C22;  /* anything lifted: cards, plates, the solid glass fallback */
  --cc-ink-on-cyan: #06121A; /* foreground for text sitting on a cyan fill */

  /* Channel triples, for composing alphas. */
  --rgb-cyan: 79, 204, 250;
  --rgb-purple: 207, 166, 255;
  --rgb-blue: 123, 170, 255;   /* --cc-blue as a triple, for the CTA ramp */
  --rgb-ink: 12, 9, 22;
  --rgb-white: 255, 255, 255;

  /* One alpha ramp for general translucent surfaces, borders and glows.
     Note on method: the roles below were mapped onto this ramp only where the existing value was already on or
     beside a step. Values Eric tuned by eye, chiefly the glass bevel, keep their exact numbers under their own
     names further down, because snapping a hand-tuned material to a round number is how a system destroys the
     thing it was meant to protect. The ramp governs what comes next; it does not overwrite what was judged. */
  --alpha-1: .04;
  --alpha-2: .08;
  --alpha-3: .12;
  --alpha-4: .16;
  --alpha-5: .24;
  --alpha-6: .32;
  --alpha-7: .48;

  /* ============================================================ LAYER 2: SEMANTIC COLOUR */

  /* Surfaces, darkest to lightest. */
  --surface-page: var(--cc-ink);
  --surface-sunken: var(--cc-ink-sunken);
  --surface-raised: var(--cc-ink-raised);
  --surface-glass: rgba(var(--rgb-white), .035);   /* the tint inside a glass face */
  --surface-glass-solid: rgba(var(--rgb-ink), .94); /* what glass becomes under reduced transparency */
  --surface-nav: rgba(var(--rgb-ink), .70);   /* the homepage nav once the page runs under it: its links hold 4.5:1 over any art */
  --surface-sheet: rgba(var(--rgb-ink), .96); /* the phone menu, a near-solid sheet over the page */

  /* Scrims, for laying type over artwork. Weak reads as a veil, strong as a wall. */
  --scrim-weak: rgba(var(--rgb-ink), var(--alpha-7));
  --scrim-shade: rgba(var(--rgb-ink), .55);   /* the shade at the foot of a picture, under its title or chip */
  --scrim-medium: rgba(var(--rgb-ink), .78);
  --scrim-strong: rgba(var(--rgb-ink), .92);
  --scrim-none: rgba(var(--rgb-ink), 0);

  /* Text. Primary and secondary are for words; decorative never carries a word, because at 28% on this
     background it measures 2.4:1 and would fail contrast if it did. */
  --text-primary: #F4F1FA;
  --text-body: rgba(var(--rgb-white), .76);   /* long copy that must stay brighter than meta, as on a pricing card */
  --text-secondary: rgba(var(--rgb-white), var(--alpha-7));
  --text-decorative: rgba(var(--rgb-white), .28);
  --text-on-accent: var(--cc-ink-on-cyan);   /* on a flat cyan fill */
  --text-on-bright: var(--cc-ink);           /* on the brand gradient */

  /* Accent. Cyan is the single accent for marks and pills; purple lives only inside gradients. */
  --accent: var(--cc-cyan);
  --accent-soft: rgba(var(--rgb-cyan), var(--alpha-2));
  --accent-veil: rgba(var(--rgb-cyan), var(--alpha-1));
  --accent-wash: rgba(var(--rgb-cyan), .14);          /* the faintest cyan light on a dark plate */
  --accent-glow: rgba(var(--rgb-cyan), var(--alpha-7));
  --accent-glow-strong: rgba(var(--rgb-cyan), .55);
  --accent-halo: rgba(var(--rgb-cyan), .45);          /* the cast shadow under a cyan element */
  --accent-ring: rgba(var(--rgb-cyan), .2);           /* the soft ring around a hovered primary button */
  --accent-gradient: linear-gradient(135deg, var(--cc-cyan), var(--cc-blue), var(--cc-purple));
  --accent-gradient-text: linear-gradient(135deg, var(--cc-cyan), var(--cc-purple));   /* the wordmark, and the Work bar's lit segment */
  --accent-gradient-glass: linear-gradient(135deg, rgba(var(--rgb-cyan), .8), rgba(var(--rgb-blue), .8), rgba(var(--rgb-purple), .8)); /* a primary pill's face, inside its clear glass ring */
  --accent-gradient-selected: linear-gradient(135deg, rgba(var(--rgb-cyan), .9), rgba(var(--rgb-purple), .9)); /* the selected Proof tab's face (Q25: kept apart from the primary's) */
  --purple-wash: rgba(var(--rgb-purple), .14);
  --purple-soft: rgba(var(--rgb-purple), var(--alpha-2));   /* purple light in a glow, never on its own */
  --purple-veil: rgba(var(--rgb-purple), var(--alpha-1));

  /* Added 2026-09-23 with the seven secondary pages (two more, a purple mark and the pages' old h1 gradient, went unused
     when those pages were rebuilt on 2026-10-11 and were deleted on 2026-10-12, Eric's Q22).
       accent-bright        the one hover colour of every link (since 2026-10-12, review B8.6), and of the FAQ's
                            plus; one step above --accent, and the light stripe of the Pricing slate's arm.
       accent-gradient-bar  the vertical cyan-into-purple rule: How it works' rail. */
  --accent-bright: var(--cc-cyan-light);
  --accent-gradient-bar: linear-gradient(180deg, var(--cc-cyan), var(--cc-purple));

  /* The Geometry Lock punch: a white hot core falling to cyan and then to nothing. */
  --flash-core: #FFFFFF;
  --flash-mid: rgba(226, 248, 255, .94);
  --flash-edge: rgba(var(--rgb-cyan), var(--alpha-7));

  /* Borders, darkest to brightest. Hairlines snap to the ramp: a two point alpha difference on a one pixel
     line is five values out of 255 and is not visible, so these are a system concern rather than a tuned one. */
  --border-faint: rgba(var(--rgb-white), var(--alpha-1));    /* the scrolled nav's top highlight */
  --border-subtle: rgba(var(--rgb-white), var(--alpha-2));
  --border-medium: rgba(var(--rgb-white), var(--alpha-3));   /* the Work bar's unlit segments */
  --border-strong: rgba(var(--rgb-white), var(--alpha-4));
  --border-bright: rgba(var(--rgb-white), var(--alpha-5));
  --border-lit: rgba(var(--rgb-white), var(--alpha-6));   /* the rim of a lit or selected control */
  --border-accent: rgba(var(--rgb-cyan), var(--alpha-4));

  /* Depth. */
  --shadow-glow: 0 24px 80px rgba(var(--rgb-cyan), var(--alpha-3)), 0 8px 30px rgba(var(--rgb-purple), var(--alpha-2));
  --shadow-card: 0 30px 80px -30px rgba(0, 0, 0, .75);
  --shadow-pill: 0 10px 30px -14px rgba(0, 0, 0, .7);
  --shadow-nav: 0 10px 40px rgba(0, 0, 0, .25);
  --shadow-inset-card: inset 0 -14px 24px -16px rgba(0, 0, 0, .55);

  /* Liquid glass, the card plates' material, plus the hover sweep the pills still use. These are the parts of one
     recipe, not general-purpose alphas: Eric tuned them by eye in round 4 and the values are deliberately uneven, so
     they are named by their part rather than snapped onto the ramp above. The pills' own bevel tokens went with the
     move to GlassSurface on 2026-10-04 (git history before that date has them). */
  --glass-bulge-out: rgba(var(--rgb-white), 0);
  --glass-sweep: rgba(var(--rgb-white), .42);
  --glass-plate-rim-top: rgba(var(--rgb-white), .4);
  --glass-plate-rim-bottom: rgba(var(--rgb-white), var(--alpha-2));
  --glass-plate-rim-side: rgba(var(--rgb-white), .07);
  --glass-plate-bulge: rgba(var(--rgb-white), .2);
  --glass-plate-bulge-mid: rgba(var(--rgb-white), var(--alpha-1));
  /* The cursor's specular light on a plate. --spec is the Plates tuner's strength (default .16), which home.js sets on
     the root, so this resolves here; until 2026-10-12 each plate redeclared --spec and the tuner never reached it. */
  --glass-spec: rgba(var(--rgb-white), var(--spec, .16));

  /* GlassSurface, the pill material since 2026-10-04 (Eric asked for React Bits' GlassSurface look on every glass
     button). Its values are kept as they ship in that component, named by part like the bevel above. In Chromium the
     page behind a pill is bent by a per-size SVG filter (assets/glass.js) and the face is clear, lit only by these
     inner glows; Safari and Firefox get the component's own fallback, a bright frosted blur. */
  --gs-glow-edge: rgba(var(--rgb-white), .35);    /* the thin bright rim, inset 0 0 2px 1px */
  --gs-glow-soft: rgba(var(--rgb-white), .15);    /* the wider inner glow, inset 0 0 10px 4px */
  --gs-shade: rgba(var(--rgb-ink), .05);          /* the faint layered depth, inside and out */
  --shadow-gs-inset: inset 0 0 2px 1px var(--gs-glow-edge), inset 0 0 10px 4px var(--gs-glow-soft), inset 0 4px 16px var(--gs-shade), inset 0 8px 24px var(--gs-shade), inset 0 16px 56px var(--gs-shade);
  --shadow-gs-inset-hover: inset 0 0 2px 1px var(--gs-glow-edge), inset 0 0 14px 5px var(--gs-glow-soft), inset 0 4px 16px var(--gs-shade), inset 0 8px 24px var(--gs-shade), inset 0 16px 56px var(--gs-shade);
  --shadow-gs-outer: 0 4px 16px var(--gs-shade), 0 8px 24px var(--gs-shade), 0 16px 56px var(--gs-shade);
  --gs-clear-fill: rgba(var(--rgb-white), var(--glass-tint, 0)); /* Chromium: the face is clear, unless the Liquid tuner's
                                                     pill frost (--glass-tint, set on the root by glass.js) adds some */
  --gs-fb-fill: rgba(var(--rgb-white), .1);       /* fallback: the frosted fill */
  --gs-fb-border: rgba(var(--rgb-white), .2);
  --gs-fb-rim-top: rgba(var(--rgb-white), .2);
  --gs-fb-rim-bottom: rgba(var(--rgb-white), .1);
  --gs-fb-filter: blur(12px) saturate(1.8) brightness(1.2);
  --gs-cta-inset: 2px;                            /* the clear refracting ring left around a primary's gradient */
  /* The comic "Book a demo" button (2026-10-06, Eric's pick of the site's cyan for Eduard Constantin's comic-book
     button): a cyan face over light-cyan halftone stripes, inked in the page's darkest colour, with a purple and blue
     misprint split on hover where the original used magenta and cyan. */
  --comic-face: var(--cc-cyan);
  --comic-face-light: var(--cc-cyan-light);
  --comic-ink: var(--cc-ink);
  --comic-stripe: rgba(var(--rgb-ink), .18);
  --comic-glitch-a: var(--cc-purple);
  --comic-glitch-b: var(--cc-blue);
  --comic-glitch-ink: var(--cc-deep);  /* the label's misprint copy: the light purple vanished on the cyan face */

  /* ============================================================ LAYER 2: SEMANTIC STATE
     One vocabulary for the whole site, so the four states can never be confused with one another:
     hover warms and lifts, focus draws a ring, pressed scales down, selected sets a cyan mark. */
  --focus-ring: var(--cc-cyan);
  --focus-ring-width: 2px;
  --focus-ring-offset: 4px;
  --state-hover-lift: -1px;
  --state-pressed-scale: .97;
  /* A non-replaced inline box ignores transform, so a link inside a paragraph cannot scale on press.
     Those links dim to this instead, which is the same "something happened" signal in the one property
     an inline box will animate. Added 2026-09-23 with the secondary pages, which are mostly prose. */
  --state-pressed-opacity: .72;
  --state-selected: var(--cc-cyan);

  /* Feedback. Derived from the palette rather than stock red and green, which would read as a template. The
     waitlist form is their user since 2026-10-11 (the invalid field's border, the error and success lines). Both
     are checked against --surface-page at 4.5:1. */
  --feedback-error: #FF8C9B;
  --feedback-success: #7FE3C4;
  --disabled-opacity: .4;

  /* ============================================================ TYPE
     The faces are self-hosted; each @font-face lives in the stylesheet that uses it (home.css, pages.css, credits.css,
     comic.css for Dekko, the 404's inline style), all pointing at the same root-absolute files, so a page downloads
     each face once. Instrument Serif (since 2026-10-05, Eric's pick over Syne, which he found generic) is the display
     face: the homepage's headings and, since 2026-10-11, the other pages' h1 and h2, the 404 title and the names in
     the end credits. Dekko letters the comic button and nothing else; Inter carries everything else. Instrument Serif
     ships one weight, a regular (and an italic the site does not use), so display type is set at --weight-display and
     never asks for bold: a browser or a canvas asked for 700 would smear the regular into a fake bold.
     --tracking-display replaces the tight tracking Syne's wide bold needed.

     The scale replaces 25 hand-written sizes, which included every integer from 10 to 18 with no gaps.
     Six body steps and three display steps. Anything that does not fit one of these is a signal that the
     component is wrong, not that the scale needs another value. */
  --font-display: "Instrument Serif", "Instrument Serif Fallback", Georgia, "Times New Roman", serif; /* the stand-in: end of file */
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-comic: "Dekko", "Comic Sans MS", cursive; /* the "Book a demo" comic button only (2026-10-06) */
  --font-mono: ui-monospace, Menlo, monospace;

  --text-2xs: 11px;   /* overlines, status pills, table headings */
  --text-xs: 12px;    /* micro labels and fine print */
  --text-sm: 14px;    /* nav, meta, list items, buttons */
  --text-md: 16px;    /* body copy at every width, and the floor for any paragraph a phone user reads; labels, tags,
                         chips, tab names, in-card links, fact values, status lines and fine print are smaller on
                         purpose (measured at 390, 2026-10-12) */
  --text-lg: 18px;    /* lead paragraphs, the logo, step numbers */
  --text-xl: 20px;    /* card titles that are not display type */

  /* Three fluid display steps, for the serif. Every heading is one of these; there are no bespoke clamps left.
     Instrument Serif is narrow and has no bold, so these are about a fifth larger than the Inter steps the Syne
     headings used; those Inter steps (--display-s, -m, -l) went on 2026-10-12, unused once every page set its
     headings in the serif (Q22). */
  --display-serif-s: clamp(1.6rem, 2.8vw, 2.6rem);   /* card, step and FAQ titles; the other pages' h2 */
  --display-serif-m: clamp(2.25rem, 4.3vw, 3.95rem); /* section titles, the Pillars film's headings, prices, menu links; the other pages' h1 */
  --display-serif-l: clamp(4rem, 8.8vw, 7.9rem);     /* the hero, the Pillars film's title over the sky, and a price on a phone */

  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-display: 400;   /* the display face's only weight */

  --leading-none: 1;       /* numerals and single-line lockups */
  --leading-tight: 1.02;   /* display headings */
  --leading-snug: 1.2;     /* short headings and card titles */
  --leading-normal: 1.55;  /* dense body */
  --leading-loose: 1.7;    /* page body */

  --tracking-display: -.01em; /* the serif headings */
  --tracking-normal: 0;
  /* The gap between normal and wide, added 2026-09-23: capitals that need opening up without reading as a label.
     Its one user since the 2026-10-11 rebuild of the other pages is the comic button's Dekko lettering. */
  --tracking-slight: .06em;
  --tracking-wide: .12em;    /* the other pages' table headings and figure labels */
  --tracking-wider: .18em;   /* the label: team, slate, form, end card and credits labels, the Work facts, the tags on pictures */
  --tracking-widest: .22em;  /* eyebrows and the intro caption */

  /* ============================================================ SPACE, SHAPE, MOTION, LAYERS */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 40px; --space-7: 64px; --space-8: 104px;

  --radius-s: 6px; --radius-m: 14px; --radius-l: 24px; --radius-pill: 9999px;

  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --duration-fast: .2s;
  --duration-base: .35s;
  --duration-slow: .55s;

  --nav-h: 64px;
  --container: 1200px;
  --gutter: 24px;
  --tap-min: 44px;   /* the floor for any touch target */

  /* z-index scale: local stacking inside a component stays at 0 to 3; these are the page layers. */
  --z-nav: 200; --z-menu: 300; --z-intro: 1000; --z-skip: 2000; --z-grain: 9999;
}

@media (max-width: 640px) {
  :root { --gutter: 18px; --space-8: 72px; }
}

/* The stand-in for Instrument Serif while it loads (2026-10-12, Eric's Q4; typeset review finding 9). Both faces are
   preloaded with font-display: swap, so on a slow first visit the headings render in the next face of --font-display
   until the serif arrives. That was Georgia, a third wider than this narrow serif: headings wrapped onto extra lines,
   the page grew by 98 px at 1440 x 900 and by 148 px on a 390 phone, and jumped back on the swap. This face is the
   system Times New Roman (macOS, iOS, Windows) scaled to Instrument Serif's average advance, measured in Chrome over
   the homepage's own serif text (34.06 against 41.50 per 100 px, so 82.06%), with its ascent and descent set to the
   serif's (.99 and .31 em; the overrides are scaled by size-adjust too, hence 99 / .8206 and 31 / .8206). The widths
   match, so lines break in the same places; the cap height cannot match as well (Times is wider for its height), so
   the stand-in reads a little smaller until the swap. Where Times New Roman is missing (Android) local() finds
   nothing and the stack falls through to Georgia and serif as before. It lives here, not beside each page's
   Instrument Serif @font-face, because every page links this file first, the 404 included. */
@font-face { font-family: "Instrument Serif Fallback"; src: local("Times New Roman"), local("TimesNewRomanPSMT");
  size-adjust: 82.06%; ascent-override: 120.64%; descent-override: 37.78%; line-gap-override: 0%; }
