/* ============================================================================
   GRAVELY x KOENIG DESIGN SYSTEM — single entry point.
   Drop this whole file into a HubSpot stylesheet, or link it. Order matters:
   fonts and tokens first, base second, components last.

   ⚠️  typography.css is imported AFTER colors.css on purpose. The two files no
   longer share any token name (--gv-text-... for sizes, --gv-color-... and --gv-ink... for colour), so the
   order is safe — but the PDM system shipped exactly this import order with a
   name collision and rendered body text black-on-black. Do not add a colour
   token named --gv-text-anything.
   ========================================================================= */
@import url("https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600;700&display=swap");

/* ============================================================================
   GRAVELY x KOENIG — FONT LOADING

   ⚠️  WHAT IS AND IS NOT SHIPPABLE — MEASURED 2026-09-03 (fontTools, OS/2.fsType),
       not read off a licence page:

     United Sans Reg  House Industries  fsType 0  Installable Embedding  -> SHIPPED (woff2)
     Hyperspace Race  Swell Type        fsType 8  Editable Embedding     -> SHIPPED (woff2)
     DIN Next LT Pro  Linotype          fsType 4  PREVIEW & PRINT ONLY   -> NOT SHIPPED

   AriensCo's own Brandfolder distributes these to dealers in DESKTOP FORMATS ONLY
   (measured: 88 font attachments, 0 woff/woff2). gravely.com serves DIN Next from a
   Monotype web kit (30AD8D_*.woff2) that AriensCo licensed for itself — Koenig does not
   inherit it. So the body face here is Barlow until Adam decides otherwise; see
   docs/DECISIONS.md #1. Swapping back is one line: change --gv-font-body.

   Barlow was chosen by measurement, not taste: against DIN Next it drifts -2.3% on set
   width (the smallest of five candidates) and its x-height/cap-height ratio is 0.723 vs
   DIN's 0.704 (the closest). Proof sheet: exports/font-substitute-proof.png.
   ========================================================================= */

/* NOTE: these paths are relative to THIS FILE (tokens/), not to the page. That is how
   url() works inside a stylesheet, and getting it wrong 404s silently — the page still
   renders, just in the fallback face. Measured 2026-09-03: every United Sans face was
   404ing as tokens/assets/fonts/... and nothing said so. If this CSS is flattened into a
   HubSpot stylesheet, re-point these to the File Manager URLs. */
