/* ==========================================================================
   tokens.css — the design brief, compiled.
   J&R Sanchez Painting, San Angelo TX.
   Source: runs/j-r-sanchez-painting-san-angelo-tx/brief.md (APPROVED,
   C3 2026-09-18). Every value below is stated there. Nothing here was chosen
   here. THIS FILE IS THE ONLY PLACE RAW VALUES LIVE (house-tech-spec §3).
   ========================================================================== */

:root {

  /* --- Colour — brief §2.2. 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: #F7F1E6;                 /* warm bone/parchment — page ground */
  --color-surface: #EFE6D4;            /* cards, Index of Care rows, form fields */
  --color-ink: #192537;                /* body + heading text — their own real logo navy, echoed as ink */
  --color-ink-muted: #4B5566;          /* secondary text, captions */
  --color-accent: #9C7A44;             /* aged brass — decorative + large-text only, brief §2.3 */
  --color-accent-ink: #FFFFFF;         /* text/icons ON a solid accent fill — large-text/icon only */
  --color-accent-wash: #F3E9D6;        /* light brass tint — badge/tag fills; text on it stays --color-ink */

  /* House-required structural colours. */
  --color-border: #E3D8C0;             /* DECORATIVE hairlines only — no contrast floor */
  --color-border-strong: #4B5566;      /* = --color-ink-muted, reused deliberately: a control's own boundary, WCAG 1.4.11 */

  --color-focus: #192537;              /* = --color-ink; :focus-visible ring */
  /* --color-focus-on-band: …; — not declared. playbooks/painters.md §6.1: no dark band on this site. */

  --color-selection-bg: #192537;
  --color-selection-ink: #F7F1E6;

  /* Primary button roles (brief §2.2) — both equal --color-ink / white,
     stated as their own tokens because they are the house-required button slot. */
  --color-cta-fill: #192537;
  --color-cta-text: #FFFFFF;


  /* --- Typography — brief §2.4. Two families, four woff2 (exactly the §5
     cap). Marcellus ships ONE static instance (400, upright, no italic
     master) — no synthetic italic is ever applied to --font-display anywhere
     on this site (brief §2.4's own instruction). Mulish ships 400, 700 and a
     true drawn 400 italic; the one italic use on the page (the review quote)
     is that real Mulish italic file, never a browser-synthesized slant. --- */

  --font-display: 'Marcellus', 'Marcellus Fallback', 'Libre Caslon Text', Georgia, serif;
  --font-body: 'Mulish', 'Mulish Fallback', -apple-system, sans-serif;

  --font-weight-body: 400;
  --font-weight-body-strong: 700;
  --font-weight-display: 400;

  /* --- Type scale — brief §2.5, computed at every breakpoint the token
     declares. Fixed tokens state the same number at 375 and 1440 and mean it. */

  --text-hero: clamp(2.15rem, 1.55rem + 2.6vw, 3.6rem);      /* 34.55px @375 -> 57.6px @1440 (ceiling) */
  --text-h2: clamp(1.35rem, 1.15rem + 0.9vw, 2rem);           /* 21.78px @375 -> 31.36px @1440 */
  --text-h3: clamp(1.15rem, 1.02rem + 0.6vw, 1.5rem);         /* 18.57px @375 -> 24px @1440 (ceiling) */
  --text-lead: clamp(1.05rem, 0.95rem + 0.5vw, 1.2rem);       /* 17.08px @375 -> 19.2px @1440 (ceiling) */
  --text-index-num: clamp(1.75rem, 1.3rem + 2vw, 2.5rem);     /* 28.3px @375 -> 40px @1440 (ceiling) */
  --text-body: 1rem;                                          /* 16px fixed */
  --text-small: 0.875rem;                                     /* 14px fixed */
  --text-eyebrow: 0.78rem;                                    /* 12.48px fixed */

  --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 — brief §3.1, the house scale unchanged. --------------------- */

  --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.1: --space-2xl,
     "restraint, whitespace, refined serif, muted" — quiet-premium's own
     argument for the more generous step). Fixed, not fluid, at every
     breakpoint: 96px always. */
  --section-gap: var(--space-2xl);


  /* --- Layout — house defaults; the brief argues no override. ------------- */

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

  /* --- Hero field geometry (brief §3.2/§3.3). Mobile/tablet (<64em): fixed
     300px height, full content width — brief §3.3's first-screen arithmetic
     table states this number exactly and the Builder verifies it against the
     render. Desktop (>=64em, the house's own breakpoint): the split-hero
     archetype's asymmetric two-column shape — Builder-derived execution
     within the archetype the brief names (design-rules §7's "text block vs.
     visual block, asymmetric weight"), not a new aesthetic decision: no
     colour, font, archetype or motion value is set here. The image column is
     narrower than the text column (asymmetric, text-forward), and its width
     is independent of the anchor's OWN internal composition (brief §3.2's
     "brass fills ~2/3 of the panel", a property of the generated image
     itself, unaffected by how wide the panel's layout slot is). */
  --hero-field-height: 18.75rem;       /* 300px, brief §3.3's stated fixed mobile field height, <64em */
  --hero-field-inline-size: 26rem;     /* 416px, Builder-derived desktop column width, >=64em */
  --hero-field-height-lg: 30rem;       /* 480px, Builder-derived minimum desktop field height, >=64em */

  /* The seam overlay's CSS device (brief §5's "the seam holds light" — the
     specular sweep track and the two brass motes composite OVER the static
     generated image, on the brass side of the seam). --hero-seam-inset is
     the sweep track's horizontal position as a percentage of the panel's own
     width, tuned to the generated image's actual seam position (Builder
     execution, per brief §3.2's instruction that the split is verified
     against the rendered asset, not assumed). --hero-seam-width is the
     brief's own stated fixed 2px ornament (§2.5's em-based-ornament check). */
  --hero-seam-inset: 38%;              /* measured against the actual generated hero asset (bone
                                           field ~0-38% of the panel width, brass ~38-100%) */
  --hero-seam-width: 2px;              /* the brief's own stated fixed cut-in-line ornament (§2.5) */

  /* The two brass motes' geometry (brief §5) — Builder-derived choreography
     values, not itemised in the brief's token table (same latitude as
     garden-art's --stem-leaf-* tokens): a fixed diameter and a fixed drift
     distance, shared by both motes; independence comes from --duration-mote-1/2
     and --mote-2-delay above, never from a different path shape. */
  --mote-size: 0.4375rem;              /* 7px */
  --mote-drift-x: 0.625rem;            /* 10px */
  --mote-drift-y: 0.875rem;            /* 14px */
  --hero-sweep-glow-width: 2.5rem;     /* 40px — the travelling highlight's own width, wider than
                                           the static --hero-seam-width line it rides along */

  /* Index of Care's numeral column (brief §2.5's repeated-ornament minimum:
     56px at >=48em, stated minimum 40px, below which the row collapses to a
     single column and the numeral moves above its heading). */
  --index-num-col: 3.5rem;             /* 56px, >=48em */
  --index-num-col-min: 2.5rem;         /* 40px, the stated minimum — never actually reached (brief §2.5) */

  /* Services list's two supporting images (Cabinet Painting, Exterior
     Painting) — a small contextual thumbnail beside those two lines only,
     never a per-item icon set (design-rules §4's ban; brief §3.1 row 2).
     Builder-derived execution size, not itemised in the brief's token table. */
  --service-img-size: 4.5rem;          /* 72px square */


  /* --- Radius / shadow / border — house defaults; brief argues no override,
     consistent with quiet-premium's restraint (no card grid, no drop-shadow
     device anywhere on this site). --------------------------------------- */

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

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

  --border-hairline: 1px;
  --border-thick: 3px;
  --border-style: solid;


  /* --- Motion — brief §5. House architecture tokens, unchanged, driving the
     standard IntersectionObserver reveal (Services, Index of Care, review
     quote, form field stack). ------------------------------------------- */

  --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 seam holds light" (brief §5, bespoke,
     hero-only, ambient on load). No two share a timing origin or duration. */
  --duration-sweep: 6.5s;              /* the specular sweep's continuous loop */
  --duration-mote-1: 8.4s;
  --duration-mote-2: 7.1s;
  --mote-2-delay: 1.2s;                /* offsets mote 2 from mote 1 */

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

