/* ==========================================================================
   tokens.css — the design brief, compiled.
   Alvarez Painting, San Angelo TX.
   Source: runs/alvarez-painting-san-angelo-tx/brief.md (APPROVED, C3
   2026-09-19). Every value below is stated there or computed fresh where the
   brief cites the method and leaves the number to the Builder (its own §0
   framing). THIS FILE IS THE ONLY PLACE RAW VALUES LIVE (house-tech-spec §3).
   ========================================================================== */

:root {

  /* --- Colour — brief §2.1. One deliberate mode: light (playbooks/painters.md
     §6.1: this vertical's market is 11/11 determinable light grounds, 0 dark —
     no dark-hero move is licensed here, so no --color-focus-on-band exists). */

  --scheme: light;

  --color-bg: #F6F1E8;                 /* caliche bone — the §6.1 light ground */
  --color-surface: #EDE5D8;            /* deeper caliche, panels / Index ground */
  --color-ink: #25191B;                /* near-black with a red cast, claret family */
  --color-ink-muted: #5C4A4D;          /* secondary text */
  --color-accent: #6E1F33;             /* claret — the coated plane, numerals, CTA fill */
  --color-accent-hi: #7C2438;          /* plane gradient, light end */
  --color-accent-lo: #5E1A2B;          /* plane gradient, dark end */
  --color-accent-ink: #FBF7F1;         /* text sitting ON claret */

  /* House-required structural colours. */
  --color-border: #DCCFC0;             /* DECORATIVE hairlines only — no contrast floor */
  --color-border-strong: #8C6B72;      /* control boundary, WCAG 1.4.11: 4.18:1 vs bg, 3.77:1 vs surface */

  --color-focus: #6E1F33;              /* = --color-accent; :focus-visible ring, 9.79:1 vs bg */
  /* --color-focus-on-band: …; — not declared. playbooks/painters.md §6.1: no dark band on this site. */

  --color-selection-bg: #6E1F33;
  --color-selection-ink: #FBF7F1;


  /* --- Typography — brief §2.2. Two families, three woff2 files (variable,
     under the ≤4 cap). Both SIL OFL 1.1, self-hosted, Google Fonts, subset to
     the house declared safe range (house-tech-spec §8). Bodoni Moda carries
     wght 400 (index numerals, tally) and 500 (h1, section heads), plus its
     italic instance (Index of 85 verbatim quotes, brief §3.4). Hanken Grotesk
     carries wght 400 (body) and 700 (CTA label, sec-head labels, h4 row
     titles). `font-variation-settings` on this site carries `opsz` only,
     never `wght` (house-tech-spec §8's trap) — weight is set with
     `font-weight` everywhere. */

  --font-display: 'Bodoni Moda', 'Bodoni Moda Fallback', Georgia, serif;
  --font-body: 'Hanken Grotesk', 'Hanken Grotesk Fallback', Arial, sans-serif;

  --font-weight-body: 400;
  --font-weight-body-strong: 700;
  --font-weight-display: 500;          /* h1, h2, h3 (section heads) — brief §2.2 */
  --font-weight-display-num: 400;      /* Index tally + row numerals only — brief §2.2 */

  /* No font-variation-settings anywhere on this site: `font-optical-sizing:
     auto` is the CSS default for a variable font carrying an `opsz` axis, so
     Bodoni Moda's optical size tracks its rendered font-size automatically
     with no explicit axis value to invent — and house-tech-spec §8's
     `wght`-in-`font-variation-settings` trap (dead `font-weight` on every
     descendant that doesn't re-declare it) cannot occur on a property this
     site never sets. Weight is set with `font-weight` everywhere. */

  /* --- Type scale — brief §2.3, computed at every stated point (375px and
     1440px minimum, design-rules §5). Fixed tokens state the same number at
     every width and mean it. */

  --text-hero: clamp(2.125rem, 1.377rem + 3.192vw, 4.25rem);   /* 34px @375 -> 68px @1440 (ceiling) */
  --text-h2: clamp(1.5rem, 1.148rem + 1.502vw, 2.5rem);         /* 24px @375 -> 40px @1440 (ceiling) */
  --text-tally: clamp(2.75rem, 1.870rem + 3.756vw, 5.25rem);    /* 44px @375 -> 84px @1440 (ceiling) */
  --text-index: clamp(1.125rem, 1.037rem + 0.376vw, 1.375rem);  /* 18px @375 -> 22px @1440 (ceiling) */
  --text-eyebrow: 0.6875rem;           /* 11px fixed, every width */
  --text-body: clamp(1rem, 1.4vw, 1.0625rem); /* house default, unchanged — 16px @375 -> 17px @1440 */
  --text-small: 0.875rem;              /* 14px fixed, every width */

  /* House-structural sizes the brief's typography table does not itemise
     (site-header__brand, .btn--quiet etc. are shared chrome, not archetype
     content) — house default fluid scale kept unmodified; brief argues no
     override for either. */
  --text-h3: clamp(1.3rem, 3vw, 1.75rem);
  --text-lead: clamp(1.125rem, 2.2vw, 1.375rem);

  --leading-tight: 1.05;
  --leading-snug: 1.25;
  --leading-body: 1.6;

  --tracking-tight: -0.02em;
  --tracking-normal: 0em;
  --tracking-wide: 0.08em;             /* eyebrows / small caps */


  /* --- Space — house scale, unchanged (brief §3 argues no override). ------ */

  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2.5rem;
  --space-xl: 4rem;
  --space-2xl: 6rem;
  --space-3xl: 9rem;

  /* The ONE token setting space between sections (brief §3: --space-2xl,
     "generous space… needs air around each block to read as calm rather than
     dense — a step up the house scale"). Fixed, not fluid: 96px, every width. */
  --section-gap: var(--space-2xl);


  /* --- Layout — house defaults; the brief argues no override except the
     hero-title measure below. -------------------------------------------- */

  --layout-container: 72rem;
  --layout-measure: 62ch;
  --layout-gutter: clamp(1.25rem, 5vw, 3rem);
  --layout-tap-min: 44px;

  /* Poster-hero archetype (brief §3): the h1 carries the first screen and
     wraps across several lines by design. A percentage keeps the column
     width-relative rather than face-relative — `ch` is the current font's own
     "0" glyph, so a ch-based cap reflows the moment the display face swaps in
     over its fallback (a font-swap-triggered reflow, the documented house
     caution — see 3-elements-landscaping-asheville-nc's site.css). Builder-
     derived to the brief's own "~13-14 char/line" description; re-measured
     against the actual approved headline render, not assumed (brief §3.2). */
  --hero-title-measure: 68%;

  /* The living-hero field (brief §5, "the second coat evens"). Brief §3.2's
     measured table states 300px (18.75rem) at 375px width, <64em. Builder-
     derived growth above that breakpoint, same latitude as the sibling
     painter site's --hero-field-height-lg: no colour, font, archetype or
     motion value is set here, only the field's own height. */
  --hero-field-height: 18.75rem;                        /* 300px, brief §3.2, <64em */
  --hero-field-height-lg: clamp(18.75rem, 30vw, 32rem);  /* Builder-derived, >=64em */

  /* The living-hero overlay's own execution geometry (brief §5) — Builder-
     derived choreography values, same latitude as the sibling painter
     site's --mote-size/--mote-drift-*: no colour, font, archetype or motion
     TIMING value is set here (the three durations above are the brief's own
     numbers), only the overlay elements' own texture scale and travel. */
  --hero-nap-cell: 0.5rem;             /* roller-nap stipple dot pitch */
  --hero-nap-dot: 0.0625rem;           /* the stipple dot's own radius stop */
  --hero-nap-dot-edge: 0.09375rem;     /* the dot's soft-edge radius stop */
  --hero-sheen-width: 45%;             /* the drifting sheen band's own inline size */

  /* The Index of 85's numeral rule (brief §2.4's 3px claret rule, borrowed
     per the registry row's own description — "the Index of 85 borrows the
     same rule to set its running numerals rather than any card or icon").
     Builder-derived mark length; the rule's own thickness is the house
     --border-thick token already declared above, unchanged. */
  --index-num-rule-length: 1.5rem;


  /* --- Radius / shadow / border — house defaults; brief argues no override,
     consistent with editorial-modern's restraint. ------------------------- */

  --radius-none: 0;
  --radius-sm: 2px;
  --radius-md: 6px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  --shadow-none: none;
  --shadow-sm: 0 1px 2px rgb(37 25 27 / 0.06);
  --shadow-md: 0 6px 24px rgb(37 25 27 / 0.09);
  --shadow-lg: 0 24px 60px rgb(37 25 27 / 0.14);

  --border-hairline: 1px;
  --border-thick: 3px;                 /* the claret section rule — brief §2.4 */
  --border-style: solid;


  /* --- Motion — house architecture tokens, unchanged, driving the standard
     IntersectionObserver reveal (Services rows, Index of 85 rows). -------- */

  --duration-fast: 140ms;
  --duration-base: 320ms;
  --duration-slow: 640ms;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  --reveal-shift: 1.25rem;
  --reveal-stagger: 90ms;

  /* The one signature move, "the second coat evens" (brief §5). One-shot on
     load, then two independent, non-synchronised ambient loops — different
     periods so they never lock into a visible combined cycle (brief §5 / §0). */
  --duration-pass: 2.4s;               /* the one-shot first-coat-to-even sweep, named by the brief */
  --duration-sheen: 8.6s;              /* wet-sheen drift, continuous */
  --duration-nap: 6.4s;                /* roller-nap stipple opacity pulse, continuous */

  /* --- Z layers ----------------------------------------------------------- */
  --z-base: 0;
  --z-header: 100;
  --z-nav-panel: 200;
  --z-skip-link: 300;
}