@font-face {
  font-family: "United Sans Reg";
  src: url("https://45668251.fs1.hubspotusercontent-na1.net/hubfs/45668251/gravely/fonts/UnitedSansReg-Medium.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "United Sans Reg";
  src: url("https://45668251.fs1.hubspotusercontent-na1.net/hubfs/45668251/gravely/fonts/UnitedSansReg-Bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "United Sans Reg";
  src: url("https://45668251.fs1.hubspotusercontent-na1.net/hubfs/45668251/gravely/fonts/UnitedSansReg-Heavy.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "United Sans Reg";
  src: url("https://45668251.fs1.hubspotusercontent-na1.net/hubfs/45668251/gravely/fonts/UnitedSansReg-Black.woff2") format("woff2");
  font-weight: 900; font-style: normal; font-display: swap;
}
/* Campaign face. Reserved for secondary campaign lock-ups ("Mow Like A Pro"), never
   for headings, never for body. Brand guide p.16: campaign marks are accents. */
@font-face {
  font-family: "Hyperspace Race";
  src: url("https://45668251.fs1.hubspotusercontent-na1.net/hubfs/45668251/gravely/fonts/HyperspaceRace-Bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

:root {
  /* Display — the brand signature. Always uppercase, always heavy. */
  --gv-font-display: "United Sans Reg", "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* Body. Swap this ONE value to return to DIN Next if a web licence is bought. */
  --gv-font-body:    "Barlow", "DIN Next LT Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* Campaign only. */
  --gv-font-campaign:"Hyperspace Race", "United Sans Reg", sans-serif;
  /* Figures in spec tables — tabular so columns line up. */
  --gv-font-numeric: "Barlow", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

/* ============================================================================
   GRAVELY x KOENIG — COLOUR
   Source of truth: GRAVELY 1.0 Brand Standards Guide (AriensCo, © 2026), pp. 13 & 17,
   plus the live Brandfolder "Colors" section (collection ktq32jp387p8sshwrbvw8n).

   ⚠️  NAMING RULE (paid for on the PDM system, where --text-body was defined BOTH as a
   colour and as a type size; the size won and body copy rendered black-on-black):
   colour tokens are --gv-color-*, type sizes are --gv-text-*. They never share a name.

   ⚠️  EVERY RATIO BELOW WAS COMPUTED, NOT TRANSCRIBED — `python3 scripts/contrast.py`.
   Re-run it after any change. Do not edit a ratio by hand.
   ========================================================================= */

:root {
  /* ── PRIMARY (brand guide p.17) ─────────────────────────────────────── */
  --gv-red:              #DA291C;  /* PMS 485C  · CMYK 0/95/100/0  */
  --gv-black:            #212721;  /* PMS Black 3C               */
  --gv-white:            #FEFEFF;  /* never pure #FFF — the guide specifies FEFEFF */

  /* ── SECONDARY — accents only. "do not rely on them too heavily" (p.17) ─ */
  --gv-gray-dark:        #848689;
  --gv-gray-mid:         #B8BABC;

  /* ── ELECTRIC (EV sub-brand) — Brandfolder only, absent from the 1.0 guide ─
     Use ONLY on electric-product surfaces, and only on the Electric Dark ground. */
  --gv-electric-blue:    #00B2E3;
  --gv-electric-dark:    #101820;

  /* ── DERIVED NEUTRALS ───────────────────────────────────────────────────
     The brand grays fail as body text (measured). These are the same blue-gray
     hue pushed to a legible value, and they exist for exactly that reason. */
  --gv-gray-body-light:  #636568;  /* muted body ON WHITE  — 5.80:1 PASS AA   */
  --gv-gray-body-dark:   #B8BABC;  /* muted body ON BLACK  — 7.84:1 PASS AAA  */
  --gv-hairline-light:   #D2D4D5;  /* 1px rule on white — decorative, not meaning-bearing */
  --gv-hairline-dark:    #454B45;  /* 1px rule on black — decorative                      */
  --gv-border-light:     #848689;  /* meaning-bearing border on white — 3.62:1 PASS 1.4.11 */
  --gv-border-dark:      #848689;  /* meaning-bearing border on black — 4.18:1 PASS 1.4.11 */

  /* ── GROUNDS ────────────────────────────────────────────────────────────
     Two, and only two. A third ground is how a system starts to drift. */
  --gv-ground-dark:      #212721;
  --gv-ground-light:     #FEFEFF;
  --gv-ground-inset:     #F2F2F3;  /* a well on the light ground: cards, spec tables */
  --gv-ground-inset-dark:#2C332C;  /* a well on the dark ground                       */

  /* ── SEMANTIC INK ───────────────────────────────────────────────────────
     Set by the ground class, not chosen per element. See base.css. */
  --gv-ink:              var(--gv-black);
  --gv-ink-muted:        var(--gv-gray-body-light);
  --gv-ink-inverse:      var(--gv-white);
  --gv-rule:             var(--gv-hairline-light);
  --gv-edge:             var(--gv-border-light);

  /* ── ACTION ─────────────────────────────────────────────────────────────
     ONE action colour. Rank comes from the button VARIANT, never from a new hue.
     (Measured on gravely.com 2026-09-03: its own primary CTA is a red surface with a
     white uppercase United Sans label and border-radius 0. This matches.) */
  /* ⚠️  RED AS TEXT IS DISPLAY-ONLY. Measured: 4.83:1 on --gv-ground-light, but only
     4.35:1 on --gv-ground-inset, and 3.13:1 on black. It clears AA for normal text on
     exactly ONE of the three grounds, so the system does not allow it as body copy
     anywhere. Red text = >=24px, or >=19px at weight 700. Otherwise red is a SURFACE
     and the ink on it is white. */
  --gv-action:           var(--gv-red);
  --gv-action-ink:       var(--gv-white);   /* 4.83:1 on red — PASS AA */
  --gv-action-hover:     #B31F14;           /* red darkened; white ink 6.67:1 — PASS AA */
}

/* The dark ground re-points the semantic ink. Nothing else changes. */
.gv-dark {
  --gv-ink:        var(--gv-white);
  --gv-ink-muted:  var(--gv-gray-body-dark);
  --gv-ink-inverse:var(--gv-black);
  --gv-rule:       var(--gv-hairline-dark);
  --gv-edge:       var(--gv-border-dark);
  background: var(--gv-ground-dark);
  color: var(--gv-ink);
}
.gv-light {
  --gv-ink:        var(--gv-black);
  --gv-ink-muted:  var(--gv-gray-body-light);
  --gv-ink-inverse:var(--gv-white);
  --gv-rule:       var(--gv-hairline-light);
  --gv-edge:       var(--gv-border-light);
  background: var(--gv-ground-light);
  color: var(--gv-ink);
}
/* EV surfaces only. Electric Blue is 2.46:1 on white — it may NEVER appear on a light ground. */
.gv-electric {
  --gv-ink:        var(--gv-white);
  --gv-ink-muted:  var(--gv-gray-body-dark);
  --gv-action:     var(--gv-electric-blue);
  --gv-action-ink: var(--gv-electric-dark);   /* 7.22:1 — PASS AA */
  --gv-rule:       #263039;
  --gv-edge:       #6A7783;   /* 3.90:1 on Electric Dark — PASS 1.4.11.
                                 #55636E was tried first and MEASURED 2.89:1 — a fail. */
  background: var(--gv-electric-dark);
  color: var(--gv-ink);
}

/* ============================================================================
   GRAVELY x KOENIG — TYPE SCALE
   Brand guide p.18: United Sans = headline · DIN Next = body · Hyperspace Race =
   secondary (campaign) headline.

   ⚠️  These are SIZE tokens (--gv-text-*). Colour tokens are --gv-color-* / --gv-ink*.
       The two namespaces never overlap. See the warning at the top of colors.css.

   The scale is fluid between 390px and 1440px. Every step is clamp()ed so a phone
   never gets a 96px headline and a desktop never gets a timid one.
   ========================================================================= */

:root {
  /* ── DISPLAY (United Sans, uppercase) ─────────────────────────────────── */
  --gv-text-hero:    clamp(2.75rem, 1.30rem + 5.95vw, 6.50rem);  /*  44 -> 104 px */
  --gv-text-display: clamp(2.25rem, 1.38rem + 3.57vw, 4.50rem);  /*  36 ->  72 px */
  --gv-text-h1:      clamp(2.00rem, 1.42rem + 2.38vw, 3.50rem);  /*  32 ->  56 px */
  --gv-text-h2:      clamp(1.50rem, 1.16rem + 1.39vw, 2.38rem);  /*  24 ->  38 px */
  --gv-text-h3:      clamp(1.25rem, 1.11rem + 0.60vw, 1.63rem);  /*  20 ->  26 px */

  /* ── BODY (Barlow / DIN Next) ─────────────────────────────────────────── */
  --gv-text-lead:    clamp(1.13rem, 1.03rem + 0.40vw, 1.38rem);  /*  18 ->  22 px */
  --gv-text-body:    1.0625rem;                                  /*      17 px    */
  --gv-text-small:   0.9375rem;                                  /*      15 px    */
  --gv-text-fine:    0.8125rem;                                  /*      13 px    */

  /* ── UTILITY ──────────────────────────────────────────────────────────── */
  --gv-text-eyebrow: 0.75rem;                                    /*      12 px    */
  --gv-text-label:   0.8125rem;                                  /*      13 px    */
  /* The signature readout — a model number, a deck size, a year. */
  --gv-text-readout: clamp(2.25rem, 1.52rem + 3.00vw, 4.13rem);  /*  36 ->  66 px */

  /* ── WEIGHT ───────────────────────────────────────────────────────────── */
  --gv-weight-display: 800;   /* United Sans Heavy — the default for headings   */
  --gv-weight-black:   900;   /* United Sans Black — hero + readout only        */
  --gv-weight-bold:    700;
  --gv-weight-medium:  500;
  --gv-weight-regular: 400;

  /* ── LINE HEIGHT ──────────────────────────────────────────────────────── */
  --gv-leading-hero:  0.92;   /* heavy caps set TIGHT; that tension is the brand */
  --gv-leading-tight: 1.02;
  --gv-leading-head:  1.12;
  --gv-leading-body:  1.55;
  --gv-leading-loose: 1.68;   /* long-form article copy                          */

  /* ── TRACKING ─────────────────────────────────────────────────────────── */
  --gv-tracking-hero:    -0.005em;  /* United Sans caps need almost none        */
  --gv-tracking-display:  0.005em;
  --gv-tracking-eyebrow:  0.16em;   /* micro-labels open right up               */
  --gv-tracking-label:    0.08em;
  --gv-tracking-body:     0;

  /* ── MEASURE ──────────────────────────────────────────────────────────── */
  --gv-measure:      64ch;    /* body copy never runs wider                      */
  --gv-measure-lead: 46ch;    /* a lead paragraph is shorter on purpose          */
}

/* ============================================================================
   GRAVELY x KOENIG — SPACE & GRID
   An 8px base. Every gap in the system is one of these; nothing is hand-nudged.
   ========================================================================= */
:root {
  --gv-space-1:  0.25rem;   /*  4 */
  --gv-space-2:  0.5rem;    /*  8 */
  --gv-space-3:  0.75rem;   /* 12 */
  --gv-space-4:  1rem;      /* 16 */
  --gv-space-5:  1.5rem;    /* 24 */
  --gv-space-6:  2rem;      /* 32 */
  --gv-space-7:  3rem;      /* 48 */
  --gv-space-8:  4rem;      /* 64 */
  --gv-space-9:  6rem;      /* 96 */
  --gv-space-10: 8rem;      /*128 */

  /* Band padding — the vertical rhythm of a page, fluid. */
  --gv-band-y:       clamp(3rem, 1.60rem + 5.71vw, 6.50rem);
  --gv-band-y-tight: clamp(2rem, 1.40rem + 2.46vw, 3.50rem);

  /* Page shell */
  --gv-gutter:    clamp(1.25rem, 0.55rem + 2.86vw, 3rem);
  --gv-max:       1280px;   /* standard content width  */
  --gv-max-wide:  1520px;   /* galleries, full grids   */
  --gv-max-text:  46rem;    /* article column          */

  /* Grid */
  --gv-grid-gap:  clamp(1rem, 0.60rem + 1.63vw, 2rem);

  /* Hit targets — 44px minimum, no exceptions. */
  --gv-hit: 44px;
}

/* ============================================================================
   GRAVELY x KOENIG — EDGES
   The system separates things with RULES and EDGES. No shadows, no gradients,
   no glassmorphism, no glow. The brand guide forbids effects on the logo; the
   same restraint runs through the chrome, and it is what keeps photography loud.
   ========================================================================= */
:root {
  --gv-rule-hair:  1px;   /* decorative divider          */
  --gv-rule-mid:   2px;   /* section rule, table header  */
  --gv-rule-heavy: 4px;   /* the RED RULE — see below    */
  --gv-rule-slab:  8px;   /* a slab edge, hero underline */

  /* ── RADIUS ────────────────────────────────────────────────────────────
     ZERO. Everywhere. Measured on gravely.com 2026-09-03: its own primary CTAs
     render at border-radius 0px. The ONLY curve in the system is the "G" badge
     itself, and that curve is the mark's, not the chrome's. */
  --gv-radius: 0;

  /* ── SHADOW ────────────────────────────────────────────────────────────
     One, and only for a floating overlay (drawer, modal) where depth is the
     only way to say "above". Never on a card, never on a button. */
  --gv-shadow-overlay: 0 24px 64px rgba(0,0,0,.45);
}

/* ============================================================================
   GRAVELY x KOENIG — MOTION
   Short, linear-ish, mechanical. Nothing bounces. Nothing floats. Machines move
   with intent; so does this.
   ========================================================================= */
:root {
  --gv-dur-fast:  120ms;
  --gv-dur-base:  180ms;
  --gv-dur-slow:  280ms;
  --gv-ease:      cubic-bezier(.2,.6,.3,1);
  --gv-ease-out:  cubic-bezier(0,0,.25,1);
}
@media (prefers-reduced-motion: reduce) {
  :root { --gv-dur-fast: 1ms; --gv-dur-base: 1ms; --gv-dur-slow: 1ms; }
  *, *::before, *::after {
    animation-duration: 1ms !important; animation-iteration-count: 1 !important;
    transition-duration: 1ms !important; scroll-behavior: auto !important;
  }
}

/* ============================================================================
   GRAVELY x KOENIG — BASE
   Element defaults. Everything above the components; nothing decorative here.
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--gv-ground-light);
  color: var(--gv-ink);
  font-family: var(--gv-font-body);
  font-size: var(--gv-text-body);
  line-height: var(--gv-leading-body);
  font-weight: var(--gv-weight-regular);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ── HEADINGS ────────────────────────────────────────────────────────────
   United Sans, uppercase, heavy, tight. This is the loudest thing the brand
   does with type and it is not negotiable per element. */
h1, h2, h3, h4, .gv-display {
  font-family: var(--gv-font-display);
  font-weight: var(--gv-weight-display);
  text-transform: uppercase;
  letter-spacing: var(--gv-tracking-display);
  line-height: var(--gv-leading-head);
  color: var(--gv-ink);
  margin: 0 0 var(--gv-space-4);
  text-wrap: balance;
}
h1 { font-size: var(--gv-text-h1); line-height: var(--gv-leading-tight); }
h2 { font-size: var(--gv-text-h2); }
h3 { font-size: var(--gv-text-h3); }
h4 { font-size: var(--gv-text-body); letter-spacing: var(--gv-tracking-label); }

p { margin: 0 0 var(--gv-space-4); max-width: var(--gv-measure); }
p:last-child { margin-bottom: 0; }

a { color: inherit; text-underline-offset: 0.18em; text-decoration-thickness: 1px; }

img, svg, video { max-width: 100%; height: auto; display: block; }

hr {
  border: 0; height: var(--gv-rule-hair);
  background: var(--gv-rule);
  margin: var(--gv-space-7) 0;
}

/* ── FOCUS — visible, square, red, never removed ─────────────────────── */
:focus-visible {
  outline: 3px solid var(--gv-red);
  outline-offset: 2px;
}
.gv-dark :focus-visible, .gv-electric :focus-visible {
  outline-color: var(--gv-white);
}

::selection { background: var(--gv-red); color: var(--gv-white); }

/* ── LAYOUT PRIMITIVES ───────────────────────────────────────────────── */
.gv-shell   { max-width: var(--gv-max);      margin-inline: auto; padding-inline: var(--gv-gutter); }
.gv-shell--wide { max-width: var(--gv-max-wide); }
.gv-shell--text { max-width: var(--gv-max-text); }

.gv-band    { padding-block: var(--gv-band-y); }
.gv-band--tight { padding-block: var(--gv-band-y-tight); }
/* A well on the light ground. Use this class rather than an inline background — the accent
   eyebrow has to know it is on the inset, because red at 12px measures 4.35:1 here against
   4.83:1 on pure white. */
.gv-inset { background: var(--gv-ground-inset); }

.gv-grid    { display: grid; gap: var(--gv-grid-gap); }
/* Grid and flex children default to min-width:auto, so one wide child (a spec table, a
   long readout) makes the whole track wider than the viewport. Measured: 253px of
   horizontal scroll at 390px before this line. */
.gv-grid > *, .gv-split > *, .gv-stats > * { min-width: 0; }
.gv-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }
.gv-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
@media (min-width: 64rem) { .gv-grid--3 { grid-template-columns: repeat(3, 1fr); } }
.gv-grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }

.gv-stack > * + * { margin-top: var(--gv-space-4); }

/* ── TYPE ROLES ──────────────────────────────────────────────────────── */
.gv-eyebrow {
  font-family: var(--gv-font-display);
  font-size: var(--gv-text-eyebrow);
  font-weight: var(--gv-weight-bold);
  letter-spacing: var(--gv-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--gv-ink-muted);
  margin: 0 0 var(--gv-space-3);
  display: block;
}
/* An eyebrow may be red ONLY at this size when it is BOLD — see the display-only
   rule in colors.css. On the dark ground red drops to 3.13:1, so it turns white. */
.gv-eyebrow--accent { color: var(--gv-red); font-weight: 700; }
.gv-dark .gv-eyebrow--accent, .gv-electric .gv-eyebrow--accent { color: var(--gv-white); }
/* 4.35:1 on the inset ground — below AA for 12px text. Falls back to ink. */
.gv-inset .gv-eyebrow--accent { color: var(--gv-ink); }

.gv-lead {
  font-size: var(--gv-text-lead);
  line-height: 1.45;
  max-width: var(--gv-measure-lead);
  color: var(--gv-ink);
}
.gv-muted { color: var(--gv-ink-muted); }
.gv-fine  { font-size: var(--gv-text-fine); color: var(--gv-ink-muted); }

/* ── THE RED RULE — the system's one recurring ornament ──────────────────
   A 4px red bar that opens a section. It is the only decoration allowed, and it
   is never used twice in the same band. */
.gv-rule-red {
  width: 4rem; height: var(--gv-rule-heavy);
  background: var(--gv-red);
  margin: 0 0 var(--gv-space-5);
  border: 0;
}

/* ── THE READOUT — a number treated as an object ─────────────────────────
   1916. 60". 26 HP. The signature device: United Sans Black, tight, with a
   small tracked label beneath it. */
.gv-readout { display: flex; flex-direction: column; gap: var(--gv-space-1); }
.gv-readout__value {
  font-family: var(--gv-font-display);
  font-size: var(--gv-text-readout);
  font-weight: var(--gv-weight-black);
  line-height: 0.86;
  letter-spacing: var(--gv-tracking-hero);
  color: var(--gv-ink);
  font-variant-numeric: tabular-nums;
}
.gv-readout__label {
  font-family: var(--gv-font-display);
  font-size: var(--gv-text-eyebrow);
  font-weight: var(--gv-weight-bold);
  letter-spacing: var(--gv-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--gv-ink-muted);
}

/* ── THE SLAB — a red or black plate carrying a short, loud line ───────── */
.gv-slab {
  display: inline-block;
  background: var(--gv-red);
  color: var(--gv-white);
  font-family: var(--gv-font-display);
  font-weight: var(--gv-weight-display);
  text-transform: uppercase;
  letter-spacing: var(--gv-tracking-label);
  font-size: var(--gv-text-label);
  padding: var(--gv-space-2) var(--gv-space-4);
}
.gv-slab--black { background: var(--gv-black); color: var(--gv-white); }

/* ── SCREEN-READER ONLY ─────────────────────────────────────────────── */
.gv-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* Skip link — visible on focus, never a hidden dead end. */
.gv-skip {
  position: absolute; left: var(--gv-space-4); top: -100px; z-index: 999;
  background: var(--gv-red); color: var(--gv-white);
  padding: var(--gv-space-3) var(--gv-space-4);
  font-family: var(--gv-font-display); text-transform: uppercase;
  letter-spacing: var(--gv-tracking-label); text-decoration: none;
  transition: top var(--gv-dur-fast) var(--gv-ease);
}
.gv-skip:focus { top: var(--gv-space-4); }

/* ============================================================================
   GRAVELY x KOENIG — COMPONENTS
   Plain semantic HTML + CSS, because the implementation target is HubSpot CMS.
   Every class is namespaced .gv- so it can never collide with HubSpot's own CSS
   or with the Koenig main-site chrome.
   ========================================================================= */

/* ══ ACTIONS ═══════════════════════════════════════════════════════════════
   ONE action colour (red). Rank comes from the VARIANT, never from a new hue.
     primary   red surface, white label      — the one thing you want done
     secondary outlined, ink label           — the real alternative
     ghost     underline only                — tertiary, in-flow
   At most ONE primary per band. Two primaries side by side is not a choice,
   it is a shrug.
   ═══════════════════════════════════════════════════════════════════════ */
.gv-btn {
  --_bg: var(--gv-action);
  --_ink: var(--gv-action-ink);
  --_edge: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--gv-space-2);
  min-height: var(--gv-hit);
  padding: var(--gv-space-3) var(--gv-space-6);
  background: var(--_bg); color: var(--_ink);
  border: 2px solid var(--_edge);
  border-radius: var(--gv-radius);
  font-family: var(--gv-font-display);
  font-size: var(--gv-text-label);
  font-weight: var(--gv-weight-display);
  text-transform: uppercase;
  letter-spacing: var(--gv-tracking-label);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--gv-dur-fast) var(--gv-ease),
              color var(--gv-dur-fast) var(--gv-ease),
              border-color var(--gv-dur-fast) var(--gv-ease);
}
.gv-btn:hover  { --_bg: var(--gv-action-hover); }
.gv-btn:active { transform: translateY(1px); }

.gv-btn--secondary {
  --_bg: transparent; --_ink: var(--gv-ink); --_edge: var(--gv-ink);
}
.gv-btn--secondary:hover { --_bg: var(--gv-ink); --_ink: var(--gv-ink-inverse); }

.gv-btn--ghost {
  --_bg: transparent; --_ink: var(--gv-ink); --_edge: transparent;
  padding-inline: 0; text-decoration: underline;
  text-decoration-thickness: 2px; text-underline-offset: 0.3em;
  text-decoration-color: var(--gv-red);
}
.gv-btn--ghost:hover { --_bg: transparent; text-decoration-color: currentColor; }

.gv-btn--block { width: 100%; }

/* A phone number is an action, and on a mobile-first dealer site it is often THE
   action. It gets its own treatment so it is never mistaken for body copy. */
.gv-phone {
  display: inline-flex; align-items: center; gap: var(--gv-space-2);
  min-height: var(--gv-hit);
  font-family: var(--gv-font-display);
  font-weight: var(--gv-weight-display);
  font-size: var(--gv-text-h3);
  letter-spacing: var(--gv-tracking-display);
  color: var(--gv-ink); text-decoration: none;
}
.gv-phone:hover { text-decoration: underline; text-decoration-color: var(--gv-red);
                  text-decoration-thickness: 3px; text-underline-offset: 0.25em; }

/* An inline text link inside body copy. Red underline, ink text — because red
   TEXT below 24px fails AA on two of the three grounds (measured). */
.gv-link {
  color: inherit; text-decoration: underline;
  text-decoration-color: var(--gv-red); text-decoration-thickness: 2px;
  text-underline-offset: 0.2em;
}
.gv-link:hover { text-decoration-color: currentColor; }

/* ══ NAVIGATION ════════════════════════════════════════════════════════ */
.gv-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--gv-black); color: var(--gv-white);
  border-bottom: var(--gv-rule-heavy) solid var(--gv-red);
}
/* A three-column grid, not a flex row: the middle column is the only way to centre the
   lock-up regardless of what sits either side of it. Column 1 is empty at every width;
   column 3 carries the toggle (below 62rem) or the quote CTA (above it), and the nav drops
   to a second row so a 52px-tall lock-up and six nav items are not competing for one line.
   Measured at 992px: nav 540px + lock-up 387px + CTA 180px = 1107px, which does not fit. */