/* --------------------------------------------------------------------------
   @font-face — brief §2.4. Four files, two families, SIL OFL 1.1,
   self-hosted, Google Fonts, subset to the house declared safe range
   (house-tech-spec §8). Marcellus ships exactly one static instance (400
   upright) — no italic master exists, so no italic is ever set on
   --font-display anywhere on this site. Mulish ships 400, 700 and a true
   drawn 400 italic (the review quote's face).

   Metrics-matched fallbacks: computed with scripts/font-metrics.mjs.
   Marcellus 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; Gelasio is built to
   Georgia's exact metrics for precisely this purpose, same method as
   garden-art-landscaping-fort-collins-co). Mulish is measured against
   Liberation Sans (Red Hat's stated metric-compatible clone of Arial).

   TWO Mulish Fallback declarations, not one — found by measurement, not
   assumed. The single-cut approach 3-elements-landscaping-asheville-nc uses
   (tune against 400, accept the residual on 700) reasons that a 700-weight
   run is always short. That reasoning breaks here: this hero puts a
   700-weight primary CTA and a 700-weight eyebrow directly ABOVE the
   300px-tall hero field (brief §3.3's house order), so even the small
   width delta between a browser's SYNTHETIC bold of the regular fallback
   and the REAL drawn Mulish 700 glyphs is enough to move the field.
   Measured empirically on the rendered build (`node scripts/qa/lighthouse.mjs`,
   corroborated by blocking mulish-700-latin.woff2 outright and watching CLS
   drop from 0.151 to 0.000): the 700 cut is the one andonly cause. A second
   `font-weight: 700` fallback face, measured against Liberation Sans Bold
   (Arial Bold's metric-compatible clone) rather than reusing the 400 cut's
   numbers, removes the mismatch at its source instead of racing the network
   for it. The 400 cut (body, lead, facts) and the italic cut (the one
   review quote, below the fold) keep the single-cut reasoning — neither
   sits above a large element the way the CTA row does. -------------------- */