/* --------------------------------------------------------------------------
   @font-face — brief §2.2. Three files, two families, SIL OFL 1.1,
   self-hosted, Google Fonts, subset to the house declared safe range
   (house-tech-spec §8). Bodoni Moda and Hanken Grotesk both ship as variable
   instances restricted to wght 400..700 (the only weights this brief uses),
   opsz 6..96 kept on Bodoni Moda.

   Metrics-matched fallbacks: computed with scripts/font-metrics.mjs against
   each real face's own pinned static instance (wght=400 opsz=11 for the
   Bodoni Moda cuts; wght=400 and wght=700 for the two Hanken Grotesk cuts).
   Bodoni Moda is measured against Gelasio (Google Fonts' own metric-
   compatible open substitute for Georgia — Georgia itself is not freely
   distributable, so no local .ttf of it exists to measure against; same
   method as the sibling painter site, j-r-sanchez-painting-san-angelo-tx).
   Hanken Grotesk is measured against Liberation Sans (Red Hat's stated
   metric-compatible clone of Arial).

   TWO Hanken Grotesk Fallback cuts, not one — same reasoning the sibling site
   recorded: this hero puts a 700-weight primary CTA directly above the
   300px-tall claret field (brief §3.2's house DOM order — eyebrow, h1, CTA,
   field), so the width delta between a browser's un-embellished regular
   fallback and the real drawn Hanken Grotesk 700 glyphs is exactly the kind
   of mismatch that moves the field. The 700 cut is measured against a wght=700
   pinned instance of the real variable font, not against the 400 cut's
   numbers, for the same reason. Bodoni Moda gets ONE cut: its h1 (weight 500)
   and index numerals (weight 400) both resolve to the same single fallback
   face regardless of requested weight — Gelasio ships no local weight between
   400 and 700, so there is nothing for a second cut to differentiate here,
   unlike Hanken Grotesk where a real local Bold face exists and is reachable. */