.gv-header__bar {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: var(--gv-space-2);   /* every px of gap costs 7.44px of lock-up */
  min-height: 72px;
  max-width: var(--gv-max-wide); margin-inline: auto;
  padding-inline: var(--gv-gutter);
  padding-block: var(--gv-space-3);
  min-width: 0;
}
.gv-header__logo { display: flex; align-items: center; gap: var(--gv-space-4);
  grid-column: 2; grid-row: 1; justify-self: center;
  min-height: var(--gv-hit); min-width: 0; text-decoration: none; }
/* The approved Koenig x Gravely lock-up is 1130.95 x 152.1 — aspect 7.44, so HEIGHT buys width
   at 7.44x the rate. At 52px it is 387px wide.

   Centred is a geometric promise, and on a phone it fights the mark's own width: with a 64px
   Menu button in the right column, a truly centred lock-up may only be as wide as TWICE the
   space left beside it. Measured at 360px it was sitting 22px off centre because the empty left
   column collapsed to 26px while the toggle held the right one at 64px. So the height is capped
   by the width actually available — (100vw - 208px) / 7.44 — rather than by a guess. Above
   62rem the toggle is gone and the nav has its own row, so the full 52px always fits. */
.gv-header__logo svg, .gv-header__logo img {
  height: min(clamp(20px, 9.2vw, 52px), calc(13.4vw - 24px));
  width: auto; flex: 0 1 auto;
}
@media (min-width: 62rem) {
  .gv-header__logo svg, .gv-header__logo img { height: 52px; }
}
/* The co-brand: Gravely mark, a hairline, then "at Koenig Equipment". Gravely-forward,
   Koenig-endorsed. NEVER the John Deere/Koenig lockup — this is a shortline surface. */
