/* ==========================================================================
   tokens.css — the design brief, compiled.

   bend-lawn-service-bend-or — brief.md v1 (C3 APPROVED 2026-08-27), family
   `bold-industrial`, archetype `split-hero`, signature "the bid stamps down".
   Every value below cites brief.md by section. Builder execution fills are
   flagged inline exactly where they occur — never a silent choice.
   ========================================================================== */

:root {

  /* --- Colour (brief §3.2). Derivation: dossier §4.5 has no real-world brand
     colour (recorded empty, not a gap) → local character (Bend's high-desert
     lodgepole-pine register) → the playbook's green/growth anchor taken
     directly in the dominant hue → family norms (bold-industrial, 0/18
     landscaping rows). Contrast computed in brief §4.1–§4.2. */

  --scheme: light;

  --color-bg:          #F2E9D8;  /* manila-cream */
  --color-surface:     #E8DCC3;  /* duplicate-sheet tone — every ticket/card ground */
  --color-ink:         #241E17;  /* typewriter-ink charcoal */
  --color-ink-muted:   #5C5140;  /* muted brown-grey */
  --color-accent:      #163B29;  /* DOMINANT — lodgepole, hsl(150°, 45%, 16%) */
  --color-accent-ink:  #F7F2E4;  /* text ON accent fill (CTA, imprint chip) */

  --color-border:      #7D7152;  /* khaki-ink hairline — every ticket row divider */
  --color-focus:       #163B29;  /* :focus-visible ring — = accent, brief §4.2 rows 10–11 */

  /* One light register throughout, no dark band anywhere on this site
     (brief §5.1 rule 6) — --color-focus-on-band is not needed. */

  --color-selection-bg:  #163B29;
  --color-selection-ink: #F7F2E4;

  /* No second green token (--color-moss or equivalent) is introduced — the
     playbook's anchor is carried directly in --color-accent itself
     (brief §3.2's note). This site has no other brief-specific colours. */


  /* --- Typography (brief §2). Two families:
       Anton   — SIL OFL 1.1, static, wght 400 only, no italic.
       Barlow  — SIL OFL 1.1. THE BRIEF NAMES THIS "variable: wght 400–600,
       one file". Google Fonts' own metadata (fonts.google.com/metadata/fonts,
       read at build time) records Barlow's axes as [] — it ships NO variable
       instance from the licensed source. Substituted with TWO STATIC
       instances (400, 600) of the identical family instead of one variable
       file: same face, same two weights, same roles, only the delivery
       mechanism changes (a mechanical substitution, not a design choice —
       house-tech-spec §7.1 treats font delivery as delivery-mechanical work).
       File count is now 3 (Anton 400 + Barlow 400 + Barlow 600), still inside
       design-rules §5's ≤4 woff2 / ≤2 family caps, and the combined payload is
       comfortably under §2.6's 100 KB total. FLAGGED in the build report as a
       brief inaccuracy for Art Director awareness — no token, weight or role
       assignment changed. */

  --font-display: 'Anton', 'Anton Fallback', 'Arial Narrow', Arial, sans-serif;
  --font-body:    'Barlow', 'Barlow Fallback', 'Helvetica Neue', Arial, sans-serif;

  --font-weight-body:        400;
  --font-weight-body-strong: 600;   /* ticket-line labels, h3 section heads */
  --font-weight-display:     400;   /* Anton has one static weight */

  /* --- Type scale — every declared breakpoint, both clamp ends (brief §2.9–§2.10) */

  --text-display: clamp(2.0rem, 1.3rem + 3.0vw, 3.75rem);
  --text-h2:      clamp(1.375rem, 1.10rem + 1.17vw, 2.125rem);
  --text-lead:    clamp(1.0625rem, 1.0rem + 0.27vw, 1.375rem);
  --text-body:    1rem;      /* 16px, fixed at every width */
  --text-eyebrow: 0.75rem;   /* 12px, fixed at every width */
  --text-micro:   0.6875rem; /* 11px, fixed at every width */

  --leading-tight:   1.08;  /* h1 */
  --leading-snug:    1.20;  /* h3 section heads */
  --leading-lead:    1.55;
  --leading-body:    1.62;
  --leading-eyebrow: 1.35;

  --tracking-wide: 0.16em;  /* eyebrows, kickers, section heads, the BID imprint */

  /* base.css's house h1–h4 rule reads --tracking-tight for every heading
     level. The brief gives Anton no tracking value at all (it is a very
     condensed face already) — set to the neutral no-op rather than an
     invented number. */
  --tracking-tight: normal;


  /* --- Space scale (brief §3.3) --------------------------------------- */

  --space-3xs: 0.25rem;  /* 4px */
  --space-2xs: 0.5rem;   /* 8px */
  --space-xs:  0.75rem;  /* 12px */
  --space-sm:  1rem;     /* 16px */
  --space-md:  1.5rem;   /* 24px */
  --space-lg:  2.5rem;   /* 40px */
  --space-xl:  4rem;     /* 64px */
  --space-2xl: 6rem;     /* 96px */
  /* --space-3xl keeps the skeleton default (9rem) — the brief does not use it
     anywhere except the form textarea's minimum height, unchanged. */
  --space-3xl: 9rem;

  --section-gap: var(--space-xl);   /* = 64px, at EVERY width (brief §5.4) */


  /* --- Layout (brief §5.3) --------------------------------------------- */

  --layout-container: 75rem;   /* 1200px, caps + centres at ≥1440 */
  --layout-measure:   62ch;    /* skeleton default — thanks.html prose only */
  --layout-tap-min:   44px;

  /* Gutter is STEPPED at the declared breakpoints, not fluid — the brief's
     own content-column arithmetic (335px@375, 576px@640) only holds if the
     gutter is exactly 20/32/48 at those widths, not a continuously
     interpolated value. */
  --layout-gutter: 20px;

  /* Sticky-chrome geometry (brief §6, "Sticky chrome (both pages)"): the
     expiry bar (44px, = --layout-tap-min, preview.css) sits above a sticky
     56px + 1px header. Needed for the sticky offsets and each section's
     scroll-margin so an in-page jump (the hero CTA → #contact) does not
     land under the fixed chrome. */
  --header-height: 3.5rem;  /* 56px */


  /* --- Hero geometry (brief §5.2, §5.3, §5.5) --------------------------- */

  --hero-field-height: 320px;         /* < 1024, fixed */
  --hero-text-col-width: 460px;       /* ≥ 1024, fixed narrow text column */

  --hero-pad-top: 20px;               /* < 1024 .hero padding-block-start */
  --hero-gap-eyebrow-h1: var(--space-xs);  /* 12px < 1024 */
  --hero-gap-h1-cta: 18px;                 /* < 1024 — not on the general scale */
  --control-height-primary: 52px;          /* < 1024 */

  /* Hero ticket card rotation. brief §7.4 states -2deg "matching the tile",
     but that value described the C2 tile's flat 2-D mock, not this
     photographic asset's own depicted ticket — the same section requires
     the Builder to measure "the generated asset's own ticket bounds" and
     register against THOSE. Re-measured at QA round 1 directly against the
     shipped 1500×1006 hero asset (four corners, see site.css's
     .hero__ticket comment): the photo's own ticket sits at roughly -10.5deg,
     not -2deg. Updated here, once, with the registration math recorded in
     site.css and README.md rather than only in this comment. Drawn as a
     literal shape geometry, never a token-driven UI radius (brief §3.2). */
  --hero-ticket-rotate: -10.5deg;

  /* Wordmark size (brief §6, sticky chrome): 14px < 1024, 17px ≥ 1024 — a
     stepped value the fluid scale has no row for. */
  --text-wordmark: 14px;

  /* Ornament geometry (brief §8.2): the stamp, pencil and paperclip are
     small CSS/SVG shapes carried from the tile — the brief gives their
     motion and colour exactly, not their pixel dimensions. Sized here as a
     Builder execution fill (interpolated proportionally from the hero field
     height already stated, never a new design choice), flagged in the build
     report. Drawn as literal shape geometry, never a token-driven UI radius
     (brief §3.2) — dedicated tokens, not a reused --radius-* step. */
  --ornament-stamp-head-w: 2.5rem;
  --ornament-stamp-head-h: 1.75rem;
  --ornament-stamp-head-radius: 3px;
  --ornament-stamp-handle-w: 0.875rem;
  --ornament-stamp-handle-h: 2.125rem;
  --ornament-stamp-handle-radius: 6px;
  --ornament-pencil-w: 4.5rem;
  --ornament-pencil-h: 0.5rem;
  --ornament-pencil-radius: 4px;
  --ornament-clip-w: 1.375rem;
  --ornament-clip-h: 2.125rem;
  /* --ornament-clip-radius retired at QA round 1: the clip is now a stroked
     SVG path (site.css .hero__clip), not a CSS border-radius shape, so no
     radius token applies to it. */

  /* --- Radius / shadow / border (brief §3.2) ---------------------------- */

  --radius-none: 0;
  /* --radius-sm/md/lg/pill keep their skeleton values and have ZERO call
     sites on this site (brief §3.2's own note) — nothing here rounds. */
  --radius-sm:   2px;
  --radius-md:   6px;
  --radius-lg:   16px;
  --radius-pill: 999px;

  --shadow-none: none;   /* NO SHADOW IS USED ANYWHERE ON THIS SITE */
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: none;

  --border-hairline: 1px;
  --border-thick:    3px;   /* skeleton default — focus ring outline width */
  --border-style:    solid;

  /* --- Motion (brief §8) ------------------------------------------------- */

  --duration-fast: 140ms;   /* focus/hover transitions */
  --duration-base: 320ms;   /* the scroll reveal */
  --ease-standard: cubic-bezier(.2, .6, .2, 1);

  /* base.css's reveal rule reads --duration-slow / --ease-out by name; both
     are set to the brief's single reveal timing so there is one real value
     behind two token names rather than an invented third tier. */
  --duration-slow: var(--duration-base);
  --ease-out:      var(--ease-standard);
  --ease-in-out:   var(--ease-standard);

  --reveal-shift:   12px;    /* brief §8.1: translateY(12px) → 0 */
  --reveal-stagger: 60ms;    /* brief §8.1: staggered 60ms within a group */

  /* The signature move — carried forward from the winning tile unchanged
     (brief §8.2). */
  --duration-press-sequence: 5000ms;  /* one-shot, never repeats */
  --loop-pencil-rock: 9s;
  --loop-clip-glint: 12s;

  /* --- Z layers (skeleton default, unchanged) --------------------------- */
  --z-base: 0;
  --z-header: 100;
  --z-nav-panel: 200;
  --z-skip-link: 300;
}

