/* ==========================================================================
   AKAI Mobile Detailing
   One stylesheet, no build step. Authored mobile-first: the base rules are
   the small-screen case and min-width queries layer on the larger layouts.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Fallback faces
   Futura and Avenir Next ship with macOS and iOS, so most visitors render
   them straight from the system with nothing downloaded. These self-hosted
   open faces cover everyone else: Jost is a Futura revival, Mulish sits
   close to Avenir Next. Both are variable, so one file serves every weight.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Jost";
  src: url("../fonts/jost-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Mulish";
  src: url("../fonts/mulish-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibm-plex-mono-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibm-plex-mono-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   2. Tokens
   Three layers: primitives hold raw values, semantic tokens name a role,
   component tokens name a part. Components only ever read the last two.
   -------------------------------------------------------------------------- */
:root {
  /* Color primitives */
  --color-black-950: #0a0a0b;
  --color-black-900: #151517;
  --color-red-500: #ef1b24;
  --color-red-700: #c91018;
  /* Small red text on paper or cream misses AA at both the values above
     (3.95 and 3.25 against the 4.5 body/control minimum). This darker step
     reads as the same brand red and clears it: 6.27 on paper, 5.17 on cream. */
  --color-red-800: #b60d14;
  /* Hero-headline accent only. Reds sit at a stubbornly mid-low luminance no
     matter how saturated, so against a flat dark overlay they need a much
     heavier scrim than a lighter warm tone does to hold 3:1 — measured at
     0.76 alpha for --color-red-500 versus 0.58 for this amber, against every
     current hero photo (docs/.work/measure_hero_flat.py). */
  --color-amber-500: #ff8a3d;
  --color-paper-50: #f8f4ed;
  --color-cream-100: #e8ded0;
  --color-sand-300: #cdbcaa;
  --color-white-warm: #fffdfa;
  /* #6c6761 from Design.md clears AA on paper (5.11) but not on the cream
     surface (4.21). Nudged darker so one token is safe on both: 6.22 / 5.13. */
  --color-neutral-600: #5f5a55;

  /* Alpha primitives */
  --alpha-ink-18: rgba(10, 10, 11, 0.18);
  --alpha-white-24: rgba(255, 255, 255, 0.24);
  --alpha-black-55: rgba(0, 0, 0, 0.55);

  /* Type primitives.
     Futura and Avenir Next ship with macOS/iOS and render natively there.
     Neither exists on Android or Windows, so those visitors fall through to
     the self-hosted Jost + Mulish (assets/fonts/*.woff2) automatically —
     verified via the font stack order below. */
  --font-display: "Futura", "Jost", "Avenir Next", sans-serif;
  --font-body: "Avenir Next", "Avenir", "Mulish", sans-serif;
  --font-label: "IBM Plex Mono", "Courier New", monospace;

  /* Layout primitives */
  --content-max: 1480px;
  --content-width: 92vw;
  --section-space: clamp(4.5rem, 10vw, 11rem);
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;

  /* Motion primitives */
  --ease-out-expressive: cubic-bezier(0.22, 1, 0.36, 1);
  --duration-fast: 180ms;
  --duration-medium: 420ms;
  --duration-slow: 800ms;

  /* Semantic */
  --surface-dark: var(--color-black-950);
  --surface-dark-raised: var(--color-black-900);
  --surface-light: var(--color-paper-50);
  --surface-warm: var(--color-cream-100);
  /* Red fields carrying warm-white labels. The 12px mono button label against
     #ef1b24 is only 4.26; against this it is 5.79. Design.md asks for AKAI red
     on the primary CTA and also for AA on controls — AA wins, and the deeper
     red is already in the palette. */
  --surface-accent: var(--color-red-700);

  --text-on-dark: var(--color-white-warm);
  --text-on-light: var(--color-black-950);
  --text-muted-on-light: var(--color-neutral-600);
  --text-muted-on-dark: rgba(255, 253, 250, 0.68);
  /* Surface-aware muted text. Flipped by the dark-surface rule below, the same
     way --text-accent is, so muted copy cannot end up light-on-light. */
  --text-muted: var(--text-muted-on-light);
  --text-accent: var(--color-red-800);

  --border-on-light: var(--alpha-ink-18);
  --border-on-dark: var(--alpha-white-24);
  --focus-ring: var(--color-red-500);

  --layout-shell: min(var(--content-width), var(--content-max));
  --layout-section-block: var(--section-space);
}

:root {
  /* Component */
  --header-bg: var(--surface-dark);
  --header-height: 4.25rem;
  --button-primary-bg: var(--surface-accent);
  --button-primary-text: var(--text-on-dark);
  --button-dark-bg: var(--surface-dark);
  --button-dark-text: var(--text-on-dark);
  --button-cream-bg: var(--surface-light);
  --button-cream-text: var(--text-on-light);
  --button-min-height: 3.65rem;
  --card-light-bg: var(--surface-light);
  --card-dark-bg: var(--surface-dark);
  --rule-light: var(--border-on-dark);
  --rule-dark: var(--border-on-light);
}

/* On ink the vivid AKAI red is the legible one (4.57) and the darker step is
   not, so red text flips back to it inside every dark surface. */
.hero,
.trust,
.process,
.setup,
.footer,
.mobile-menu,
.header,
.action-bar,
.breadcrumb,
.detail-hero,
.callout--dark,
.section--dark,
.service-card--featured,
.closing__panel {
  --text-accent: var(--color-red-500);
  --text-muted: var(--text-muted-on-dark);
}

@media (min-width: 64rem) {
  :root { --header-height: 5rem; }
}

/* --------------------------------------------------------------------------
   3. Reset
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

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

body {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--text-on-light);
  background: var(--surface-light);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Nothing may cause a sideways scrollbar at any width. `clip` rather than
     `hidden`: any non-visible overflow-x on body makes overflow-y compute to
     auto, which turns body into its own scroll container and breaks every
     position:sticky element on the page (they never release, because their
     containing block's bounds stop mattering once body itself is what
     scrolls). `clip` suppresses the horizontal overflow without creating a
     scrolling box. */
  overflow-x: clip;
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}

/* The width/height attributes every image carries (for layout stability) map
   to CSS presentational hints, and an explicit height beats aspect-ratio.
   Resetting height here lets aspect-ratio drive the box wherever it is set. */
img {
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button { background: none; border: 0; cursor: pointer; }

a { color: inherit; }

ul, ol { list-style: none; padding: 0; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  /* Futura's round O/C/G/Q jam together under the heavy negative tracking
     a grotesk can take, so the whole display scale is set looser. */
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   4. Accessibility helpers
   -------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -100%;
  z-index: 999;
  padding: var(--space-3) var(--space-5);
  background: var(--surface-accent);
  color: var(--text-on-dark);
  font-family: var(--font-label);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  transition: top var(--duration-fast) var(--ease-out-expressive);
}
.skip-link:focus { top: var(--space-4); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 4px;
}

/* --------------------------------------------------------------------------
   5. Layout
   -------------------------------------------------------------------------- */
.shell {
  width: var(--layout-shell);
  margin-inline: auto;
}

.section {
  padding-block: var(--layout-section-block);
}

.section--dark {
  background: var(--surface-dark);
  color: var(--text-on-dark);
}

.section--warm { background: var(--surface-warm); }

.rule {
  height: 1px;
  border: 0;
  background: var(--rule-dark);
}
.section--dark .rule { background: var(--rule-light); }

/* --------------------------------------------------------------------------
   6. Typography scale
   Ranges follow Design.md section 5.2, retuned for Futura: looser tracking
   and a slightly taller line box, because Futura's small x-height reads
   airy where a grotesk reads tight.
   -------------------------------------------------------------------------- */
.display-hero {
  font-family: var(--font-display);
  font-weight: 700;
  /* Capped at 7rem: the headline runs to four stacked lines, and Futura sets
     wider than a grotesk, so a taller cap overflows a 900px-tall viewport. */
  font-size: clamp(2.75rem, 9vw, 7rem);
  line-height: 0.9;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.display-section {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.25rem, 7.5vw, 5.5rem);
  line-height: 0.92;
  letter-spacing: -0.018em;
  text-transform: uppercase;
}

.display-card {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 5vw, 3.25rem);
  line-height: 0.96;
  letter-spacing: -0.015em;
  text-transform: uppercase;
}