/* Kept for surfaces where the lock-up will not fit (a narrow utility bar, an email
   signature). The lock-up is the default; this is the fallback, not the other way round. */
.gv-header__cobrand {
  display: none;
  font-family: var(--gv-font-display); font-size: var(--gv-text-eyebrow);
  font-weight: var(--gv-weight-bold); text-transform: uppercase;
  letter-spacing: var(--gv-tracking-eyebrow); color: var(--gv-gray-mid);
  padding-left: var(--gv-space-4); border-left: 1px solid var(--gv-hairline-dark);
  line-height: 1.3;
}
.gv-header__nav { display: none; gap: var(--gv-space-5);
  grid-column: 1 / -1; grid-row: 2; justify-self: center; }
.gv-header__nav a {
  font-family: var(--gv-font-display); font-size: var(--gv-text-label);
  font-weight: var(--gv-weight-display); text-transform: uppercase;
  letter-spacing: var(--gv-tracking-label); color: var(--gv-white);
  text-decoration: none; padding-block: var(--gv-space-3);
  border-bottom: 3px solid transparent;
}
.gv-header__nav a:hover, .gv-header__nav a[aria-current="page"] { border-bottom-color: var(--gv-red); }
.gv-header__actions { display: none; grid-column: 3; grid-row: 1; justify-self: end;
  align-items: center; gap: var(--gv-space-3); }