@font-face {
  font-family: 'Marcellus Fallback';
  src: local('Georgia');
  size-adjust: 103.85%;
  ascent-override: 93.8%;
  descent-override: 26.94%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Mulish Fallback';
  src: local('Arial'), local('Liberation Sans');
  font-weight: 400;
  size-adjust: 104.47%;
  ascent-override: 96.2%;
  descent-override: 23.93%;
  line-gap-override: 0%;
}

/* The 700 cut — measured against Liberation Sans Bold, not the 400 numbers
   above. Carries the hero's primary CTA and eyebrow, both above the 300px
   field (see the block comment above). */
@font-face {
  font-family: 'Mulish Fallback';
  src: local('Arial Bold'), local('Liberation Sans Bold');
  font-weight: 700;
  size-adjust: 100.26%;
  ascent-override: 100.24%;
  descent-override: 24.93%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Marcellus';
  src: url('../assets/fonts/marcellus-400-latin.woff2') format('woff2');
  font-weight: 400;
  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: 'Mulish';
  src: url('../assets/fonts/mulish-400-latin.woff2') format('woff2');
  font-weight: 400;
  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: 'Mulish';
  src: url('../assets/fonts/mulish-700-latin.woff2') format('woff2');
  font-weight: 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: 'Mulish';
  src: url('../assets/fonts/mulish-400italic-latin.woff2') format('woff2');
  font-weight: 400;
  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;
}