/* Titles inside a narrow column size off that column, not the viewport.
   MAINTENANCE, EQUIPMENT and TRANSPARENT are long unbreakable words, and a
   vw-based size clips them once the grid goes multi-column — the exact defect
   visible in the previous build. */
.service-card,
.why__item,
.process__step {
  container-type: inline-size;
}

.service-card .display-card,
.why__item .display-card,
.process__step .display-card {
  font-size: clamp(1.5rem, 10cqi, 3rem);
}

.body-lg {
  font-size: clamp(1.05rem, 2.2vw, 1.35rem);
  line-height: 1.5;
  letter-spacing: -0.005em;
}

.kicker {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: clamp(0.68rem, 2.4vw, 0.78rem);
  line-height: 1.3;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-accent);
}

/* Small label introducing a gallery or an image strip. */
.section-label {
  margin-bottom: var(--space-3);
}

.meta {
  font-family: var(--font-label);
  font-weight: 500;
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   7. Buttons
   Rectangular, typographic, no rounding. Label is always mono.
   -------------------------------------------------------------------------- */
.btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: var(--button-min-height);
  padding: var(--space-4) var(--space-5);
  border: 1px solid transparent;
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.76rem;
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform var(--duration-fast) var(--ease-out-expressive),
    background-color var(--duration-fast) var(--ease-out-expressive),
    color var(--duration-fast) var(--ease-out-expressive);
}

/* Drawn rather than typed. As a text glyph the arrow inherited the 12px mono
   label size and rendered thin and faint; line-height:0 also collapsed its box
   to zero height. An SVG gives a controllable stroke weight at any size. */
.btn__arrow {
  flex: none;
  display: grid;
  place-items: center;
  transition: transform var(--duration-fast) var(--ease-out-expressive);
}
.btn__arrow svg { width: 1.5rem; height: 1.5rem; }

.btn--primary { background: var(--button-primary-bg); color: var(--button-primary-text); }
.btn--dark    { background: var(--button-dark-bg);    color: var(--button-dark-text); border-color: var(--border-on-dark); }
.btn--cream   { background: var(--button-cream-bg);   color: var(--button-cream-text); }

@media (hover: hover) {
  .btn:hover { transform: translateY(-3px); }
  .btn:hover .btn__arrow { transform: translateX(4px); }
  .btn--primary:hover { background: var(--color-red-700); }
  .btn--cream:hover   { background: var(--color-cream-100); }
  .btn--dark:hover    { background: var(--surface-dark-raised); }
}

/* Compact inline variant for links that sit inside body copy blocks. */
.link-more {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-accent);
  text-decoration: none;
  border-bottom: 2px solid currentColor;
  align-self: flex-start;
}
.link-more .link-arrow { flex: none; display: grid; place-items: center; }
.link-more .link-arrow svg { width: 1.35rem; height: 1.35rem; }

/* Boxed variant. On a card the "see everything included" link is the primary
   next step, and as a quiet inline link it vanished into the light field. */
.link-more--boxed {
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-4) var(--space-5);
  border: 2px solid var(--surface-accent);
  border-bottom-width: 2px;
  background: transparent;
  transition:
    background-color var(--duration-fast) var(--ease-out-expressive),
    color var(--duration-fast) var(--ease-out-expressive);
}
@media (hover: hover) {
  .link-more--boxed:hover {
    background: var(--surface-accent);
    color: var(--text-on-dark);
  }
}
.service-card--featured .link-more--boxed { border-color: var(--text-accent); }

/* --------------------------------------------------------------------------
   8. Header
   Opaque black at every scroll position and every width. Never translucent
   over photography, because the hero images sit directly beneath it.
   -------------------------------------------------------------------------- */
.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-height);
  background: var(--header-bg);
  color: var(--text-on-dark);
  border-bottom: 1px solid var(--rule-light);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  height: 100%;
  width: var(--layout-shell);
  margin-inline: auto;
}

.header__start,
.header__end {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.header__start { min-width: 0; }

.header__logo {
  display: flex;
  align-items: center;
  min-height: 44px;
  flex: none;
}
.header__logo img {
  height: clamp(1.9rem, 6.4vw, 2.9rem);
  width: auto;
}

.header__nav { display: none; }

.header__dropdown { position: relative; }
.header__dropdown-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
}
.header__dropdown-caret { width: 0.85em; height: 0.85em; transition: transform var(--duration-fast) var(--ease-out-expressive); }

.header__dropdown-panel {
  position: absolute;
  top: calc(100% + var(--space-4));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  min-width: 13rem;
  padding: var(--space-3) 0;
  background: var(--surface-dark);
  border: 1px solid var(--rule-light);
  visibility: hidden;
  opacity: 0;
  transform: translateX(-50%) translateY(-0.4rem);
  transition:
    opacity var(--duration-fast) var(--ease-out-expressive),
    transform var(--duration-fast) var(--ease-out-expressive),
    visibility 0s linear var(--duration-fast);
}
.header__dropdown-panel a {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  padding-inline: var(--space-5);
  white-space: nowrap;
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--text-muted-on-dark);
  transition: color var(--duration-fast) var(--ease-out-expressive), background-color var(--duration-fast) var(--ease-out-expressive);
}
.header__dropdown-panel a:hover {
  color: var(--text-on-dark);
  background: var(--alpha-white-24, rgba(255, 255, 255, 0.06));
}

.header__dropdown:hover .header__dropdown-panel,
.header__dropdown:focus-within .header__dropdown-panel,
.header__dropdown[data-open="true"] .header__dropdown-panel {
  visibility: visible;
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  transition-delay: 0s;
}
.header__dropdown:hover .header__dropdown-caret,
.header__dropdown:focus-within .header__dropdown-caret,
.header__dropdown[data-open="true"] .header__dropdown-caret {
  transform: rotate(180deg);
}

/* The phone number is the header's centrepiece on desktop. Hidden on small
   screens, where the sticky action bar carries it instead. */
.header__phone {
  display: none;
  flex-direction: column;
  gap: 1px;
  min-height: 44px;
  justify-content: center;
  text-decoration: none;
}
.header__phone .kicker { font-size: 0.6rem; letter-spacing: 0.16em; }
.header__phone strong {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.35rem;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--text-on-dark);
}

.header__book {
  display: none;
  min-height: 2.75rem;
  padding-inline: var(--space-5);
  justify-content: center;
}