.gv-header__toggle {
  grid-column: 3; grid-row: 1; justify-self: end;
  min-width: var(--gv-hit); min-height: var(--gv-hit);
  background: none; border: 2px solid var(--gv-gray-dark); color: var(--gv-white);
  font-family: var(--gv-font-display); text-transform: uppercase;
  letter-spacing: var(--gv-tracking-label); font-size: var(--gv-text-fine);
  cursor: pointer; border-radius: var(--gv-radius);
}
/* The co-brand line needs room to be legible; below 30rem it is carried by the
   drawer and the footer instead of being crushed next to the mark. */
@media (min-width: 30rem) { .gv-header__cobrand { display: block; } }
@media (min-width: 62rem) {
  .gv-header__bar { gap: var(--gv-space-5); }
  .gv-header__nav { display: flex; }
  .gv-header__actions { display: flex; }
  .gv-header__toggle { display: none; }
  .gv-header__actions { margin-left: 0; }
}
/* Mobile drawer */
.gv-drawer { display: none; background: var(--gv-black); border-top: 1px solid var(--gv-hairline-dark); }
.gv-drawer[data-open="true"] { display: block; }
.gv-drawer .gv-btn { margin: var(--gv-space-4) var(--gv-gutter); width: calc(100% - 2 * var(--gv-gutter)); }
.gv-drawer a:not(.gv-btn) {
  display: block; padding: var(--gv-space-4) var(--gv-gutter);
  min-height: var(--gv-hit);
  font-family: var(--gv-font-display); font-weight: var(--gv-weight-display);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  color: var(--gv-white); text-decoration: none;
  border-bottom: 1px solid var(--gv-hairline-dark);
}
@media (min-width: 62rem) { .gv-drawer { display: none !important; } }

.gv-footer { background: var(--gv-black); color: var(--gv-white); padding-block: var(--gv-space-8) var(--gv-space-6); }
.gv-footer__grid { display: grid; gap: var(--gv-space-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }
.gv-footer h4 { color: var(--gv-gray-mid); font-size: var(--gv-text-eyebrow);
  letter-spacing: var(--gv-tracking-eyebrow); margin-bottom: var(--gv-space-3); }
.gv-footer a { color: var(--gv-white); text-decoration: none; display: flex; align-items: center;
  min-height: var(--gv-hit); padding-block: var(--gv-space-2); font-size: var(--gv-text-small); }
.gv-footer a:hover { text-decoration: underline; text-decoration-color: var(--gv-red); }
.gv-footer__legal {
  margin-top: var(--gv-space-7); padding-top: var(--gv-space-5);
  border-top: 1px solid var(--gv-hairline-dark);
  font-size: var(--gv-text-fine); color: var(--gv-gray-mid);
  display: flex; flex-wrap: wrap; gap: var(--gv-space-4); justify-content: space-between;
}

/* ══ BANDS ═════════════════════════════════════════════════════════════ */

/* HERO — full-bleed photograph, black scrim, heavy caps bottom-left.
   The photograph does the emotional work. The chrome stays out of its way. */
.gv-hero {
  /* A band that paints its own dark ground MUST re-point the semantic ink, exactly as
     .gv-dark does. Measured 2026-09-03: without these four lines the hero <h1> inherited
     --gv-ink (black) over a black scrim and rendered at 1.00:1 — invisible. Any new band
     that sets its own background has to do the same. */
  --gv-ink: var(--gv-white);
  --gv-ink-muted: var(--gv-gray-body-dark);
  --gv-ink-inverse: var(--gv-black);
  --gv-rule: var(--gv-hairline-dark);
  --gv-edge: var(--gv-border-dark);
  position: relative; background: var(--gv-black); color: var(--gv-ink); isolation: isolate;
}
.gv-hero__media { position: absolute; inset: 0; z-index: -2; }
.gv-hero__media img { width: 100%; height: 100%; object-fit: cover; }
.gv-hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(33,39,33,.35) 0%, rgba(33,39,33,.55) 45%, rgba(33,39,33,.88) 100%);
}
.gv-hero__inner {
  max-width: var(--gv-max); margin-inline: auto; padding-inline: var(--gv-gutter);
  min-height: clamp(28rem, 60vh, 42rem);
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-block: var(--gv-space-9) var(--gv-space-8);
}
.gv-hero__title {
  font-size: var(--gv-text-hero); font-weight: var(--gv-weight-black);
  line-height: var(--gv-leading-hero); letter-spacing: var(--gv-tracking-hero);
  margin: 0 0 var(--gv-space-5); max-width: 18ch; text-wrap: balance;
}
.gv-hero__lead { max-width: var(--gv-measure-lead); font-size: var(--gv-text-lead);
  color: var(--gv-ink-muted); margin-bottom: var(--gv-space-6); }