@font-face {
  font-family: 'Bodoni Moda Fallback';
  src: local('Gelasio');
  size-adjust: 104.88%;
  ascent-override: 107.26%;
  descent-override: 38.14%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Bodoni Moda Fallback';
  src: local('Gelasio Italic');
  font-style: italic;
  size-adjust: 96.29%;
  ascent-override: 116.84%;
  descent-override: 41.54%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Hanken Grotesk Fallback';
  src: local('Arial'), local('Liberation Sans');
  font-weight: 400;
  size-adjust: 101.56%;
  ascent-override: 98.47%;
  descent-override: 29.84%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Hanken Grotesk Fallback';
  src: local('Arial Bold'), local('Liberation Sans Bold');
  font-weight: 700;
  size-adjust: 95.41%;
  ascent-override: 104.81%;
  descent-override: 31.76%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Bodoni Moda';
  src: url('../assets/fonts/bodoni-moda-roman-variable-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0020-007E, U+00A0, U+00A9, U+00AE, U+2122, U+00B0, U+00B7,
    U+00BF, U+00C0-00FF, U+2010-2015, U+2018-201A, U+201C-201E, U+2026, U+2032-2033;
}

@font-face {
  font-family: 'Bodoni Moda';
  src: url('../assets/fonts/bodoni-moda-italic-variable-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0020-007E, U+00A0, U+00A9, U+00AE, U+2122, U+00B0, U+00B7,
    U+00BF, U+00C0-00FF, U+2010-2015, U+2018-201A, U+201C-201E, U+2026, U+2032-2033;
}

@font-face {
  font-family: 'Hanken Grotesk';
  src: url('../assets/fonts/hanken-grotesk-variable-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0020-007E, U+00A0, U+00A9, U+00AE, U+2122, U+00B0, U+00B7,
    U+00BF, U+00C0-00FF, U+2010-2015, U+2018-201A, U+201C-201E, U+2026, U+2032-2033;
}