/* Menu toggle: a 44x44 target with a two-bar mark that becomes an X. */
.menu-toggle {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
}
.menu-toggle__bars {
  position: relative;
  width: 22px;
  height: 2px;
  background: currentColor;
  transition: background-color var(--duration-fast) var(--ease-out-expressive);
}
.menu-toggle__bars::before,
.menu-toggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 22px;
  height: 2px;
  background: currentColor;
  transition: transform var(--duration-medium) var(--ease-out-expressive);
}
.menu-toggle__bars::before { top: -7px; }
.menu-toggle__bars::after  { top: 7px; }

.menu-toggle[aria-expanded="true"] .menu-toggle__bars { background: transparent; }
.menu-toggle[aria-expanded="true"] .menu-toggle__bars::before { transform: translateY(7px) rotate(45deg); }
.menu-toggle[aria-expanded="true"] .menu-toggle__bars::after  { transform: translateY(-7px) rotate(-45deg); }

/* Desktop header: logo on the left, phone + booking CTA on the right, nav
   centred in the bar. Below 80rem there may not be room to centre the nav
   without colliding with the logo or the phone/CTA group, so it flows inline
   next to the logo instead; only once the header is genuinely wide does it
   detach and centre itself against the header as a whole. */
@media (min-width: 64rem) {
  .header__inner { position: relative; }

  .header__nav {
    display: flex;
    align-items: center;
    gap: clamp(var(--space-5), 2.5vw, var(--space-7));
    margin-left: clamp(var(--space-5), 3vw, var(--space-8));
  }
  .header__nav > a,
  .header__dropdown-trigger {
    display: flex;
    align-items: center;
    min-height: 44px;
    white-space: nowrap;
    font-family: var(--font-label);
    font-weight: 600;
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--text-muted-on-dark);
    transition: color var(--duration-fast) var(--ease-out-expressive);
  }
  .header__nav > a:hover,
  .header__dropdown-trigger:hover,
  .header__dropdown:hover .header__dropdown-trigger,
  .header__dropdown:focus-within .header__dropdown-trigger { color: var(--text-on-dark); }

  /* Extra breathing room before the red CTA — with only header__end's
     regular gap, the phone number and the button read as one crowded
     cluster. */
  .header__phone { display: flex; margin-right: var(--space-6); }
  .header__book  { display: flex; white-space: nowrap; }
  .menu-toggle   { display: none; }
}

/* A three-column grid would force the side zones equal, and the left one needs
   more room than the right. Centring against the header itself lets the nav
   size to its own content — but only once there is genuinely room, so it can
   never collide with the logo or the phone/CTA group. */
@media (min-width: 80rem) {
  .header__nav {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    margin-left: 0;
  }
}

/* --------------------------------------------------------------------------
   9. Mobile menu
   Fully opaque panel. Phone number sits first, ahead of navigation, because
   calling is the most common thing a visitor wants from a phone.
   -------------------------------------------------------------------------- */
.mobile-menu {
  position: fixed;
  inset: var(--header-height) 0 0 0;
  z-index: 99;
  display: flex;
  flex-direction: column;
  padding: var(--space-6) 0 calc(var(--space-8) + env(safe-area-inset-bottom, 0px));
  background: var(--surface-dark);
  color: var(--text-on-dark);
  overflow-y: auto;
  visibility: hidden;
  opacity: 0;
  transform: translateY(-1rem);
  transition:
    opacity var(--duration-medium) var(--ease-out-expressive),
    transform var(--duration-medium) var(--ease-out-expressive),
    visibility 0s linear var(--duration-medium);
}
.mobile-menu[data-open="true"] {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0s;
}

.mobile-menu__inner {
  width: var(--layout-shell);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.mobile-menu__phone {
  display: block;
  text-decoration: none;
}
.mobile-menu__phone .kicker { margin-bottom: var(--space-2); }
.mobile-menu__phone strong {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2rem, 9vw, 2.75rem);
  line-height: 1;
  letter-spacing: -0.015em;
}

.mobile-menu__nav {
  display: flex;
  flex-direction: column;
}
.mobile-menu__nav a {
  display: flex;
  align-items: center;
  min-height: 3.5rem;
  border-bottom: 1px solid var(--rule-light);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  text-decoration: none;
}

/* Services accordion: a trigger row styled like its sibling links, expanding
   a panel of sub-links in place rather than navigating to index.html#services
   the way the flat link used to. */
.mobile-submenu__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 3.5rem;
  border: 0;
  border-bottom: 1px solid var(--rule-light);
  padding: 0;
  background: none;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: inherit;
  cursor: pointer;
}
.mobile-submenu__caret {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
  transition: transform var(--duration-fast) var(--ease-out-expressive);
}
.mobile-submenu[data-open="true"] .mobile-submenu__caret { transform: rotate(180deg); }

/* max-height rather than the grid-template-rows: 0fr/1fr trick — that
   technique doesn't reliably animate in WebKit/Safari, which is what
   produced the "stuck open, chevron doesn't collapse it" report on iPhone.
   max-height transitions are supported everywhere. 20rem comfortably clears
   five 3rem rows (15rem) with headroom for a sixth without clipping. */
.mobile-submenu__panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height var(--duration-medium) var(--ease-out-expressive);
}
.mobile-submenu[data-open="true"] .mobile-submenu__panel { max-height: 20rem; }
.mobile-submenu__panel-inner { display: flex; flex-direction: column; }
.mobile-submenu__panel-inner a {
  display: flex;
  align-items: center;
  min-height: 3rem;
  padding-left: var(--space-5);
  border-bottom: 1px solid var(--rule-light);
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--text-muted-on-dark);
}
.mobile-submenu__panel-inner a:last-child { border-bottom: 0; }

/* --------------------------------------------------------------------------
   10. Sticky mobile action bar
   Held back until the hero has scrolled away, so it never duplicates the
   hero's own actions. site.js toggles data-visible.
   -------------------------------------------------------------------------- */
.action-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 90;
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: var(--surface-dark);
  border-top: 1px solid var(--rule-light);
  transform: translateY(100%);
  transition: transform var(--duration-medium) var(--ease-out-expressive);
}
.action-bar[data-visible="true"] { transform: translateY(0); }

.action-bar a {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  min-height: 3.75rem;
  padding-inline: var(--space-3);
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--text-on-dark);
  text-align: center;
}
.action-bar__label {
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  color: var(--text-accent);
}
.action-bar a strong {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.15rem;
  line-height: 1;
  letter-spacing: -0.01em;
}
.action-bar__book { background: var(--surface-accent); }

@media (min-width: 48rem) {
  .action-bar { display: none; }
}

/* --------------------------------------------------------------------------
   11. Hero
   Mobile is the designed case: a full-height 9:16 frame with the headline in
   the clean sky at the top and the actions anchored over the pavement. The
   wide 21:9 art and the side-by-side composition arrive at 64rem.
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 100svh;
  padding-top: calc(var(--header-height) + var(--space-6));
  padding-bottom: var(--space-7);
  background: var(--surface-dark);
  color: var(--text-on-dark);
  overflow: hidden;
  isolation: isolate;
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -1;
}

/* Legibility scrim, not decoration — one flat tone across the whole frame
   rather than a gradient hugging the headline. A directional gradient could
   stay lighter overall since it only had to darken the text's own corner;
   a flat tone has to clear 3:1 everywhere the text might sit, including the
   brightest sky in the frame, which is why this reads darker than it looks
   like it should need to. 0.6 is the measured minimum for the amber accent
   above (0.58) plus a small margin, re-verified against every current hero
   photo at both breakpoints via docs/.work/measure_hero_flat.py — the cream
   lines clear the same bar with comfortable headroom to spare (6.0+). */
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 11, 0.6);
}

.hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--duration-slow) var(--ease-out-expressive);
}
.hero__slide[data-active="true"] { opacity: 1; }

/* <picture> is an inline box with auto height, so height:100% on the image
   would resolve against nothing. Give it a real box first. */
.hero__slide picture {
  display: block;
  width: 100%;
  height: 100%;
}

.hero__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Keeps the van in frame as the viewport narrows or shortens. */
  object-position: center 62%;
  /* Below 64rem the image is taller (relative to its width) than the hero
     box, so cover already shows its full height edge to edge — there's no
     vertical slack left for object-position to shift. A small scale-up from
     an origin above the van creates that slack, so the van (and the crowding
     against the headline above it) moves down instead of sitting fixed. */
  transform: scale(1.18);
  transform-origin: 50% 24%;
}

.hero__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.hero__title > span {
  display: block;
  /* A soft contact shadow, not the primary legibility mechanism — the flat
     overlay + color choice above already clear 3:1 on their own. This adds
     a real-world edge that keeps the glyphs crisp right at that boundary,
     the same way it would on any photo the scrim didn't fully anticipate. */
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.55);
}
/* Brand red measures a stubbornly mid-low luminance no matter the shade, so
   it needs a much darker overlay than a warm amber does to hold 3:1 against
   bright daytime photography — this hero-only accent trades literal red for
   legibility at a lighter scrim. See --color-amber-500 above. */
.hero__title .is-accent { color: var(--color-amber-500); }
/* AKAI red for the lower two lines, white for the upper two — the hero's
   plain white/red pairing rather than the amber accent used elsewhere. */
.hero__dark-text { color: var(--text-accent); }

/* The staggered indent is the brand's editorial signature. It only applies
   once there is room for it; on narrow screens every line starts flush. */
@media (min-width: 48rem) {
  .hero__title > span:nth-child(2) { margin-left: 0.08em; }
  .hero__title > span:nth-child(3) { margin-left: 0.16em; }
  .hero__title > span:nth-child(4) { margin-left: 0.24em; }
}

.hero__foot {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.hero__actions {
  display: flex;
  flex-direction: column;
  gap: 1px;
  max-width: 34rem;
}

.hero__phone {
  display: inline-flex;
  flex-direction: column;
  gap: var(--space-1);
  min-height: 44px;
  text-decoration: none;
  align-self: flex-start;
}
.hero__phone .kicker { color: var(--color-cream-100); }
.hero__phone strong {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 6vw, 2rem);
  line-height: 1;
  letter-spacing: -0.015em;
  color: var(--color-cream-100);
}

/* Carousel controls, shared by every rotating region on the page. */
.carousel-controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.carousel-btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border-on-dark);
  color: var(--text-on-dark);
  background: var(--alpha-black-55);
  transition:
    background-color var(--duration-fast) var(--ease-out-expressive),
    color var(--duration-fast) var(--ease-out-expressive);
}
.carousel-btn:hover { background: var(--surface-accent); }

.section--light .carousel-btn,
.carousel-controls--on-light .carousel-btn {
  border-color: var(--border-on-light);
  color: var(--text-on-light);
  background: transparent;
}
.carousel-controls--on-light .carousel-btn:hover {
  background: var(--surface-accent);
  color: var(--text-on-dark);
}

/* Controls share the last row with the phone number rather than floating over
   it. At 319px the two wrap onto separate lines instead of colliding. */
.hero__foot-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: flex-end;
  gap: var(--space-4);
}
.hero__controls { flex: none; }

/* A quiet cue that this is a full page, not just the hero — centred so it
   never competes with the carousel controls sitting at the right. */
.hero__scroll-cue {
  position: absolute;
  left: 50%;
  bottom: var(--space-4);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  /* Same white as the "Mobile Detailing" headline lines, so the cue reads as
     an obvious, intentional call to action rather than quiet chrome. */
  color: var(--text-on-dark);
  opacity: 1;
}
/* Below 48rem the fixed action bar owns the bottom edge, so lift the cue
   clear of it. */
@media (max-width: 47.999rem) {
  .hero__scroll-cue { bottom: calc(3.75rem + env(safe-area-inset-bottom, 0px) + var(--space-4)); }
}
.hero__scroll-cue-label {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
/* display:flex is the fix, not decoration: width/height do not apply to a
   plain inline span, so without it the child svg's 100%/100% has no
   definite box to resolve against and balloons toward the hero's own
   min-height: 100svh instead of staying a small icon. */
.hero__scroll-cue-icon { display: flex; align-items: center; justify-content: center; width: 1.5rem; height: 2.1rem; }
.hero__scroll-cue-icon svg { width: 100%; height: 100%; }

@keyframes hero-scroll-cue {
  0%, 100% { transform: translateY(0); opacity: 0.5; }
  50% { transform: translateY(5px); opacity: 1; }
}
.js .hero__scroll-cue-icon { animation: hero-scroll-cue 1.8s var(--ease-out-expressive) infinite; }

@media (prefers-reduced-motion: reduce) {
  .hero__scroll-cue-icon { animation: none; }
}

@media (min-width: 64rem) {
  .hero {
    justify-content: center;
    min-height: 100svh;
    padding-block: calc(var(--header-height) + var(--space-6)) var(--space-7);
  }
  /* Reset the mobile-only zoom: at this width the box is wide enough that
     cover already crops horizontally, giving real slack for object-position
     to do the framing on its own. */
  .hero__slide img { object-position: 70% center; transform: none; }
  .hero__content { gap: var(--space-6); }
  /* Copy occupies the left column; the art direction keeps the van clear of it
     on the right. Constrain the lines, not the shell — capping the shell and
     letting margin-inline:auto centre it would push the copy into the van. */
  .hero__title { max-width: 60%; }
  .hero__actions { max-width: 32rem; }

  /* Pulled out of the flex flow: with only two items, .hero's
     justify-content:center packs the title and foot block together and
     centers that group, rather than pinning the foot to the bottom the way
     mobile's space-between does. Anchoring the row straight to .hero
     (already position:relative) keeps the title's centering untouched. */
  .hero__foot-row {
    position: absolute;
    right: max(4vw, calc((100vw - var(--content-max)) / 2));
    bottom: var(--space-7);
  }
}

/* --------------------------------------------------------------------------
   12. Trust bar
   -------------------------------------------------------------------------- */
.trust {
  background: var(--surface-dark);
  color: var(--text-on-dark);
  border-block: 1px solid var(--rule-light);
}
.trust__list {
  display: grid;
  gap: 1px;
  background: var(--rule-light);
}

.trust__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-6) 0;
  background: var(--surface-dark);
}

.trust__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  color: var(--text-accent);
  border: 1px solid var(--rule-light);
}
.trust__icon svg { width: 1.75rem; height: 1.75rem; }

.trust__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  margin-bottom: var(--space-2);
}
.trust__body {
  color: var(--text-muted-on-dark);
  font-size: 0.95rem;
  line-height: 1.5;
  max-width: 38ch;
}

@media (min-width: 48rem) {
  .trust__list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
  }
  .trust__item { padding-inline: var(--space-5); }
  .trust__item:first-child { padding-left: 0; }
  .trust__item:last-child { padding-right: 0; }
  .trust__item + .trust__item { border-left: 1px solid var(--rule-light); }
}

/* --------------------------------------------------------------------------
   13. Shared section heading
   -------------------------------------------------------------------------- */
.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-bottom: var(--space-8);
}
.section-head__lead {
  max-width: 46ch;
  color: var(--text-muted-on-light);
}
.section--dark .section-head__lead { color: var(--text-muted-on-dark); }