.gv-hero__actions { display: flex; flex-wrap: wrap; gap: var(--gv-space-3); }
.gv-hero--compact .gv-hero__inner { min-height: 22rem; }

/* SECTION BAND — the workhorse. A ground, a red rule, a heading, content. */
.gv-section__head { margin-bottom: var(--gv-space-7); max-width: var(--gv-measure); }

/* STAT BAND — three or four readouts on the black ground. Heritage numbers,
   spec numbers, coverage numbers. Every number must be sourceable. */
.gv-stats { display: grid; gap: var(--gv-space-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr)); }

/* CLOSER — exactly one per page, the last thing before the footer. */
.gv-closer {
  --gv-ink: var(--gv-white); --gv-ink-muted: var(--gv-white);
  --gv-ink-inverse: var(--gv-red); --gv-rule: rgba(255,255,255,.35); --gv-edge: var(--gv-white);
  background: var(--gv-red); color: var(--gv-ink);
}
.gv-closer h2 { color: var(--gv-white); max-width: 20ch; }
.gv-closer .gv-btn { --_bg: var(--gv-white); --_ink: var(--gv-red); }
.gv-closer .gv-btn:hover { --_bg: var(--gv-black); --_ink: var(--gv-white); }
.gv-closer .gv-btn--secondary { --_bg: transparent; --_ink: var(--gv-white); --_edge: var(--gv-white); }
.gv-closer .gv-btn--secondary:hover { --_bg: var(--gv-white); --_ink: var(--gv-red); }

/* SPLIT — media one side, copy the other. Alternates by modifier, never by
   hand-written order. Three in a row on the same side reads as a template. */
.gv-split { display: grid; gap: var(--gv-space-7); align-items: center; }
.gv-split__media img { width: 100%; }
@media (min-width: 54rem) {
  .gv-split { grid-template-columns: 1fr 1fr; gap: var(--gv-space-8); }
  .gv-split--flip .gv-split__media { order: 2; }
}

/* ══ CONTENT ═══════════════════════════════════════════════════════════ */

/* MODEL CARD — the unit of a lineup grid. Photo on the inset ground, series
   name, one line of positioning, deck range, then a single ghost action. */
.gv-model {
  display: flex; flex-direction: column;
  background: var(--gv-ground-light); color: var(--gv-black);
  border: 1px solid var(--gv-hairline-light);
  text-decoration: none;
  transition: border-color var(--gv-dur-base) var(--gv-ease);
}
.gv-model:hover { border-color: var(--gv-red); }
.gv-model__media { background: var(--gv-ground-inset); aspect-ratio: 4 / 3;
  display: grid; place-items: center; padding: var(--gv-space-5); }
.gv-model__media img { max-height: 100%; width: auto; object-fit: contain; }
.gv-model__body { padding: var(--gv-space-5); display: flex; flex-direction: column;
  gap: var(--gv-space-2); flex: 1; }
.gv-model__tier {
  font-family: var(--gv-font-display); font-size: var(--gv-text-eyebrow);
  font-weight: var(--gv-weight-bold); text-transform: uppercase;
  letter-spacing: var(--gv-tracking-eyebrow); color: var(--gv-gray-body-light);
}
.gv-model__name {
  font-family: var(--gv-font-display); font-size: var(--gv-text-h3);
  font-weight: var(--gv-weight-display); text-transform: uppercase;
  letter-spacing: var(--gv-tracking-display); margin: 0;
}
.gv-model__note { font-size: var(--gv-text-small); color: var(--gv-gray-body-light); margin: 0; }
.gv-model__meta {
  margin-top: auto; padding-top: var(--gv-space-4);
  border-top: 1px solid var(--gv-hairline-light);
  font-family: var(--gv-font-display); font-size: var(--gv-text-fine);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  display: flex; justify-content: space-between; gap: var(--gv-space-3);
}
.gv-model__meta span:last-child { color: var(--gv-red); }

/* SPEC TABLE — figures are tabular, the header is a black slab, and on a phone
   the table scrolls inside itself rather than breaking the page. */
.gv-spec { width: 100%; max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.gv-spec table { width: 100%; border-collapse: collapse; min-width: 32rem;
  font-variant-numeric: tabular-nums; }
.gv-spec th, .gv-spec td {
  text-align: left; padding: var(--gv-space-3) var(--gv-space-4);
  border-bottom: 1px solid var(--gv-hairline-light); font-size: var(--gv-text-small);
}
.gv-spec thead th {
  background: var(--gv-black); color: var(--gv-white);
  font-family: var(--gv-font-display); font-size: var(--gv-text-fine);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  border-bottom: 0;
}
.gv-spec tbody th { font-weight: var(--gv-weight-medium); color: var(--gv-gray-body-light);
  font-family: var(--gv-font-body); text-transform: none; letter-spacing: 0; width: 40%; }
.gv-spec tbody tr:nth-child(even) { background: var(--gv-ground-inset); }
/* A link that IS a table cell's content is a standalone target, not an inline link in prose,
   so it has to clear the 44px floor. Measured: 46 cell links were landing at 18px. */
.gv-spec td a, .gv-spec th a {
  display: inline-flex; align-items: center; min-height: var(--gv-hit);
}

/* FEATURE LIST — a red rule per item, no bullet glyphs. */
.gv-features { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gv-space-5); }
.gv-features li { padding-left: var(--gv-space-5); border-left: var(--gv-rule-mid) solid var(--gv-red); }
.gv-features h3 { font-size: var(--gv-text-body); letter-spacing: var(--gv-tracking-label);
  margin-bottom: var(--gv-space-2); }
.gv-features p { font-size: var(--gv-text-small); color: var(--gv-ink-muted); margin: 0; }

/* STORE CARD — a Koenig location that carries the line. */
.gv-store { border: 1px solid var(--gv-hairline-light); padding: var(--gv-space-5);
  display: flex; flex-direction: column; gap: var(--gv-space-2); }
.gv-store h3 { margin: 0; font-size: var(--gv-text-h3); }
/* A link that IS a card heading is a standalone target, not an inline link in prose —
   measured at 26px on the store pages before this. */
.gv-store h3 a { display: inline-flex; align-items: center; min-height: var(--gv-hit); }
.gv-store address { font-style: normal; font-size: var(--gv-text-small); color: var(--gv-ink-muted); }

/* FAQ — <details>, visible copy, no JS. The answer is on the page for a person
   AND for an answer engine; it is not a rich-snippet play. */
.gv-faq { border-top: var(--gv-rule-mid) solid var(--gv-ink); }
.gv-faq details { border-bottom: 1px solid var(--gv-rule); }
.gv-faq summary {
  cursor: pointer; list-style: none; padding: var(--gv-space-4) 0;
  min-height: var(--gv-hit); display: flex; align-items: center; justify-content: space-between;
  gap: var(--gv-space-4);
  font-family: var(--gv-font-display); font-weight: var(--gv-weight-display);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  font-size: var(--gv-text-small);
}
.gv-faq summary::-webkit-details-marker { display: none; }
.gv-faq summary::after { content: "+"; color: var(--gv-red); font-size: 1.5em; line-height: 1; }
.gv-faq details[open] summary::after { content: "\2013"; }
.gv-faq details > *:not(summary) { padding-bottom: var(--gv-space-5); max-width: var(--gv-measure); }

