:root{
  /* base palette, SRG Compass v2.1 (confirmed with Jeffrey 2026-07-31) */
  --black:#000000;
  --white:#FFFFFF;
  --ink:#1A1A1A;
  --fog:#F1F1EE;
  --infinity-blue:#1B2C4A;
  --infinity-blue-dark:color-mix(in oklch,var(--infinity-blue) 78%,black);
  --chimichurri-green:#4B7A3F;
  --chimichurri-green-dark:#3A5F30;

  /* Gold is RATING STARS ONLY. Convention beats brand cohesion here: a reader
     recognises gold stars and has to stop and think about blue ones. Do not
     reach for this token for anything else.

     The stars themselves are inline SVG rendered by build/components.js, which
     cannot read a CSS custom property, so it takes the same value from
     src/data/site-facts.js palette. Those two must not drift. */
  --gold:#D4A017;
  --star-empty:#D8D8D2;

  --border-subtle:#E5E5E0;

  /* semantic aliases */
  --surface-page:var(--white);
  --surface-card:var(--fog);
  --surface-inverse:var(--black);
  --text-heading:var(--black);
  --text-body:var(--ink);
  --text-muted:#5A5A54;
  --text-inverse:var(--white);
  --border-default:var(--border-subtle);
  --accent-primary:var(--infinity-blue);
  --accent-primary-hover:var(--infinity-blue-dark);
  --accent-spot:var(--chimichurri-green);
  --accent-spot-hover:var(--chimichurri-green-dark);
  /* Green TEXT on a dark ground is not available: Chimichurri Green is 3.44:1
     on --ink, below the 4.5:1 WCAG AA threshold for normal text, and the brand
     palette contains no lighter green. Small text on a dark band uses Fog Gray
     instead (15.38:1). The base green stays correct for borders and fills,
     where the 3:1 non-text threshold applies and it passes comfortably. */
  --accent-spot-on-dark:var(--fog);
  --link:var(--infinity-blue);
  --link-hover:var(--infinity-blue-dark);
  --focus-ring:var(--infinity-blue);

  /* TYPE FAMILIES. Exactly two, per Brand Guidelines v2.1 section 04.
     The fallbacks are the ones the guide names. Nothing in this codebase may
     declare a font-family that is not one of these two tokens; build/audit.js
     fails the build if it finds one. */
  --font-heading:'Playfair Display',Georgia,serif;
  --font-body:'Inter',Helvetica,Arial,sans-serif;

  /* type scale */
  --text-display:3rem;
  --text-h1:2.25rem;
  --text-h2:1.5rem;
  --text-h3:1.125rem;
  --text-body-size:1rem;
  --text-caption:0.8125rem;

  --leading-tight:1.05;
  --leading-heading:1.2;
  --leading-body:1.6;

  --tracking-label:0.14em;
  --tracking-tight:0.02em;

  /* spacing */
  --space-1:4px;
  --space-2:8px;
  --space-3:12px;
  --space-4:16px;
  --space-5:24px;
  --space-6:32px;
  --space-7:48px;
  --space-8:64px;
  --space-9:96px;

  --radius-sm:2px;
  --radius-md:8px;
  --radius-lg:12px;
  --radius-pill:999px;

  --shadow-card:0 1px 3px rgba(0,0,0,0.08);
  --shadow-raised:0 4px 16px rgba(0,0,0,0.12);

  /* motion */
  --ease-out-expo:cubic-bezier(0.16,1,0.3,1);
  --ease-out:cubic-bezier(0.22,1,0.36,1);
  --duration-fast:150ms;
  --duration-base:250ms;
  --duration-slow:450ms;
  --duration-deliberate:650ms;

  /* ---------------------------------------------------------------------
     LAYOUT, added 2026-08-26.
     ---------------------------------------------------------------------
     The site used to be a 1440px card centred on a fog background: .wrap
     carried max-width:1440px and every band sat inside it. Above 1440 the
     page stopped using the screen and just grew its own margins, which on a
     1920 monitor read as a marketing email and on a 3440 ultrawide read as a
     mistake. .wrap is now fluid and these four tokens are the whole system.

     --gutter is the ONLY horizontal breathing room the page gets. It
     interpolates continuously, so there is no breakpoint and no jump:
       1280px viewport -> 51.2px per side
       1920px viewport -> 76.8px per side
       2560px viewport -> 102.4px per side
       3440px viewport -> 120px per side (the clamp ceiling)
     Below 500px it floors at 20px, which is exactly the padding the mobile
     rules already used, so nothing moves under 1024px.

     --measure-prose caps RUNNING PROSE ONLY. At 3440 an uncapped paragraph
     runs past 400 characters a line. It is a token precisely so that dropping
     the idea later is a one-line change; nothing hardcodes 78ch.

     --card-min is documented below with the per-grid values, because one
     global figure could not preserve the current card sizes. See the note on
     the grid tokens. */
  --gutter:clamp(20px,4vw,120px);
  --measure-prose:78ch;
  --grid-gap:24px;

  /* CARD MINIMUMS, PER GRID, AND WHY THIS IS NOT ONE NUMBER.
     The brief asked for a single --card-min. A single value cannot hold,
     because the grids do not share a card size today: at the old 1440 cap a
     .team-grid card computed to 308px and a .tile-grid card to 429px. Setting
     one global minimum of 308px would have turned every 3-up grid into a 4-up
     grid AT TODAY'S WIDTHS and shrunk those cards by more than a hundred
     pixels, which is the one thing the brief forbids: cards must keep the size
     they have today and the grid must gain columns only as the screen grows.
     So each grid keeps its own measured minimum. --card-min is the base
     default for any grid added later that does not declare one. */
  --card-min:308px;
  --card-min-place:314px;
  --card-min-team:308px;
  --card-min-testimonial:421px;
  --card-min-phase:427px;
  --card-min-stat:421px;
  --card-min-choice:427px;
  --card-min-service:317px;
  --card-min-howwework:339px;
  --card-min-tools:429px;
  --card-min-tile:429px;
}