@media (min-width: 64rem) {
  .section-head {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    align-items: end;
    column-gap: var(--space-8);
  }
  .section-head .kicker { grid-column: 1 / -1; }
}

/* --------------------------------------------------------------------------
   14. Intro / rotating vehicle gallery
   -------------------------------------------------------------------------- */
.intro { background: var(--surface-light); }

.intro__grid {
  display: grid;
  gap: var(--space-7);
}

.intro__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  max-width: 52ch;
}
.intro__copy p:not(.kicker) { color: var(--text-muted-on-light); }

.figure-frame {
  position: relative;
  background: var(--surface-dark);
  overflow: hidden;
}
.figure-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.slide-stack {
  position: relative;
  display: grid;
  aspect-ratio: 3 / 2;
}

/* Every slide occupies the same grid cell, so they overlay without absolute
   positioning and the container can still size itself to the tallest one. */
.slide-stack > .slide {
  grid-area: 1 / 1;
  min-width: 0;
  opacity: 0;
  transition: opacity var(--duration-medium) var(--ease-out-expressive);
}

/* No fixed ratio: the stack takes its height from the tallest slide. Each
   slide decides its own internal layout. */
.slide-stack--text {
  aspect-ratio: auto;
}
.slide-stack > .slide[data-active="true"] { opacity: 1; }
.slide-stack img { width: 100%; height: 100%; object-fit: cover; }

.slide-caption {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-top: var(--space-4);
  min-height: 5.5rem;
}
.slide-caption__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.35rem, 4.5vw, 2rem);
  line-height: 1;
  letter-spacing: -0.015em;
  text-transform: uppercase;
}
.slide-caption__meta {
  font-family: var(--font-label);
  font-weight: 500;
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-accent);
  min-height: 1.2em;
}

.carousel-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-4);
}

@media (min-width: 64rem) {
  .intro__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
    align-items: start;
    column-gap: var(--space-8);
  }
}

/* --------------------------------------------------------------------------
   15. Services
   Three cards. The middle one is the recommendation, so it carries the dark
   field and the badge. No nested cards, no rounding, hierarchy from type
   and rules alone.
   -------------------------------------------------------------------------- */
.services { background: var(--surface-warm); }

.services__grid {
  display: grid;
  gap: var(--space-6);
}

.service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--card-light-bg);
  border: 1px solid var(--border-on-light);
  container-type: inline-size;
}

/* Scroll cue: a red rule wipes across the top edge as the card enters view,
   marking where one service ends and the next begins. Purely additive — the
   card is fully readable before, during and after. */
.js .service-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--surface-accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--duration-slow) var(--ease-out-expressive);
  transition-delay: var(--reveal-delay, 0ms);
}
.js .service-card[data-revealed="true"]::before { transform: scaleX(1); }

.service-card--featured {
  background: var(--card-dark-bg);
  color: var(--text-on-dark);
  border-color: transparent;
}
.service-card--featured .service-card__cond,
.service-card--featured .service-card__body { color: var(--text-muted-on-dark); }
.service-card--featured .service-card__list li { border-color: var(--rule-light); }

.service-card__media {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--surface-dark);
}
.service-card__media img { width: 100%; height: 100%; object-fit: cover; }

/* Badges sit in their own row beneath the media so they can never cover the
   condition label or the title. */
.service-card__flags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5) 0;
}
.badge {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  background: var(--surface-accent);
  color: var(--text-on-dark);
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  /* Hard guarantee against the label ever wrapping onto two lines — the
     services grid jumps straight to 3 equal columns at 64rem, and a card
     that briefly carries two badges (the featured one) has less room per
     badge right at that jump than the browser's flex-wrap math assumes. */
  white-space: nowrap;
}
.badge--quiet {
  background: transparent;
  color: var(--text-muted-on-light);
  border: 1px solid var(--border-on-light);
}
.service-card--featured .badge--quiet {
  color: var(--text-muted-on-dark);
  border-color: var(--rule-light);
}

/* The pinch zone: cards are narrowest right as the 3-column grid engages,
   before the shell has grown enough to give them breathing room again. The
   featured card carries two badges here, so it needs the extra margin the
   others don't. */
@media (min-width: 64rem) and (max-width: 75rem) {
  .badge {
    padding: calc(var(--space-2) * 0.75) calc(var(--space-3) * 0.75);
    font-size: 0.56rem;
    letter-spacing: 0.1em;
  }
}

.service-card__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  flex: 1;
}

/* "Maintenance" is long enough to wrap the title onto a third line at this
   column width while "Standard" and "Reset" hold to two, which knocks the
   condition line and everything below it out of alignment across the row.
   Reserving space for three lines keeps every card's body content starting
   at the same height regardless of how its own title wraps. */
.service-card__inner h3.display-card {
  min-height: 3.05em;
}

.service-card__cond {
  font-family: var(--font-label);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted-on-light);
}

.service-card__body { color: var(--text-muted-on-light); }

.service-card__lists {
  display: grid;
  gap: var(--space-5);
  padding-block: var(--space-2);
}

.service-card__list h4 {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  margin-bottom: var(--space-3);
}
.service-card__list--in h4  { color: var(--text-accent); }
.service-card__list--out h4 { color: var(--text-muted-on-light); }
.service-card--featured .service-card__list--out h4 { color: var(--text-muted-on-dark); }

.service-card__list li {
  padding-block: var(--space-2);
  border-top: 1px solid var(--border-on-light);
  font-size: 0.95rem;
  line-height: 1.45;
}

/* Price rail: the vehicle selector and the live price share one band. */
.price-rail {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: auto;
  padding: var(--space-5);
  background: var(--surface-accent);
  color: var(--text-on-dark);
}

.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field > label {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.field select {
  min-height: 3rem;
  padding: var(--space-3) var(--space-4);
  background: transparent;
  color: inherit;
  border: 1px solid currentColor;
  border-radius: 0;
  font-family: var(--font-body);
  font-size: 1rem;
  /* The native arrow is hard to see on a red field, so draw our own. */
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 1.25rem) calc(50% + 2px),
    calc(100% - 0.9rem) calc(50% + 2px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
.field select option { color: var(--text-on-light); }

.price-readout {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
}
.price-readout__item { display: flex; flex-direction: column; gap: var(--space-1); }
.price-readout__item span:first-child {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.85;
}
.price-readout__value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.25rem, 8vw, 3rem);
  line-height: 0.95;
  letter-spacing: -0.02em;
}