/* ══ FORMS ═════════════════════════════════════════════════════════════ */
.gv-field { display: flex; flex-direction: column; gap: var(--gv-space-2); margin-bottom: var(--gv-space-5); }
.gv-field label {
  font-family: var(--gv-font-display); font-size: var(--gv-text-fine);
  font-weight: var(--gv-weight-bold); text-transform: uppercase;
  letter-spacing: var(--gv-tracking-label); color: var(--gv-ink);
}
.gv-field input, .gv-field select, .gv-field textarea {
  min-height: var(--gv-hit);
  padding: var(--gv-space-3) var(--gv-space-4);
  background: var(--gv-ground-light); color: var(--gv-black);
  border: 2px solid var(--gv-edge); border-radius: var(--gv-radius);
  font-family: var(--gv-font-body); font-size: var(--gv-text-body);
  width: 100%;
}
.gv-field input:focus, .gv-field select:focus, .gv-field textarea:focus { border-color: var(--gv-red); }
.gv-field__hint { font-size: var(--gv-text-fine); color: var(--gv-ink-muted); }
.gv-field--error input { border-color: var(--gv-red); }
.gv-field__error { font-size: var(--gv-text-fine); color: var(--gv-red); font-weight: 600; }


/* ══ DECK RULER ════════════════════════════════════════════════════════════
   Introduced by the Claude Design homepage, added here rather than left as page CSS —
   when a design needs something the library cannot express, the library grows.

   Every series on one 30–72" scale, so deck width (the decision that actually matters)
   is comparable at a glance instead of buried in a table.

   ⚠️ THE NUMBERS ARE THE DRAWING. Bar start and end are computed from the real deck range,
   so a wrong deck width is not a typo — it is a bar of the wrong length in the wrong place.
   Always render this from gravely_models, never from hand-typed ranges. The synced design
   had 6 of 7 bars drawn from wrong numbers for exactly this reason.
   ═════════════════════════════════════════════════════════════════════════ */
.gv-ruler-scale, .gv-ruler {
  display: grid; grid-template-columns: minmax(8rem, 12rem) 1fr;
  gap: var(--gv-space-4); align-items: center;
}
.gv-ruler-scale {
  align-items: end; border-bottom: var(--gv-rule-mid) solid var(--gv-ink);
  padding-bottom: var(--gv-space-2);
}
.gv-ruler-scale__ticks { display: grid; }
.gv-ruler-scale__ticks span {
  text-align: right; font-family: var(--gv-font-display); font-weight: var(--gv-weight-display);
  font-size: var(--gv-text-small); letter-spacing: var(--gv-tracking-label);
  font-variant-numeric: tabular-nums;
}
.gv-ruler {
  min-height: 56px; text-decoration: none;
  border-bottom: 1px solid var(--gv-rule);
}
.gv-ruler__label { display: grid; gap: 2px; }
.gv-ruler__name {
  font-family: var(--gv-font-display); font-weight: var(--gv-weight-display);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  font-size: var(--gv-text-small); color: var(--gv-ink);
  transition: color var(--gv-dur-fast) var(--gv-ease);
}
.gv-ruler__range {
  font-family: var(--gv-font-display); font-size: var(--gv-text-fine);
  letter-spacing: var(--gv-tracking-label); color: var(--gv-ink-muted);
  font-variant-numeric: tabular-nums;
}
.gv-ruler__track {
  display: grid; align-items: center; min-height: 56px;
  background-image: repeating-linear-gradient(90deg, transparent 0 calc(100% / 7 - 1px),
    var(--gv-rule) calc(100% / 7 - 1px) calc(100% / 7));
}
.gv-ruler__bar {
  height: 16px; background: var(--gv-ink);
  transition: background var(--gv-dur-fast) var(--gv-ease);
}
.gv-ruler:hover .gv-ruler__bar { background: var(--gv-red); }
.gv-ruler:hover .gv-ruler__name { color: var(--gv-red); }
/* On a phone the label column would squeeze the track to nothing. */
@media (max-width: 40rem) {
  .gv-ruler-scale, .gv-ruler { grid-template-columns: 1fr; gap: var(--gv-space-2); }
  .gv-ruler { padding-block: var(--gv-space-3); min-height: 0; }
  .gv-ruler__track { min-height: 28px; }
}

/* A "text this store" action — the design pairs every phone number with an SMS link. */
.gv-sms {
  min-height: var(--gv-hit); display: inline-flex; align-items: center;
  font-family: var(--gv-font-display); font-size: var(--gv-text-fine);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  text-decoration: underline; text-decoration-color: var(--gv-red);
  text-decoration-thickness: 2px; text-underline-offset: .25em; color: var(--gv-ink);
}


/* ══ MODEL ROW ═════════════════════════════════════════════════════════════
   From the Claude Design series template: a big deck number, the model beside it, and one
   action — instead of a spec table, which is what most dealer sites reach for and what makes
   a lineup feel like a spreadsheet.
   The row has three cells; below 40rem the middle one is left with ~70px and the engine line
   wraps to five lines, so the action drops to its own row on a phone. */
.gv-modelrow {
  display: grid; grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: var(--gv-space-4); align-items: center;
  padding: var(--gv-space-5) var(--gv-space-3);
  border-bottom: 1px solid var(--gv-rule); text-decoration: none;
  transition: background var(--gv-dur-fast) var(--gv-ease);
}
.gv-modelrow:hover { background: var(--gv-ground-inset); }
.gv-modelrow__deck {
  font-family: var(--gv-font-display); font-weight: var(--gv-weight-black);
  font-size: 2rem; line-height: .9; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums; color: var(--gv-ink);
}
.gv-modelrow__name {
  font-family: var(--gv-font-display); font-weight: var(--gv-weight-display);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  font-size: var(--gv-text-small); color: var(--gv-ink);
}
.gv-modelrow__cta {
  grid-column: 1 / -1; display: flex; align-items: baseline; gap: var(--gv-space-4);
  border-top: 1px solid var(--gv-rule); padding-top: var(--gv-space-3);
}
.gv-modelrow__cta span {
  font-family: var(--gv-font-display); font-size: var(--gv-text-fine);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label); color: var(--gv-ink);
  text-decoration: underline; text-decoration-color: var(--gv-red);
  text-decoration-thickness: 2px; text-underline-offset: .25em;
}
@media (min-width: 40rem) {
  .gv-modelrow { grid-template-columns: 7.5rem minmax(0, 1fr) auto; gap: var(--gv-space-5); }
  .gv-modelrow__deck { font-size: 2.5rem; }
  .gv-modelrow__cta { grid-column: auto; display: grid; justify-items: end;
                      text-align: right; border-top: 0; padding-top: 0; }
}