/* Gutter steps (brief §5.3's declared breakpoints). */
@media (min-width: 40em) {           /* 640px */
  :root { --layout-gutter: 32px; }
}
@media (min-width: 64em) {           /* 1024px */
  :root {
    --layout-gutter: 48px;
    --hero-field-height: 400px;           /* ≥ 1024, fixed */
    --hero-pad-top: var(--space-xl);      /* 64px */
    --hero-gap-eyebrow-h1: var(--space-md); /* 24px */
    --hero-gap-h1-cta: var(--space-md);     /* 24px */
    --control-height-primary: 56px;
    --text-wordmark: 17px;
  }
}

/* --------------------------------------------------------------------------
   @font-face — self-hosted woff2, latin subset, static instances only.
   Anton: SIL OFL 1.1, Vernon Adams. Barlow: SIL OFL 1.1, Jeremy Tribby.
   Subset to the house declared range, identical on all three faces
   (house-tech-spec §8; brief §2.5).

   COVERAGE GAP, recorded per §2.5 rather than silently shipped: U+2011 is
   absent from Anton; U+2011, U+2012 and U+2015 are absent from both Barlow
   instances (measured with a fontTools cmap read against the shipped woff2,
   2026-08-27). None of the three render anywhere in this site's copy — the
   only separator used is U+00B7 (·), and copy.md carries no em dash — so the
   gap is latent, not a mid-sentence split. Not narrowed, per house-tech-spec
   §8's reasoning: narrowing would make the declared range per-site, which is
   the one property it exists not to have.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Anton';
  src: url('../assets/fonts/anton-400.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: 'Barlow';
  src: url('../assets/fonts/barlow-400.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: 'Barlow';
  src: url('../assets/fonts/barlow-600.woff2') format('woff2');
  font-weight: 600;
  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;
}

/* --- Metrics-matched fallbacks (house-tech-spec §8, brief §2.4). Donors:
   Liberation Sans Narrow (Anton — the metric-compatible open replacement for
   Arial Narrow, per Red Hat's own compatibility mapping; no Arial Narrow
   binary is reachable on the Linux build host to measure directly), Liberation
   Sans / Liberation Sans Bold (Barlow — the metric-compatible open
   replacement for Arial / Arial Bold). size-adjust / ascent-override /
   descent-override / line-gap-override computed from the real shipped
   instances' own hhea + OS/2 metrics against the donors' own tables
   (scripts/font-metrics.mjs, the fontaine algorithm), English-letter-frequency
   weighted. Measured numbers recorded in README.md. Verified against
   Lighthouse CLS: 0.000 (see README.md). */

@font-face {
  font-family: 'Anton Fallback';
  src: local('Arial Narrow'), local('Arial');
  font-weight: 400;
  font-style: normal;
  size-adjust: 112.34%;
  ascent-override: 104.70%;
  descent-override: 29.29%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Barlow Fallback';
  src: local('Helvetica Neue'), local('Arial');
  font-weight: 400;
  font-style: normal;
  size-adjust: 96.96%;
  ascent-override: 103.14%;
  descent-override: 20.63%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Barlow Fallback';
  src: local('Helvetica Neue Bold'), local('Arial Bold'), local('Arial');
  font-weight: 600;
  font-style: normal;
  size-adjust: 91.42%;
  ascent-override: 109.38%;
  descent-override: 21.88%;
  line-gap-override: 0%;
}