.service-card__ctas {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

@media (min-width: 48rem) {
  .service-card__lists { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 64rem) {
  .services__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: stretch;
  }
  .service-card__lists { grid-template-columns: minmax(0, 1fr); }
}

@media (min-width: 90rem) {
  .service-card__lists { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   16. Process
   Manual only. Nothing here is tied to scroll position.
   -------------------------------------------------------------------------- */
.process { background: var(--surface-dark); color: var(--text-on-dark); }

/* One slide holds both the photograph and its copy, so a single carousel
   drives them together. Splitting them into two parallel slide groups under
   one root made every [data-slide] query return both sets. */
.process__slide {
  display: grid;
  gap: var(--space-6);
  align-content: start;
}

.process__figure { background: var(--surface-dark-raised); }
.process__figure img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

.process__step { display: flex; flex-direction: column; gap: var(--space-4); }
.process__step-index {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: var(--text-accent);
}
.process__step-body { color: var(--text-muted-on-dark); max-width: 46ch; }

@media (min-width: 64rem) {
  .process__slide {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    align-items: center;
    column-gap: var(--space-8);
  }
  .process__figure img { aspect-ratio: 3 / 2; }
}

/* --------------------------------------------------------------------------
   17. Gallery of results
   -------------------------------------------------------------------------- */
.gallery { background: var(--surface-light); }
.gallery__stage .slide-stack { aspect-ratio: 4 / 3; }

@media (min-width: 48rem) {
  .gallery__stage .slide-stack { aspect-ratio: 16 / 9; }
}
@media (min-width: 64rem) {
  .gallery__stage .slide-stack { aspect-ratio: 21 / 9; }
}

/* --------------------------------------------------------------------------
   18. Why work with us
   Four reasons carry no imagery of their own; a separate strip below does
   the visual work, so the reasons stay typographic.
   -------------------------------------------------------------------------- */
.why { background: var(--surface-light); }

.why__grid {
  display: grid;
  gap: 1px;
  background: var(--border-on-light);
  border-block: 1px solid var(--border-on-light);
}
.why__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6) 0;
  background: var(--surface-light);
}
.why__item p { color: var(--text-muted-on-light); }

.why__strip {
  display: grid;
  gap: var(--space-4);
}
.why__strip figure { display: flex; flex-direction: column; gap: var(--space-3); }
.why__strip img { aspect-ratio: 4 / 5; width: 100%; object-fit: cover; }

@media (min-width: 48rem) {
  .why__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .why__item { padding-inline: var(--space-6); }
  .why__strip { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
  .why__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   19. Mobile setup
   -------------------------------------------------------------------------- */
.setup { background: var(--surface-dark); color: var(--text-on-dark); }

.setup__media {
  display: grid;
  gap: var(--space-4);
  margin-bottom: var(--space-7);
}
.setup__media img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }

.setup__facts {
  display: grid;
  gap: 1px;
  background: var(--rule-light);
  border-block: 1px solid var(--rule-light);
}
.setup__fact {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5) 0;
  background: var(--surface-dark);
}
.setup__fact p { color: var(--text-muted-on-dark); }
.setup__fact h3 {
  font-size: 1.05rem;
  letter-spacing: -0.005em;
}

@media (min-width: 48rem) {
  .setup__media { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .setup__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .setup__fact { padding-inline: var(--space-5); }
}
@media (min-width: 64rem) {
  .setup__facts { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   20. Reviews
   -------------------------------------------------------------------------- */
.reviews { background: var(--surface-warm); }

/* Head and quote sit side by side on wide screens. Left as a single column the
   section left more than half its width empty, which reads as unfinished
   rather than as deliberate space. */
@media (min-width: 64rem) {
  .reviews__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    column-gap: var(--space-8);
    align-items: start;
  }
  /* align-items:end is inherited from the grid rule above; in a column flex
     that means the right edge, which pushed the kicker off to the side. */
  .reviews__grid .section-head {
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
  .reviews__grid .review__quote { font-size: clamp(1.5rem, 2.6vw, 2.4rem); }
}

.review {
  display: none;
  flex-direction: column;
  gap: var(--space-5);
  max-width: 58ch;
}
.review[data-active="true"] { display: flex; }

.review__quote {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.35rem, 4.2vw, 2.15rem);
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-transform: none;
}
.review__who {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.review__name {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.review__meta {
  font-family: var(--font-label);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-accent);
  min-height: 1.2em;
}

/* --------------------------------------------------------------------------
   21. FAQ
   -------------------------------------------------------------------------- */
.faq { background: var(--surface-light); }

.faq__list { border-top: 1px solid var(--border-on-light); }

.faq__item { border-bottom: 1px solid var(--border-on-light); }

.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  min-height: 4rem;
  padding-block: var(--space-4);
  cursor: pointer;
  list-style: none;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.05rem, 3.4vw, 1.4rem);
  letter-spacing: -0.01em;
  text-transform: uppercase;
}
.faq__item summary::-webkit-details-marker { display: none; }

.faq__sign {
  flex: none;
  width: 20px; height: 20px;
  position: relative;
}
.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 2px;
  background: var(--text-accent);
  transition: transform var(--duration-medium) var(--ease-out-expressive);
}
.faq__sign::after { transform: rotate(90deg); }
.faq__item[open] .faq__sign::after { transform: rotate(0deg); }

.faq__answer {
  padding-bottom: var(--space-5);
  max-width: 62ch;
  color: var(--text-muted-on-light);
}

/* --------------------------------------------------------------------------
   21.5 Service area grid
   Small representative photos, not full-bleed heroes — the point is breadth
   of coverage, not another set of hero images.
   -------------------------------------------------------------------------- */
.area-group + .area-group { margin-top: var(--space-8); }
.area-group > h3 {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  color: var(--text-accent);
  margin-bottom: var(--space-2);
}
.area-group > p {
  color: var(--text-muted-on-light);
  max-width: 62ch;
  margin-bottom: var(--space-5);
}

.area-grid {
  display: grid;
  gap: var(--space-7) var(--space-5);
}
.area-card__media { aspect-ratio: 4 / 3; }

@media (min-width: 40rem) {
  .area-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
  .area-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   22. Closing CTA
   Deliberately a bright daylight photograph, not a near-black frame.
   -------------------------------------------------------------------------- */
.closing { position: relative; isolation: isolate; overflow: hidden; background: var(--surface-dark); }
.closing__media { position: absolute; inset: 0; z-index: -2; }
.closing__media picture { display: block; width: 100%; height: 100%; }
.closing__media img { width: 100%; height: 100%; object-fit: cover; }

/* On a narrow screen a full-bleed photograph and a large opaque panel cannot
   both read, so they stack instead of overlapping and the van stays visible. */
@media (max-width: 47.999rem) {
  .closing { display: flex; flex-direction: column; }
  .closing__media { position: static; }
  .closing__media img { height: auto; aspect-ratio: 4 / 5; }
  .closing__panel { background: transparent; padding: 0; max-width: none; }
  .closing__inner { padding-block: var(--space-8); }
}

.closing__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding-block: var(--section-space);
}
.closing__panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-6);
  background: var(--surface-dark);
  color: var(--text-on-dark);
  max-width: 44rem;
}
.closing__panel p:not(.kicker) { color: var(--text-muted-on-dark); }

.closing__ctas { display: flex; flex-direction: column; gap: var(--space-3); }

@media (min-width: 48rem) {
  .closing__ctas { flex-direction: row; }
  .closing__ctas .btn { flex: 1; }
}

/* --------------------------------------------------------------------------
   23. Footer
   -------------------------------------------------------------------------- */
.footer { background: var(--surface-dark); color: var(--text-on-dark); }

.footer__top {
  display: grid;
  gap: var(--space-7);
  padding-block: var(--space-8);
}

.footer__brand { display: flex; flex-direction: column; gap: var(--space-4); max-width: 40ch; }
/* align-self stops the flex column stretching the logo to the full column
   width, which would override width:auto and distort it. */
.footer__brand img { height: 2.25rem; width: auto; align-self: flex-start; }
.footer__brand p { color: var(--text-muted-on-dark); }