/* ══ FINDER ════════════════════════════════════════════════════════════════
   From the Claude Design Finder: a progress bar, and option buttons that carry a plain-English
   note under the label — the note is what makes the choice answerable without a spec sheet. */
.gv-progress { height: 6px; background: var(--gv-ground-inset); margin-bottom: var(--gv-space-7); }
.gv-progress__bar { height: 6px; background: var(--gv-red); transition: width var(--gv-dur-slow) var(--gv-ease); }
.gv-opts {
  display: grid; gap: var(--gv-space-3);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.gv-opt {
  text-align: left; cursor: pointer; font-family: var(--gv-font-body);
  background: var(--gv-ground-inset); border: 2px solid var(--gv-hairline-light);
  border-radius: var(--gv-radius); padding: var(--gv-space-5);
  min-height: 88px; display: grid; gap: var(--gv-space-2); align-content: start;
  transition: background var(--gv-dur-fast) var(--gv-ease), border-color var(--gv-dur-fast) var(--gv-ease);
}
.gv-opt:hover { border-color: var(--gv-red); background: var(--gv-white); }
.gv-opt__label {
  font-family: var(--gv-font-display); font-weight: var(--gv-weight-display);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  font-size: var(--gv-text-small); color: var(--gv-black);
}
.gv-opt__note { font-size: var(--gv-text-small); color: var(--gv-gray-body-light); line-height: 1.4; }


/* ══ STORE PAGE ════════════════════════════════════════════════════════════
   From the Claude Design store template. */
.gv-storefront { height: clamp(20rem, 42vh, 30rem); background: var(--gv-ground-inset); }
.gv-storefront img { width: 100%; height: 100%; object-fit: cover; }

.gv-dl,
.gv-hours { margin: 0; border-top: 1px solid var(--gv-rule); }
.gv-hours { max-width: 32rem; }
.gv-dl__row,
.gv-hours__row {
  display: flex; justify-content: space-between; gap: var(--gv-space-4);
  padding: var(--gv-space-3) 0; border-bottom: 1px solid var(--gv-rule);
  min-height: var(--gv-hit); align-items: center;
}
.gv-dl dt,
.gv-hours dt {
  font-family: var(--gv-font-display); font-size: var(--gv-text-small);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
}
.gv-dl dd,
.gv-hours dd {
  margin: 0; font-family: var(--gv-font-display); font-size: var(--gv-text-small);
  letter-spacing: var(--gv-tracking-label); font-variant-numeric: tabular-nums;
}

/* A bordered card on an inset band — the store page's three service blocks. */
.gv-panel {
  background: var(--gv-ground-light); border: 1px solid var(--gv-hairline-light);
  padding: var(--gv-space-6); display: flex; flex-direction: column; gap: var(--gv-space-3);
}
.gv-panel h3 { font-size: var(--gv-text-h2); margin: 0; }
.gv-panel p { font-size: var(--gv-text-small); color: var(--gv-ink-muted); margin: 0; }


/* ══ SOLUTIONS ═════════════════════════════════════════════════════════════
   From the Claude Design solutions template. Two devices:

   .gv-duty  — the residential/commercial pair. The dark half re-points its ink
               tokens via .gv-dark; a band that paints its own ground and does not
               is how two earlier Koenig systems shipped black-on-black headings.
   .gv-lane  — a whole card that is a link, ending in a red-underlined chip that
               names the series behind it. Built on .gv-panel so the lane grid and
               the store page's service blocks cannot drift apart. */
.gv-duty {
  display: flex; flex-direction: column; gap: var(--gv-space-4);
  padding: var(--gv-space-6); border: 1px solid var(--gv-border-light);
}
.gv-duty.gv-dark { border-color: transparent; }
.gv-duty h3 { font-size: var(--gv-text-h2); margin: 0; }
.gv-duty > .gv-slab { align-self: flex-start; }
.gv-duty > .gv-btn { margin-top: auto; }

.gv-lane { text-decoration: none; transition: border-color var(--gv-dur-fast) var(--gv-ease); }
.gv-lane:hover, .gv-lane:focus-visible { border-color: var(--gv-red); }
.gv-lane .gv-eyebrow { margin: 0; }
.gv-lane__series {
  margin-top: auto; padding-top: var(--gv-space-4);
  border-top: 1px solid var(--gv-hairline-light);
  font-family: var(--gv-font-display); font-size: var(--gv-text-fine);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  text-decoration: underline; text-decoration-color: var(--gv-red);
  text-decoration-thickness: 2px; text-underline-offset: .25em;
}
/* .gv-electric re-points the ink tokens AND sets the dark electric ground — but it lives in
   tokens/base.css, which loads before this file, so .gv-panel's light background won it and the
   lane rendered white ink on a light ground (measured 1.00:1 on the h3). Restate the ground here
   rather than reorder the cascade; the divider and chip re-point with it. */
.gv-lane.gv-electric {
  background: var(--gv-electric-dark); border: 1px solid var(--gv-edge);
}
.gv-lane.gv-electric .gv-lane__series {
  border-top-color: var(--gv-rule); color: var(--gv-electric-blue); text-decoration: none;
}

/* ══ CHOICE CHIP ═══════════════════════════════════════════════════════════
   From the Claude Design quote template: a large tappable button that reads as a
   selected/unselected state rather than as a radio. The selected state is carried by
   [aria-pressed="true"] so a screen reader hears it too — the design expressed it with
   inline colours only, which is invisible to anything that is not looking. */
.gv-choice {
  cursor: pointer; text-align: left; border-radius: 0;
  border: 2px solid var(--gv-border-light); background: var(--gv-ground-light);
  color: var(--gv-ink); padding: var(--gv-space-4); min-height: var(--gv-hit);
  display: grid; gap: 4px; font-family: var(--gv-font-body);
  transition: border-color var(--gv-dur-fast) var(--gv-ease),
              background var(--gv-dur-fast) var(--gv-ease);
}
.gv-choice:hover { border-color: var(--gv-red); }
.gv-choice[aria-pressed="true"] {
  border-color: var(--gv-red); background: var(--gv-red); color: var(--gv-white);
}
.gv-choice__label {
  font-family: var(--gv-font-display); font-weight: var(--gv-weight-display);
  text-transform: uppercase; letter-spacing: var(--gv-tracking-label);
  font-size: var(--gv-text-small);
}
.gv-choice__note { font-size: var(--gv-text-fine); opacity: .8; }
.gv-choices {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: var(--gv-space-3);
}

/* The attachments page's fitment matrix: a yes is meant to be scannable down a column. */
.gv-spec td[data-fit="yes"] { font-family: var(--gv-font-display); font-weight: var(--gv-weight-display); }
.gv-spec td[data-fit="no"] { color: var(--gv-gray-body-light); }
.gv-att:hover { border-color: var(--gv-red); }

/* A series link that IS a card's heading is a tap target, not an inline body link, so the
   44px minimum applies to it — the WCAG 2.5.8 inline exception does not cover this one.
   Measured at 38px on the comparison page's head-to-head cards. */
.gv-h2h h3 a { display: inline-flex; align-items: center; min-height: var(--gv-hit); }