.footer__cols { display: grid; gap: var(--space-6); }
.footer__col h3 {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  margin-bottom: var(--space-3);
  color: var(--text-accent);
}
.footer__col li + li { margin-top: var(--space-1); }
.footer__col a,
.footer__col span {
  display: inline-flex;
  align-items: center;
  /* A flex container drops the whitespace text node between the label and the
     injected phone number, so the gap has to be explicit. */
  gap: 0.35ch;
  min-height: 32px;
  color: var(--text-muted-on-dark);
  text-decoration: none;
  font-size: 0.95rem;
}
.footer__col a:hover { color: var(--text-on-dark); }

.footer__media { position: relative; }
.footer__media .slide-stack { aspect-ratio: 16 / 9; }

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: space-between;
  padding-block: var(--space-5);
  border-top: 1px solid var(--rule-light);
  color: var(--text-muted-on-dark);
}

/* The sticky bar covers the last strip of the page on small screens. */
@media (max-width: 47.999rem) {
  .footer__bottom { padding-bottom: calc(var(--space-8) + env(safe-area-inset-bottom, 0px)); }
}

@media (min-width: 48rem) {
  .footer__cols { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
  .footer__top { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); column-gap: var(--space-8); }
  .footer__media { grid-column: 1 / -1; }
}

/* --------------------------------------------------------------------------
   24. Detail pages
   Shared by the three service pages. Everything below reuses the tokens and
   the carousel markup already defined above.
   -------------------------------------------------------------------------- */

/* Breadcrumb — required on every page except the homepage. It is the first
   thing under the fixed header, so it carries the offset that clears it. The
   homepage does not need this because its hero pads itself. */
.breadcrumb {
  padding-top: var(--header-height);
  background: var(--surface-dark);
  color: var(--text-on-dark);
  border-bottom: 1px solid var(--rule-light);
}
.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding-block: var(--space-4);
  font-family: var(--font-label);
  font-weight: 500;
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.breadcrumb a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  color: var(--text-accent);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.breadcrumb a:hover { border-bottom-color: currentColor; }
.breadcrumb li[aria-current] { color: var(--text-muted-on-dark); }
.breadcrumb .sep { color: var(--text-muted-on-dark); }

/* Hero: copy panel and photograph side by side, price rail spanning below. */
.detail-hero { background: var(--surface-dark); color: var(--text-on-dark); }

.detail-hero__top { display: grid; }

.detail-hero__media img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }

/* The copy sits in a grid column, so it cannot use .shell — auto margins have
   nothing to centre against there. It pads itself to the same 4vw gutter the
   shell uses, and holds that alignment once the shell hits its max width. */
.detail-hero__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding-block: var(--space-8);
  padding-inline: 4vw;
  container-type: inline-size;
}
.detail-hero__copy .body-lg { color: var(--text-muted-on-dark); max-width: 46ch; }

/* "Maintenance" is eleven unbreakable characters. Sized off the viewport it
   overruns the column — the same defect this page exists to avoid. */
.detail-hero__copy h1 {
  font-size: clamp(2rem, 11cqi, 4.5rem);
}

/* The rail runs edge to edge; its contents line up with the shell inside. */
.price-rail--wide {
  /* The base .price-rail pads all four sides. This variant runs edge to edge
     and lets the .shell inside set the gutter, so the inline padding has to go
     — otherwise it stacks with the shell's 92vw and overflows narrow screens. */
  padding: var(--space-6) 0;
  background: var(--surface-accent);
  color: var(--text-on-dark);
}
.price-rail__grid {
  display: grid;
  gap: var(--space-5);
}
.price-rail--wide .field select { max-width: 26rem; }

@media (min-width: 64rem) {
  .detail-hero__top {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: stretch;
  }
  .detail-hero__copy {
    padding-block: var(--space-9);
    padding-inline-start: max(4vw, calc((100vw - var(--content-max)) / 2));
    padding-inline-end: var(--space-8);
    justify-content: center;
  }
  .detail-hero__media img { height: 100%; aspect-ratio: auto; min-height: 32rem; }
  .price-rail__grid {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) auto;
    align-items: end;
    column-gap: var(--space-7);
  }
}

/* Numbered process steps for what a service does and does not cover. */
.spec { display: grid; gap: var(--space-7); }

.spec__col h3 {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  color: var(--text-accent);
  margin-bottom: var(--space-4);
}

.spec__list { border-top: 1px solid var(--border-on-light); }
.section--dark .spec__list,
.spec--on-dark .spec__list { border-color: var(--rule-light); }

.spec__item {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--space-3);
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--border-on-light);
}
.section--dark .spec__item,
.spec--on-dark .spec__item { border-color: var(--rule-light); }

.spec__num {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: var(--text-accent);
  padding-top: 0.15em;
}
.spec__item h4 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.005em;
  margin-bottom: var(--space-2);
}
.spec__item p { color: var(--text-muted-on-light); font-size: 0.95rem; }
.section--dark .spec__item p,
.spec--on-dark .spec__item p { color: var(--text-muted-on-dark); }

@media (min-width: 64rem) {
  .spec { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-8); }
}

/* Exclusions, each with a photograph of the condition it refers to. */
.exclusions { display: grid; gap: var(--space-5); }
.exclusions figure { display: flex; flex-direction: column; gap: var(--space-3); }
.exclusions img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.exclusions figcaption h4 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  margin-bottom: var(--space-2);
}
.exclusions figcaption p { color: var(--text-muted-on-light); font-size: 0.95rem; }
.section--dark .exclusions figcaption p { color: var(--text-muted-on-dark); }

@media (min-width: 48rem) {
  .exclusions { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Video placeholder. Labelled, never dressed up as a real player. */
.film { position: relative; }
.film img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.film__tag {
  position: absolute;
  left: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  background: var(--surface-dark);
  color: var(--text-on-dark);
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Before and after: two frames side by side. Never a draggable slider. */
.ba__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--border-on-light);
}
.section--dark .ba__pair { background: var(--rule-light); }

.ba__frame { position: relative; background: var(--surface-dark); }
.ba__frame img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.ba__label {
  position: absolute;
  top: 0;
  left: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--surface-dark);
  color: var(--text-on-dark);
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.64rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.ba__frame--after .ba__label { background: var(--surface-accent); }

/* These frames are generated stand-ins, not client work. The note says so. */
.ba__disclaimer {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-on-light);
  font-family: var(--font-label);
  font-size: 0.68rem;
  line-height: 1.5;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted-on-light);
}
.section--dark .ba__disclaimer {
  border-color: var(--rule-light);
  color: var(--text-muted-on-dark);
}

/* Add-on rows. */
.addons { display: grid; gap: var(--space-5); }

.addon {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  padding-block: var(--space-5);
  border-top: 1px solid var(--border-on-light);
}
.addon img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.addon__media { display: flex; flex-direction: column; gap: var(--space-2); }
.addon__zoom {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.addon__zoom-label {
  font-family: var(--font-label);
  font-weight: 500;
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted-on-light);
  text-align: center;
}
.addon__body { display: flex; flex-direction: column; gap: var(--space-2); }
.addon__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.15rem;
  text-transform: uppercase;
  letter-spacing: -0.005em;
}
.addon__body p { color: var(--text-muted-on-light); font-size: 0.95rem; }

/* The honest caveat under an add-on. Set apart so it reads as a limit rather
   than as more sales copy. */
.addon__limit {
  font-family: var(--font-label);
  font-size: 0.7rem;
  line-height: 1.5;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted-on-light);
  border-left: 2px solid var(--surface-accent);
  padding-left: var(--space-3);
  margin-top: var(--space-1);
}

/* A vehicle-type control living on every add-on row, synced to the one in
   the hero (and to each other) via the shared [data-vehicle-sync] mechanism
   in site.js, so changing class anywhere updates every price on the page at
   once. .addon__aside lays it out next to that row's own price/duration
   figures: side by side on mobile, stacked with the select on top once the
   row goes horizontal at 48rem — see the media query below. */
.addon__aside {
  /* .addon's mobile grid only declares 2 explicit columns (media, body); as
     the 3rd auto-placed child this would otherwise land in a single 6.5rem
     cell under the thumbnail — nowhere near wide enough once a select joins
     the price figures here. Span the full row instead. */
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}
.addon-vehicle-select {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--surface-dark);
  color: var(--text-on-dark);
}
.addon-vehicle-select label {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}
@media (max-width: 29.99rem) {
  /* Below ~480px there isn't room for both the label and a full-width
     select next to the price without wrapping anyway — drop the visible
     label (kept for screen readers) so the control has a real chance of
     sitting on the same line as Add/Time on typical phone widths. */
  .addon-vehicle-select label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
.addon-vehicle-select select {
  min-height: 2.25rem;
  padding: 0 var(--space-6) 0 var(--space-3);
  background: transparent;
  color: inherit;
  border: 1px solid var(--rule-light);
  border-radius: 0;
  font-family: var(--font-body);
  font-size: 0.82rem;
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 1.1rem) calc(50% + 2px),
    calc(100% - 0.8rem) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.addon-vehicle-select select option { color: var(--text-on-light); }

@media (min-width: 48rem) {
  .addon__aside {
    /* .addon gains a real 3rd explicit column here (see grid-template-columns
       below), so .addon__aside is back to a normal single auto-placed cell
       rather than needing to span the row itself. */
    grid-column: auto;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
  }
  /* Source order stays figures-then-select (the select modifies the figures,
     so that's the more sensible reading/tab order); flipped visually so the
     select sits above the price it controls, per the desktop layout. */
  .addon__aside .addon__figures { order: 2; }
  .addon__aside .addon-vehicle-select { order: 1; }
}

/* Sub-heading inside the add-on catalogue. */
.addon-group + .addon-group { margin-top: var(--space-8); }
.addon-group > h3 {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  color: var(--text-accent);
  margin-bottom: var(--space-2);
}
.addon-group > p {
  color: var(--text-muted-on-light);
  max-width: 62ch;
  margin-bottom: var(--space-4);
}
.addon__figures {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-1);
}
.addon__figure { display: flex; flex-direction: column; gap: 2px; }
.addon__figure span:first-child {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted-on-light);
}
.addon__value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.5rem;
  line-height: 1;
  letter-spacing: -0.015em;
  color: var(--text-accent);
}

@media (min-width: 48rem) {
  .addon { grid-template-columns: 9rem minmax(0, 1fr) auto; align-items: center; }
  .addon__figures { margin-top: 0; flex-wrap: nowrap; }
}

/* Membership plan cards. The recommended cadence carries the dark field, the
   same way the recommended service does on the homepage. */
.plans { display: grid; gap: var(--space-5); }

.plan {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-6);
  background: var(--card-light-bg);
  border: 1px solid var(--border-on-light);
}
.plan--featured {
  background: var(--card-dark-bg);
  color: var(--text-on-dark);
  border-color: transparent;
}
.plan--featured .plan__base,
.plan--featured .plan__note { color: var(--text-muted-on-dark); }

.plan__cadence {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 5vw, 2.2rem);
  line-height: 1;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
.plan__pct {
  align-self: flex-start;
  padding: var(--space-2) var(--space-3);
  background: var(--surface-accent);
  color: var(--text-on-dark);
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.plan__final {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 9vw, 3.5rem);
  line-height: 0.95;
  letter-spacing: -0.02em;
  color: var(--text-accent);
}
.plan__base {
  font-family: var(--font-label);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted-on-light);
  text-decoration: line-through;
}
.plan__save {
  font-family: var(--font-label);
  font-weight: 600;
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-accent);
}
.plan__note { color: var(--text-muted-on-light); font-size: 0.92rem; margin-top: auto; }

@media (min-width: 48rem) {
  .plans { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Season strip. */
.seasons { display: grid; gap: var(--space-5); }
.seasons figure { display: flex; flex-direction: column; gap: var(--space-3); }
.seasons img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.seasons h3 {
  font-size: 1.15rem;
  letter-spacing: -0.005em;
  margin-bottom: var(--space-2);
}
.seasons p { color: var(--text-muted-on-light); }
.section--dark .seasons p { color: var(--text-muted-on-dark); }

@media (min-width: 48rem) {
  .seasons { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-8); }
}

/* Membership gallery grid. */
.plan-gallery { display: grid; gap: var(--space-4); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.plan-gallery img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
@media (min-width: 64rem) {
  .plan-gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Standalone callouts: membership, service area, deposit. */
.callout {
  display: grid;
  gap: var(--space-5);
  padding: var(--space-6);
  background: var(--surface-warm);
}
.callout p:not(.kicker) { color: var(--text-muted-on-light); max-width: 58ch; }

/* Declared after .callout p — same specificity, so order decides, and the dark
   variant has to win on a dark panel. */
.callout--dark { background: var(--surface-dark-raised); color: var(--text-on-dark); }
.callout--dark p:not(.kicker) { color: var(--text-muted-on-dark); }

@media (min-width: 64rem) {
  .callout {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    column-gap: var(--space-8);
    padding: var(--space-8);
  }
}

.split { display: grid; gap: var(--space-6); }
@media (min-width: 64rem) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-8); }
}

/* --------------------------------------------------------------------------
   24.5 Lightbox
   Full-screen enlarge for add-on example photos. One instance per page,
   repopulated by whichever trigger was tapped.
   -------------------------------------------------------------------------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: var(--space-6);
  background: var(--alpha-black-85, rgba(10, 10, 11, 0.92));
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--duration-medium) var(--ease-out-expressive), visibility 0s linear var(--duration-medium);
}
.lightbox[data-open="true"] {
  visibility: visible;
  opacity: 1;
  transition-delay: 0s;
}
.lightbox__stage { max-width: min(92vw, 42rem); max-height: 85vh; }
.lightbox__stage img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 85vh;
  object-fit: contain;
}
.lightbox__close {
  position: absolute;
  top: var(--space-5);
  right: var(--space-5);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  background: var(--alpha-white-24, rgba(255, 255, 255, 0.08));
  border: 1px solid var(--rule-light);
  color: var(--text-on-dark);
}
.lightbox__close svg { width: 1.15rem; height: 1.15rem; }

/* --------------------------------------------------------------------------
   25. Motion
   Entrance only, and only once. Content is fully readable without JS: the
   hidden state is applied by the .js class that site.js adds on load.
   -------------------------------------------------------------------------- */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity var(--duration-slow) var(--ease-out-expressive),
    transform var(--duration-slow) var(--ease-out-expressive);
}
.js [data-reveal][data-revealed="true"] {
  opacity: 1;
  transform: none;
}

/* Sequential facts stagger off a custom property set in the markup. */
.js [data-reveal][style*="--reveal-delay"] {
  transition-delay: var(--reveal-delay, 0ms);
}

/* --------------------------------------------------------------------------
   26. Reduced motion
   Complete behaviour, not a token gesture: no entrance offsets, no crossfade
   timing, no smooth scrolling. site.js separately disables autoplay and
   prints typed strings in full.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .js [data-reveal] { opacity: 1; transform: none; }
  .js .service-card::before { transform: scaleX(1); }
  .btn:hover { transform: none; }
}
