/* ==========================================================================
   BUTLER EXPRESS CAR WASH — Design System
   Mauldin, SC  ·  butlerexpresscarwash.com

   Concept: "White-glove service at lightning speed."
   The logo already carries both halves of the brand — a butler's bow tie and
   buttons (refined, attentive, sophisticated) struck through by a lightning
   bolt (fast, express). Every motif in this stylesheet comes from one of
   those two ideas. Nothing decorative was invented on top.

   Palette is sampled from the supplied logo PNG, not eyeballed:
     black  #000000   (wordmark)
     blue   #3D5AA6   (bolt + "EXPRESS")
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* --- Brand, sampled from the logo --- */
  --blue:        #3D5AA6;   /* exact logo blue. 6.55:1 with white — safe for
                               button fills AND as text on white. */
  --blue-deep:   #24376B;   /* pressed state, gradient foot, hairlines */
  --blue-bright: #6D8FE0;   /* links + accent text on the dark ground (6.15:1) */
  --blue-glow:   #8FADEF;   /* glows, focus rings, bolt highlights */

  /* --- VOLT. The one non-logo colour on the site, and it earns its place:
         the Free Wash offer is the #1 marketing CTA and needed to out-shout
         everything else. Yellow is what a lightning bolt actually looks
         like, it is the complement of the brand blue so it pops off the
         navy instead of fighting it, and it carries near-black text at
         13.3:1. Reserved for the Free Wash button and the offer bar —
         using it anywhere else kills the effect. --- */
  --volt:      #FFC42E;
  --volt-lift: #FFD84F;     /* gradient top / hover */
  --volt-deep: #F0A400;     /* gradient foot, pressed */

  /* --- Grounds. Near-black with a blue undertone, never flat #000 --- */
  --ink:    #0B0D14;        /* page ground */
  --ink-2:  #11141F;        /* raised bands */
  --ink-3:  #181C2A;        /* cards */
  --ink-4:  #232840;        /* card borders, rules */

  /* --- Neutrals --- */
  --white:      #FFFFFF;
  --silver:     #C9D2E3;    /* body copy on dark — 12.75:1 */
  --silver-dim: #8C97AE;    /* muted copy on dark — 6.60:1 */
  --paper:      #F5F7FB;    /* light sections */
  --paper-2:    #E7ECF5;    /* light section panels */
  --graphite:   #14161F;    /* body copy on light */

  /* --- Type --- */
  --font-display: 'Anton', 'Arial Narrow', sans-serif;
  --font-cond:    'Barlow Condensed', 'Arial Narrow', sans-serif;
  --font-body:    'Barlow', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* --- Layout --- */
  --wrap: 1200px;
  --wrap-wide: 1380px;
  --header-h: 78px;
  --gutter: clamp(18px, 4vw, 40px);

  /* --- Motion --- */
  --ease: cubic-bezier(.22, .61, .36, 1);

  /* --- Elevation --- */
  --glow-blue: 0 0 0 1px rgba(109,143,224,.28), 0 10px 40px -12px rgba(61,90,166,.55);
  --lift: 0 18px 46px -18px rgba(0,0,0,.85);

  /* --- The speed cut. Used on buttons, badges and eyebrows so the whole
         site leans forward the way the logo's italic wordmark does. --- */
  --cut: polygon(9px 0, 100% 0, calc(100% - 9px) 100%, 0 100%);
}

/* --------------------------------------------------------------------------
   2. RESET
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; scroll-padding-top: calc(var(--header-h) + 16px); }

body {
  background: var(--ink);
  color: var(--silver);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
button, input, select, textarea { font: inherit; color: inherit; }

/* Visible focus for keyboard users — never removed, only restyled. */
:focus-visible {
  outline: 3px solid var(--blue-glow);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute; left: 12px; top: -80px; z-index: 2000;
  background: var(--blue); color: var(--white);
  padding: 12px 20px; font-family: var(--font-cond); font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  transition: top .2s var(--ease);
}
.skip-link:focus { top: 12px; }

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

/* --------------------------------------------------------------------------
   3. TYPE SCALE
   -------------------------------------------------------------------------- */
/* Headings lean, because the logo leans - all three lines of the client's
   wordmark are italic, measured at 17.9deg off the straight stem of the E in
   EXPRESS. Anton ships no italic face, so this is a synthetic oblique and the
   browser fixes its own angle at roughly 9.5deg; `oblique 18deg` renders
   identically, so there is no way to match the logo exactly with real text.
   That is fine - half the lean still reads as the same voice, and a full 18deg
   shear on a face this heavy makes long headlines look like they are falling
   over. The lean stops at headings: nav, body and button labels stay upright.
   Buttons already carry the same slant in their clip-path, and italicising the
   label inside a slanted shape doubles one gesture and costs legibility on the
   most scannable element on the page. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;              /* Anton ships at one weight */
  font-style: italic;
  text-transform: uppercase;
  line-height: .96;
  letter-spacing: .005em;
  color: var(--white);
}

h1, h2, h3, h4 { overflow-wrap: break-word; }

h1 { font-size: clamp(2.6rem, 7.2vw, 5.4rem); }
h2 { font-size: clamp(2rem, 4.6vw, 3.4rem); }
h3 { font-size: clamp(1.25rem, 2.1vw, 1.6rem); }
h4 { font-size: clamp(1.05rem, 1.6vw, 1.22rem); }

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

.lead { font-size: clamp(1.08rem, 1.7vw, 1.28rem); line-height: 1.55; color: var(--silver); }
.muted { color: var(--silver-dim); }
.center { text-align: center; }
.nowrap { white-space: nowrap; }

/* The eyebrow quotes the logo's wide-tracked "E X P R E S S". It is the
   single most recognisable piece of the mark, so it becomes the site's
   section label. */
.eyebrow {
  display: inline-block;
  font-family: var(--font-cond);
  font-weight: 600;
  font-size: clamp(.78rem, 1.1vw, .9rem);
  text-transform: uppercase;
  letter-spacing: .42em;
  color: var(--blue-bright);
  margin-bottom: 14px;
  padding-left: .42em;      /* optical: compensates the trailing letterspace */
}

/* Accent word inside a headline */
.hl { color: var(--blue-bright); }

/* --------------------------------------------------------------------------
   4. LAYOUT
   -------------------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 var(--gutter); }
.wrap--wide { max-width: var(--wrap-wide); }
.wrap--narrow { max-width: 760px; }   /* single-column pages: the survey embed */

.section { padding: clamp(60px, 8vw, 116px) 0; position: relative; }
.section--tight { padding: clamp(44px, 5vw, 72px) 0; }

/* Raised dark band */
.section--raised { background: var(--ink-2); }

/* Light band — used sparingly, for legibility-heavy content (menus, forms) */
.section--light { background: var(--paper); color: var(--graphite); }
.section--light h1, .section--light h2, .section--light h3, .section--light h4 { color: var(--graphite); }
.section--light .eyebrow { color: var(--blue); }
.section--light .lead { color: #3A4051; }
.section--light .muted { color: #5A6274; }
.section--light .hl { color: var(--blue); }

.section-head { max-width: 760px; margin-bottom: clamp(32px, 4vw, 56px); }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.section-head p { margin-top: 16px; }

.grid { display: grid; gap: clamp(16px, 2.2vw, 28px); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(28px, 4vw, 64px); align-items: center; }
@media (max-width: 860px) { .split { grid-template-columns: minmax(0, 1fr); } }

/* Swaps the two columns on desktop only. The source order stays copy-first so
   that once the split stacks, the reader still gets the heading before the
   photo rather than a picture with no context. Paired to the 860px collapse
   above - move one, move both. */
@media (min-width: 861px) {
  .split--flip > :first-child { order: 2; }
  .split--flip > :last-child  { order: 1; }
}

/* --------------------------------------------------------------------------
   5. BRAND MOTIFS
   Three shapes, all lifted from the logo. Every icon, divider and marker on
   this site is one of them — that is what keeps it from looking generic.
   -------------------------------------------------------------------------- */

/* 5a. THE BOLT — a CSS-drawn lightning bolt echoing the logo's. Used as a
   list marker, step badge and divider centrepiece. No image request. */
.bolt {
  display: inline-block;
  width: 1em; height: 1em;
  background: currentColor;
  -webkit-mask: var(--bolt-mask) center / contain no-repeat;
          mask: var(--bolt-mask) center / contain no-repeat;
  flex-shrink: 0;
}
:root {
  --bolt-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M14.8 1 3.4 13.6h6.1L8.2 23l11.6-12.9h-6.3z' fill='%23000'/%3E%3C/svg%3E");
  --bowtie-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 20'%3E%3Cpath d='M13.4 10 1 2.2v15.6zM18.6 10 31 2.2v15.6zM16 6.6c1.6 0 2.6 1.4 2.6 3.4S17.6 13.4 16 13.4 13.4 12 13.4 10 14.4 6.6 16 6.6z' fill='%23000'/%3E%3C/svg%3E");
}
.bolt--lg { width: 1.5em; height: 1.5em; }

/* 5b. THE BOW TIE — the butler half of the mark. Reserved for
   "at your service" moments: the service badge and the footer seal. */
.bowtie {
  display: inline-block;
  width: 1.6em; height: 1em;
  background: currentColor;
  -webkit-mask: var(--bowtie-mask) center / contain no-repeat;
          mask: var(--bowtie-mask) center / contain no-repeat;
  flex-shrink: 0;
}

/* 5c. THE BUTTONS — the three dots running down the logo's shirt front.
   They become the site's divider rule and step connector. */
.dots {
  display: flex; gap: 7px; align-items: center; justify-content: center;
}
.dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--blue); }
.dots span:nth-child(2) { background: var(--blue-bright); }

/* Divider: hairline — buttons — hairline, with a bolt at centre.
   This is the site's section separator. */
.rule {
  display: flex; align-items: center; gap: 16px;
  justify-content: center;
  color: var(--blue);
  margin: 0 auto;
  max-width: 420px;
}
.rule::before, .rule::after {
  content: ''; flex: 1; height: 1px;
  background: linear-gradient(90deg, transparent, var(--blue-deep), transparent);
}

/* Diagonal bolt-streak used behind heroes and dark CTA bands. Pure CSS. */
.streak { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.streak::before,
.streak::after {
  content: '';
  position: absolute;
  width: 140%; height: 74px;
  left: -20%;
  background: linear-gradient(90deg, transparent, rgba(61,90,166,.30), rgba(143,173,239,.10), transparent);
  transform: rotate(-16deg);
  filter: blur(26px);
}
.streak::before { top: 16%; }
.streak::after  { top: 62%; opacity: .6; }

/* --------------------------------------------------------------------------
   6. BUTTONS  (locked system — nothing else may look like these)
      .btn--free   glowing blue    → free-wash.html      THE marketing CTA
      .btn--club   solid blue      → go-unlimited / e-comm
      .btn--ghost  outline         → everything else
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 52px;                    /* tap target */
  padding: 14px 30px;
  font-family: var(--font-cond);
  font-weight: 700; font-size: 1.02rem;
  text-transform: uppercase; letter-spacing: .1em;
  border: 2px solid transparent;
  cursor: pointer;
  clip-path: var(--cut);
  transition: background .25s var(--ease), color .25s var(--ease),
              transform .25s var(--ease), box-shadow .25s var(--ease);
  text-align: center;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn--club { background: var(--blue); color: var(--white); }
.btn--club:hover { background: #4668BE; }

/* THE Free Wash button. Volt yellow, near-black label, always glowing, with
   a light sweep crossing it — a bolt you cannot miss on a navy page. */
.btn--free {
  background: linear-gradient(180deg, var(--volt-lift) 0%, var(--volt) 52%, var(--volt-deep) 100%);
  color: #14161F;
  position: relative; overflow: hidden;
  box-shadow: 0 0 18px rgba(255,196,46,.45);
  animation: btnGlow 2.4s ease-in-out infinite alternate;
}
.btn--free:hover { background: linear-gradient(180deg, #FFE270 0%, var(--volt-lift) 52%, var(--volt) 100%); color: #14161F; }
.btn--free .bolt { color: #14161F; }
@keyframes btnGlow {
  from { box-shadow: 0 0 14px rgba(255,196,46,.42), 0 0 34px rgba(255,196,46,.14); }
  to   { box-shadow: 0 0 24px rgba(255,216,79,.70), 0 0 52px rgba(255,196,46,.30); }
}
/* Light sweeping across the button — the bolt, in motion. */
.btn--free::after {
  content: ''; position: absolute; inset: 0 auto 0 0;
  width: 46%; pointer-events: none;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.42), transparent);
  transform: translateX(-210%) skewX(-18deg);
  animation: btnSweep 4.2s ease-in-out infinite;
}
@keyframes btnSweep {
  0%, 14%   { transform: translateX(-210%) skewX(-18deg); }
  52%, 100% { transform: translateX(330%)  skewX(-18deg); }
}

/* Ghost buttons are NOT cut. A clip-path slices the left and right borders off
   an outlined button and leaves two floating rules, so the angled cut is
   reserved for the filled buttons. That also gives a cleaner hierarchy:
   cut + filled = act now, square + outlined = secondary. */
.btn--ghost { background: transparent; color: var(--white); border-color: rgba(201,210,227,.4); clip-path: none; }
.btn--ghost:hover { border-color: var(--blue-bright); color: var(--blue-bright); background: rgba(61,90,166,.1); }

.section--light .btn--ghost { color: var(--graphite); border-color: rgba(20,22,31,.28); }
.section--light .btn--ghost:hover { color: var(--blue); border-color: var(--blue); background: rgba(61,90,166,.07); }

.btn--lg { min-height: 60px; padding: 18px 40px; font-size: 1.14rem; }
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; }
.btn-row.center { justify-content: center; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn--free { animation: none; }
  .btn--free::after { animation: none; opacity: 0; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* --------------------------------------------------------------------------
   7. OFFER BAR + HEADER / NAV
   Duplicated per page (static site, no includes) — change one, change all.
   -------------------------------------------------------------------------- */

/* The offer bar sits above the header, same as the current site, and carries
   the Text Club offer. Volt underline on the link ties it to the CTA. */
.offer-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 910;
  background: var(--blue); color: var(--white);
  font-family: var(--font-cond); font-size: .95rem; letter-spacing: .03em;
}
.offer-bar__inner {
  max-width: var(--wrap-wide); margin: 0 auto; padding: 9px var(--gutter);
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
}
.offer-bar a.offer-bar__link { color: var(--white); font-weight: 600; }
.offer-bar a.offer-bar__link u { text-decoration-color: var(--volt); text-underline-offset: 3px; text-decoration-thickness: 2px; }
.offer-bar a.offer-bar__link:hover { color: var(--volt-lift); }
.offer-bar__manage {
  flex-shrink: 0; border: 1px solid rgba(255,255,255,.65);
  padding: 5px 15px; font-weight: 600; font-size: .86rem;
  text-transform: uppercase; letter-spacing: .08em;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.offer-bar__manage:hover { background: var(--white); color: var(--blue-deep); }
@media (max-width: 800px) {
  .offer-bar__manage { display: none; }
  .offer-bar__inner { justify-content: center; text-align: center; padding: 8px var(--gutter); }
  .offer-bar { font-size: .86rem; }
}

/* When the offer bar is present the header and main shift down by its height.
   Measured at runtime by js/main.js into --offer-h so the two never overlap. */
.has-offer { --offer-h: 40px; }
.has-offer .site-header { top: var(--offer-h); }
.has-offer main { padding-top: calc(var(--header-h) + var(--offer-h)); }
.has-offer { scroll-padding-top: calc(var(--header-h) + var(--offer-h) + 16px); }
@media (max-width: 1299px) {
  .has-offer .primary-nav { top: calc(var(--header-h) + var(--offer-h)); }
}

.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 900;
  height: var(--header-h);
  /* Transparent at the top of the page so the hero photo reads through the
     dark part of the bar. Not flat transparent: a soft top-down scrim keeps
     the nav legible over whatever the photo happens to be doing underneath.
     The white logo plate and the Free Wash button are separate elements and
     stay fully opaque.

     No backdrop-filter anywhere. It makes the header the containing block for
     its position:fixed children, which collapsed the mobile nav panel to a
     58px sliver — see the note in the mobile block below. */
  background: linear-gradient(180deg,
              rgba(11,13,20,.74) 0%,
              rgba(11,13,20,.38) 55%,
              rgba(11,13,20,.06) 100%);
  border-bottom: 1px solid transparent;
  /* The border row is outside the gradient's default origin box, so the
     gradient tiles and repaints its darkest stop there - a 1px rule across the
     hero photo. Spanning the border box kills it. */
  background-origin: border-box;
  transition: height .3s var(--ease), background .3s var(--ease), border-color .3s var(--ease);
}
/* Once the page scrolls, real content passes under the bar and it goes solid. */
.site-header.scrolled {
  height: 66px;
  background: rgba(11,13,20,.97);
  border-bottom-color: rgba(61,90,166,.28);
  box-shadow: 0 8px 30px rgba(0,0,0,.5);
}

/* THE LOGO PLATE
   The client's logo is black ink on transparent, which disappears on the
   near-black header. Rather than recolour their mark, the left end of the
   header is a white panel with a slanted right edge, so the logo can sit on
   the white it was drawn for. The slant is the same lean as the buttons
   (--cut), so it reads as part of the system rather than a patch.

   The panel is a pseudo-element on the header, not on .brand, for two
   reasons: it has to bleed to the viewport's left edge even when .header-inner
   is centred inside its 1380px max-width, and clipping .brand itself would
   clip its focus ring.

   Width is pure CSS, no JS: half the viewport minus half the wrap gets you to
   where .header-inner starts, then the gutter and the logo block. On screens
   narrower than the wrap that first term goes negative, so max() falls back to
   the gutter plus the logo block. --brand-w is the logo's rendered width plus
   breathing room, and it shrinks with the logo on scroll and on mobile. */
.site-header { --brand-w: 176px; }
.site-header.scrolled { --brand-w: 150px; }

/* Once the header has hit its max-width the nav stops drifting and a stable
   57px sits between the plate and "Wash Shop". Above that point the plate
   takes half of it, which reads as deliberate spacing rather than a gap.
   Below 1400px the header is still full-width, space-between pulls the nav
   in (only 7px clear at 1280px), and the same nudge would collide with it. */
@media (min-width: 1400px) {
  .site-header { --brand-w: 205px; }
  .site-header.scrolled { --brand-w: 179px; }
}

.site-header::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: max(
    calc(50% - (var(--wrap-wide) / 2) + var(--gutter) + var(--brand-w)),
    calc(var(--gutter) + var(--brand-w))
  );
  background: #FFFFFF;
  clip-path: polygon(0 0, 100% 0, calc(100% - 26px) 100%, 0 100%);
  transition: width .3s var(--ease);
}

.header-inner {
  position: relative;            /* paints above the plate */
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  height: 100%; width: 100%; max-width: var(--wrap-wide); margin: 0 auto;
  padding: 0 var(--gutter);
}

.brand { position: relative; display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
.brand img { height: 52px; width: auto; transition: height .3s var(--ease); }
.scrolled .brand img { height: 42px; }

/* The header uses the client's ORIGINAL logo, unmodified, because the plate
   above gives it the white ground it was drawn for. The reverse variant is
   still used in the footer and on the landing pages, which have no plate.
   Both files and the recipe are in assets/logo/README.md. */

.primary-nav ul { display: flex; align-items: center; gap: 4px; }
.primary-nav a {
  display: block; position: relative; white-space: nowrap;
  font-family: var(--font-cond); font-weight: 600; font-size: .95rem;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--silver); padding: 10px 11px;
  transition: color .22s var(--ease);
}
.primary-nav a:hover, .primary-nav a[aria-current="page"] { color: var(--white); }
.primary-nav a::after {
  content: ''; position: absolute; left: 13px; bottom: 4px; height: 2px; width: 0;
  background: var(--blue-bright);
  transition: width .25s var(--ease);
}
.primary-nav a:hover::after, .primary-nav a[aria-current="page"]::after { width: calc(100% - 26px); }

.nav-drop { position: relative; }
.nav-drop > a { display: inline-flex; align-items: center; gap: 5px; }
.nav-drop > a svg { transition: transform .25s var(--ease); }
.nav-drop:hover > a svg, .nav-drop:focus-within > a svg { transform: rotate(180deg); }
.nav-drop ul {
  position: absolute; top: 100%; left: 0; min-width: 214px; display: block;
  background: var(--ink-3); border: 1px solid var(--ink-4);
  padding: 6px 0; box-shadow: var(--lift);
  opacity: 0; visibility: hidden; transform: translateY(8px);
  transition: all .25s var(--ease);
}
.nav-drop:hover ul, .nav-drop:focus-within ul { opacity: 1; visibility: visible; transform: translateY(0); }
.nav-drop ul a { padding: 11px 18px; font-size: .9rem; }
.nav-drop ul a::after { display: none; }
.nav-drop ul a:hover { background: rgba(61,90,166,.16); color: var(--blue-bright); }

.header-ctas { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.header-ctas .btn { min-height: 44px; padding: 10px 20px; font-size: .92rem; }

.nav-toggle {
  display: none; flex-direction: column; gap: 5px;
  background: none; border: 0; cursor: pointer; padding: 10px; z-index: 950;
}
.nav-toggle span { display: block; width: 26px; height: 2px; background: var(--white); transition: transform .28s var(--ease), opacity .2s; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Collapse point is 1120px: the nav carries 7 items plus two CTAs. */
@media (max-width: 1299px) {
  /* Collapses at 1299px, not 1200px. Below ~1265px the logo plate and the
     first nav item collide — space-between pulls the nav left faster than the
     plate shrinks, and the white plate ends up under white nav text. The
     hamburger has room to spare, so the bar only runs where it actually fits. */
  .nav-toggle { display: flex; }
  .site-header { --brand-w: 160px; }
  .site-header.scrolled { --brand-w: 140px; }

  /* The nav panel is position:fixed inside the header, so the header must not
     become its containing block. backdrop-filter would do exactly that and
     collapse the panel to a 58px sliver, which is why there is none anywhere
     in this stylesheet. Do not add one. */
  .primary-nav {
    position: fixed; inset: var(--header-h) 0 0 0;
    background: var(--ink); padding: 18px var(--gutter) 40px;
    overflow-y: auto;
    transform: translateX(100%); transition: transform .32s var(--ease);
  }
  .primary-nav.open { transform: translateX(0); }
  .primary-nav ul { flex-direction: column; align-items: stretch; gap: 0; }
  .primary-nav > ul > li { border-bottom: 1px solid var(--ink-4); }
  .primary-nav a { padding: 16px 4px; font-size: 1.12rem; }
  .primary-nav a::after { display: none; }
  .nav-drop ul {
    position: static; opacity: 1; visibility: visible; transform: none;
    background: transparent; border: 0; box-shadow: none; padding: 0 0 8px 18px;
  }
  .nav-drop > a svg { display: none; }
  body.nav-open { overflow: hidden; }
  /* With the nav pulled out of flow, space-between leaves the hamburger
     stranded mid-header. Group it with the CTA on the right instead. */
  .header-ctas { order: 2; margin-left: auto; }
  .nav-toggle  { order: 3; margin-right: -10px; }
}
@media (max-width: 460px) {
  .header-ctas .btn { padding: 10px 13px; font-size: .82rem; letter-spacing: .05em; }
  .brand img { height: 38px; }
  .site-header, .site-header.scrolled { --brand-w: 122px; }
}
/* On the narrowest phones the full "Get Your Free Wash" label collides with the
   logo and the hamburger, so it drops back to "Free Wash". Same button, same
   destination — only the label shortens. */
@media (max-width: 409px) {
  .header-ctas .cta-long { display: none; }
}

/* Pages that hide the header (free-wash, thank-you, ad landers) */
.no-header .site-header { display: none; }
.no-header main { padding-top: 0; }

main { padding-top: var(--header-h); }

/* --------------------------------------------------------------------------
   8. HERO
   -------------------------------------------------------------------------- */
.hero {
  position: relative; display: flex; align-items: center;
  min-height: min(92vh, 820px);
  padding: clamp(60px, 9vw, 110px) 0 clamp(48px, 7vw, 90px);
  overflow: hidden;
  background: var(--ink);
}
.hero--short { min-height: 0; padding: clamp(64px, 9vw, 120px) 0 clamp(48px, 6vw, 80px); }

/* The homepage hero runs up behind the transparent header so the photo shows
   through it. Pulled up by exactly what <main> pads down, then given that
   height back as padding so the copy sits where it did before. */
.hero--bleed {
  margin-top: calc((var(--header-h) + var(--offer-h, 0px)) * -1);
  padding-top: calc(var(--header-h) + var(--offer-h, 0px) + clamp(60px, 9vw, 110px));
}

.hero__media { position: absolute; inset: 0; z-index: 0; --hero-drop: 76px; }

/* The photo is dropped below the header on purpose.
   There is almost no headroom in the source frame - the subject's head starts
   9.7% down it - so no amount of re-cropping moves him clear of the header.
   Instead the image box itself starts --hero-drop below the top of the hero and
   still reaches the bottom, so cover has nothing to crop short. The strip left
   above it is the hero's own --ink, which is what the transparent header sits
   over. The top edge is masked so the photo dissolves into that ink rather than
   meeting it on a hard line.
   object-position must stay at the top: centred, cover trims the crop from
   above and takes the subject's head with it. */
.hero__media img {
  position: absolute; left: 0; top: var(--hero-drop);
  width: 100%; height: calc(100% - var(--hero-drop));
  object-fit: cover; object-position: 50% 0;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 46px);
          mask-image: linear-gradient(180deg, transparent 0, #000 46px);
  /* Scaled from the top edge, never the centre - a centre origin would drag
     the subject back up under the header at the far end of the drift. */
  transform-origin: 50% 0;
  animation: heroDrift 24s ease-in-out infinite alternate;
}
@keyframes heroDrift { from { transform: scale(1.04); } to { transform: scale(1.13); } }
/* The offer bar wraps to two lines on phones, so the header is taller there
   and the drop has to grow with it. */
@media (max-width: 640px) { .hero__media { --hero-drop: 94px; } }

/* Left-weighted scrim so the headline always clears AA over any photo. */
.hero__media::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(95deg, rgba(11,13,20,.95) 0%, rgba(11,13,20,.82) 42%, rgba(11,13,20,.34) 74%, rgba(11,13,20,.55) 100%),
    linear-gradient(0deg, rgba(11,13,20,.9) 0%, transparent 42%);
}
.hero__inner { position: relative; z-index: 2; width: 100%; }
.hero__copy { max-width: 700px; }
.hero h1 { margin-bottom: 18px; }
.hero .lead { max-width: 560px; margin-bottom: 26px; }
.hero .btn-row { margin-bottom: 30px; }

/* Scroll cue — a falling bolt */
.scroll-cue {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 3; color: var(--blue-bright); opacity: .7;
  animation: cueDrop 2.2s ease-in-out infinite;
}
@keyframes cueDrop { 0%,100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 9px); } }
@media (max-width: 760px) { .scroll-cue { display: none; } }

/* Interior page hero (no photo required) */
.page-hero {
  position: relative; overflow: hidden;
  padding: clamp(56px, 8vw, 104px) 0 clamp(40px, 6vw, 72px);
  background: linear-gradient(160deg, var(--ink) 0%, #131829 58%, var(--ink) 100%);
  border-bottom: 1px solid var(--ink-4);
}
.page-hero__inner { position: relative; z-index: 2; max-width: 780px; }
.page-hero p { margin-top: 16px; }

/* --------------------------------------------------------------------------
   9. CARDS
   -------------------------------------------------------------------------- */
.card {
  position: relative;
  background: var(--ink-3);
  border: 1px solid var(--ink-4);
  padding: clamp(22px, 2.6vw, 32px);
  transition: transform .3s var(--ease), border-color .3s var(--ease), box-shadow .3s var(--ease);
  height: 100%;
}
.card:hover { transform: translateY(-4px); border-color: rgba(109,143,224,.5); box-shadow: var(--glow-blue); }
.card h3 { margin-bottom: 10px; }
.card p { color: var(--silver-dim); font-size: .99rem; }

.section--light .card { background: var(--white); border-color: #D8DFEC; }
.section--light .card p { color: #5A6274; }
.section--light .card:hover { box-shadow: 0 16px 40px -16px rgba(36,55,107,.34); }

/* Icon roundel — the bolt in a blue disc */
.card__icon {
  width: 52px; height: 52px; display: grid; place-items: center;
  background: linear-gradient(145deg, var(--blue), var(--blue-deep));
  color: var(--white); font-size: 1.35rem;
  margin-bottom: 16px;
  clip-path: var(--cut);
}
.card__icon .bolt { width: 1.2em; height: 1.2em; }

/* Numbered step card — number sits in the bolt disc */
.step__num {
  font-family: var(--font-display); font-size: 1.2rem; line-height: 1;
}

/* Feature list with bolt markers */
.ticks { display: grid; gap: 11px; }
.ticks li { display: flex; gap: 11px; align-items: flex-start; line-height: 1.5; }
.ticks .bolt { color: var(--blue-bright); margin-top: .28em; font-size: .92em; }
.section--light .ticks .bolt { color: var(--blue); }

/* --------------------------------------------------------------------------
   10. WASH MENU / PRICE CARDS
   Rebuilt to match the client's own price-card artwork. Four ideas carry it:
     - a photo with a diagonal cut, measured off the artwork (the cut sits
       lower on the left and rises to the right)
     - a tier-coloured band showing through along that cut
     - a two-part italic title: the qualifier small and coloured, the name
       large and white
     - a skewed price bar that is itself the call to action
   Every tier colour is sampled from the artwork, not eyeballed.
   -------------------------------------------------------------------------- */
.plans {
  display: grid; gap: clamp(12px, 1.1vw, 16px);
  grid-template-columns: repeat(auto-fit, minmax(226px, 1fr));
  align-items: stretch;
}

.plan {
  --t1: var(--blue-bright);        /* tier light stop */
  --t2: var(--blue);               /* tier dark stop  */
  --t-ink: var(--blue-bright);     /* tier colour that has to carry text */
  position: relative; display: flex; flex-direction: column;
  min-width: 0;
  background: linear-gradient(170deg, #02152E 0%, #011023 60%, #020C1C 100%);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 16px 40px -22px rgba(2,12,30,.85), 0 0 0 1px rgba(128,170,228,.22);
  transition: transform .3s var(--ease), box-shadow .3s var(--ease);
}
.plan:hover {
  transform: translateY(-6px);
  box-shadow: 0 28px 60px -26px rgba(2,12,30,.95), 0 0 0 1px rgba(122,160,214,.30);
}

/* Tier colours, sampled from the artwork */
.plan--graphene { --t1: #21C3C9; --t2: #0E8FB5; --t-ink: #3FD6DE; --p1: #0D7A8D; --p2: #0676A9; }
.plan--ceramic  { --t1: #17AEE4; --t2: #1478EC; --t-ink: #35C0F0; --p1: #0B779F; --p2: #116DD6; }
.plan--best     { --t1: #1C7ADB; --t2: #1050CC; --t-ink: #4A9DF5; --p1: #1470C6; --p2: #104FCC; }
.plan--deluxe   { --t1: #2A4DC0; --t2: #1B34B8; --t-ink: #5B86F0; --p1: #244AB5; --p2: #1D37BC; }
.plan--basic    { --t1: #33527A; --t2: #23405F; --t-ink: #7FA0D0; --p1: #33527A; --p2: #2A4868; }

/* Photo with the diagonal cut.
   The container carries the tier gradient and the image is clipped a little
   shorter than it, so the gradient shows through as a coloured band running
   along the cut. One element, no extra markup. */
.plan__media {
  position: relative;
  aspect-ratio: 2 / 1;
  background: linear-gradient(115deg, var(--t1), var(--t2));
  clip-path: polygon(0 0, 100% 0, 100% 78%, 0 100%);
}
.plan__media img {
  width: 100%; height: 100%; object-fit: cover;
  clip-path: polygon(0 0, 100% 0, 100% 71%, 0 93%);
}
/* Bolt watermark, shown only while a photo is missing, so the card still
   looks finished rather than broken. */
.plan__media::after {
  content: ''; position: absolute; inset: 0;
  background: var(--bolt-mask) center 40% / auto 44% no-repeat;
  opacity: .20; pointer-events: none;
}
.plan__media:has(img)::after { display: none; }

.plan__body { padding: 17px 20px 20px; display: flex; flex-direction: column; flex: 1; }

/* Title: small coloured qualifier over a large white name */
.plan .plan__name,
.section--light .plan .plan__name {
  font-family: var(--font-display); font-style: italic;
  text-transform: uppercase; line-height: .92;
  color: var(--white); font-size: clamp(1.62rem, 2.3vw, 2rem);
  margin: 0 0 9px; letter-spacing: .01em;
  text-align: center;          /* heading and its rule are centred together */
}
.plan__name span {
  display: block; color: var(--t-ink);
  font-size: .56em; letter-spacing: .02em; margin-bottom: 2px;
}
.plan__name::after {
  content: ''; display: block; width: 46px; height: 3px; margin: 9px auto 0;
  background: linear-gradient(90deg, var(--t1), var(--t2)); border-radius: 2px;
}

/* The card body is near black (#02152E ... #020C1C), so both of these sit on a
   very dark ground and were set too grey to read comfortably. White. */
/* --card-copy keeps the "+" line and the feature list on ONE size. They were
   .9rem and .89rem - a 0.16px difference, invisible but arbitrary, and the
   kind of thing that drifts further every time someone edits one of them.
   Nudged up from ~14.2px because this is the most-read copy on the page: it
   is what a customer compares one wash against the next with. */
.plan { --card-copy: .95rem; }
.plan__tag {
  font-family: var(--font-body); font-style: italic;
  font-size: var(--card-copy); color: var(--white); margin: 0 0 14px;
}

/* Feature list with roundel icons */
.plan__feats { display: grid; gap: 10px; margin: 0 0 18px; }
.plan__feats li {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--card-copy); color: var(--white); line-height: 1.35;
}
.plan__feats svg { flex-shrink: 0; width: 20px; height: 20px; color: var(--t-ink); }

/* Price bar: the card's call to action */
.plan__price {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  margin-top: auto; min-height: 70px;
  padding: 16px 20px 16px 30px;
  background: linear-gradient(100deg, var(--p1, var(--t2)), var(--p2, var(--t1)));
  clip-path: polygon(42px 0, 100% 0, 100% 100%, 0 100%, 0 44px);
  transition: filter .25s var(--ease);
}
.plan__price:hover { filter: brightness(1.12); }
/* The bar carries one figure or two. On the wash menu and the homepage it is
   the per-wash price with the monthly rate under it; on the membership page it
   is the monthly rate alone, because a per-wash figure beside it only muddies
   which number you are being asked to pay. */
.plan__figs { display: grid; gap: 3px; min-width: 0; }
.plan__amt {
  font-family: var(--font-display); font-style: italic; line-height: 1;
  font-size: clamp(1.55rem, 2.25vw, 1.95rem); color: var(--white);
}
.plan__per { font-size: .52em; }
/* The per-wash price on the menu pages. Barlow Condensed, not the display
   face - it is a secondary figure and reads as one. It is legible at this size
   because the two light tier stops were darkened to carry white, NOT because
   the text was inflated to qualify as WCAG large text. See --p1 below. */
.plan__single {
  font-family: var(--font-cond); font-weight: 600;
  font-size: .95rem; letter-spacing: .02em; line-height: 1.15;
  color: var(--white); white-space: nowrap;
}
.plan__arrow { width: 26px; height: 16px; color: var(--white); flex-shrink: 0; transition: transform .25s var(--ease); }
.plan__price:hover .plan__arrow { transform: translateX(5px); }

/* The cards carry their own dark ground, so they need no light/dark variant.
   Everything that used to restyle them per section is gone on purpose. */

/* --------------------------------------------------------------------------
   10b. FREE WASH OFFER CARD
   The visual anchor of the Free Wash Push section. Volt is allowed here —
   this IS the free wash offer, which is the one thing volt is reserved for.
   -------------------------------------------------------------------------- */
.offer-card {
  position: relative;
  background: linear-gradient(165deg, #1B2033 0%, #12162400 60%), var(--ink-3);
  border: 1px solid rgba(255, 196, 46, .32);
  border-radius: 16px;
  padding: 34px 30px 30px;
  text-align: center;
  box-shadow: 0 0 0 1px rgba(255,196,46,.08), 0 22px 60px -30px rgba(255,196,46,.5);
}
.offer-card__flag {
  position: absolute; top: 0; left: 50%; transform: translate(-50%, -50%);
  background: var(--volt); color: #14161F;
  font-family: var(--font-cond); font-weight: 700; font-size: .74rem;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 7px 18px;
  clip-path: var(--cut);
  white-space: nowrap;
}
.offer-card__free {
  font-family: var(--font-display); font-style: italic;
  text-transform: uppercase; line-height: .9;
  font-size: clamp(3.4rem, 7vw, 4.6rem);
  color: var(--volt);
  margin: 10px 0 2px;
  text-shadow: 0 0 34px rgba(255, 196, 46, .38);
}
.offer-card__name {
  /* Sits directly on top of the italic __free, so it leans with it. */
  font-family: var(--font-display); font-style: italic; text-transform: uppercase;
  font-size: clamp(1.15rem, 2vw, 1.45rem); color: var(--white);
  margin: 0 0 6px;
}
.offer-card__value { color: var(--silver-dim); font-size: .98rem; margin: 0 0 22px; }
.offer-card__value strong { color: var(--white); }
.offer-card__list {
  text-align: left; max-width: 260px; margin: 0 auto;
  padding-top: 20px; border-top: 1px solid var(--ink-4);
}
.offer-card__list li { font-size: .95rem; }

/* --------------------------------------------------------------------------
   11. AMENITY STRIP / FACT BAR
   -------------------------------------------------------------------------- */
.factbar {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  border: 1px solid var(--ink-4); background: var(--ink-3);
}
.factbar li { padding: 24px 22px; border-right: 1px solid var(--ink-4); }
.factbar li:last-child { border-right: 0; }
.factbar .k { font-family: var(--font-display); font-size: 1.85rem; color: var(--white); line-height: 1; display: block; margin-bottom: 6px; }
.factbar .v { font-family: var(--font-cond); text-transform: uppercase; letter-spacing: .14em; font-size: .82rem; color: var(--blue-bright); }
@media (max-width: 620px) { .factbar li { border-right: 0; border-bottom: 1px solid var(--ink-4); } .factbar li:last-child { border-bottom: 0; } }

/* Marquee ticker — the "express" heartbeat. */
.ticker {
  background: var(--blue); color: var(--white);
  overflow: hidden; white-space: nowrap; padding: 11px 0;
  border-top: 1px solid var(--blue-deep); border-bottom: 1px solid var(--blue-deep);
}
.ticker__track { display: inline-flex; align-items: center; gap: 30px; animation: tick 34s linear infinite; }
.ticker span { font-family: var(--font-cond); font-weight: 700; text-transform: uppercase; letter-spacing: .2em; font-size: .88rem; display: inline-flex; align-items: center; gap: 30px; }
@keyframes tick { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.ticker:hover .ticker__track { animation-play-state: paused; }

/* --------------------------------------------------------------------------
   12. MEDIA BLOCKS
   -------------------------------------------------------------------------- */
.media { position: relative; overflow: hidden; border: 1px solid var(--ink-4); max-width: 100%; }
.media img { width: 100%; height: 100%; object-fit: cover; }

/* --------------------------------------------------------------------------
   <picture> wrappers
   Every photo is a <picture> now, for the WebP/JPEG fallback, which puts an
   extra element between these containers and the <img> they size.

   Chromium resolves the percentage height through the wrapper on its own, so
   this block measures as a no-op here - it was tested with and without and the
   boxes come out identical. It is kept because percentage height through a
   wrapper is not consistently handled across engines, Safari especially, and
   this site cannot be tested in Safari from the build environment. Four lines
   of insurance on a client site nobody can spot-check in WebKit.

   If you are cutting CSS, this is a fair thing to cut - but check the photos
   on about-us, career and the wash cards in Safari first.
   -------------------------------------------------------------------------- */
.media picture,
.page-hero__media picture,
.hero__media picture,
.plan__media picture { display: block; width: 100%; height: 100%; }
/* .hero__media's image is absolutely positioned against .hero__media itself.
   The wrapper is left unpositioned on purpose so it does not become the
   containing block and break the --hero-drop offset. */
.media--tall { aspect-ratio: 4 / 5; }
.media--wide { aspect-ratio: 16 / 10; }

/* Placeholder shown until the real photo is dropped in. Keeps layout honest
   and makes a missing asset obvious rather than silent. */
.media--placeholder {
  display: grid; place-items: center; text-align: center;
  background:
    repeating-linear-gradient(-45deg, rgba(61,90,166,.10) 0 12px, transparent 12px 24px),
    var(--ink-2);
  border: 1px dashed rgba(109,143,224,.5);
  padding: 30px; min-height: 240px;
  /* Drop the parent's aspect-ratio. Left on, the browser derives the WIDTH
     from min-height (240 x 1.6 = 384px) and the box overflows a phone
     viewport, which put a horizontal scrollbar on every page showing a
     placeholder. Height is driven by min-height here instead. */
  aspect-ratio: auto;
}
.media--placeholder span {
  font-family: var(--font-cond); text-transform: uppercase; letter-spacing: .16em;
  font-size: .82rem; color: var(--blue-bright);
}

/* --------------------------------------------------------------------------
   13. FORMS & EMBED SLOTS
   Forms are Basecamp/Paperform embeds. Each slot is a labelled, dashed box so
   an un-wired form is impossible to miss in review.
   -------------------------------------------------------------------------- */
.embed-slot {
  border: 2px dashed var(--blue-bright);
  background: rgba(61,90,166,.08);
  padding: 34px 26px; text-align: center;
  display: grid; gap: 10px; place-items: center;
  min-height: 230px;
}
.embed-slot h3 { font-size: 1.1rem; color: var(--white); }
.embed-slot p { color: var(--silver-dim); font-size: .94rem; max-width: 480px; }
.embed-slot code { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: .86rem; color: var(--blue-bright); background: rgba(11,13,20,.6); padding: 2px 7px; }
.section--light .embed-slot { background: rgba(61,90,166,.06); border-color: var(--blue); }
.section--light .embed-slot h3 { color: var(--graphite); }
.section--light .embed-slot p { color: #5A6274; }
.section--light .embed-slot code { color: var(--blue-deep); background: var(--paper-2); }

/* --------------------------------------------------------------------------
   14. FAQ / ACCORDION
   -------------------------------------------------------------------------- */
.faq { display: grid; gap: 12px; max-width: 840px; margin: 0 auto; }
.faq details { background: var(--ink-3); border: 1px solid var(--ink-4); transition: border-color .25s var(--ease); }
.faq details[open] { border-color: rgba(109,143,224,.5); }
.faq summary {
  cursor: pointer; list-style: none; padding: 19px 22px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  font-family: var(--font-cond); font-weight: 600; font-size: 1.1rem;
  color: var(--white);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; flex-shrink: 0; width: 13px; height: 13px;
  border-right: 2px solid var(--blue-bright); border-bottom: 2px solid var(--blue-bright);
  transform: rotate(45deg) translate(-3px, -3px);
  transition: transform .25s var(--ease);
}
.faq details[open] summary::after { transform: rotate(225deg) translate(-3px, -3px); }
.faq .faq__body { padding: 0 22px 20px; color: var(--silver-dim); }
.section--light .faq details { background: var(--white); border-color: #D8DFEC; }
.section--light .faq summary { color: var(--graphite); }
.section--light .faq .faq__body { color: #5A6274; }

/* --------------------------------------------------------------------------
   15. CTA BAND
   -------------------------------------------------------------------------- */
.cta-band {
  position: relative; overflow: hidden;
  background: linear-gradient(135deg, var(--blue-deep) 0%, var(--blue) 52%, #4E70C6 100%);
  padding: clamp(52px, 7vw, 92px) 0; text-align: center;
}
.cta-band h2 { color: var(--white); }
.cta-band p { color: rgba(255,255,255,.9); max-width: 620px; margin: 16px auto 28px; font-size: 1.1rem; }
.cta-band .btn--ghost { border-color: rgba(255,255,255,.75); color: var(--white); }
.cta-band .btn--ghost:hover { background: var(--white); color: var(--blue-deep); border-color: var(--white); }
.cta-band .btn--club { background: var(--white); color: var(--blue-deep); }
.cta-band .btn--club:hover { background: var(--paper); }

/* --------------------------------------------------------------------------
   16. MAP
   -------------------------------------------------------------------------- */
.map { position: relative; width: 100%; aspect-ratio: 16 / 9; border: 1px solid var(--ink-4); overflow: hidden; }
.map iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; filter: grayscale(1) invert(.92) contrast(.86); }
@media (max-width: 700px) { .map { aspect-ratio: 4 / 3; } }

.info-list { display: grid; gap: 18px; }
.info-list dt { font-family: var(--font-cond); text-transform: uppercase; letter-spacing: .16em; font-size: .8rem; color: var(--blue-bright); margin-bottom: 4px; }
.info-list dd { font-size: 1.06rem; color: var(--silver); overflow-wrap: anywhere; }
.info-list a:hover { color: var(--blue-bright); text-decoration: underline; }
.section--light .info-list dt { color: var(--blue); }
.section--light .info-list dd { color: var(--graphite); }

.hours-table { width: 100%; border-collapse: collapse; }
.hours-table th, .hours-table td { text-align: left; padding: 12px 4px; border-bottom: 1px solid var(--ink-4); font-size: 1rem; }
.hours-table th { font-family: var(--font-cond); text-transform: uppercase; letter-spacing: .1em; font-weight: 600; color: var(--silver-dim); }
.hours-table td { color: var(--white); font-family: var(--font-cond); font-size: 1.1rem; }
.section--light .hours-table th, .section--light .hours-table td { border-color: #D8DFEC; }
.section--light .hours-table td { color: var(--graphite); }

/* --------------------------------------------------------------------------
   17. BADGE / SEAL  (the butler half of the brand)
   -------------------------------------------------------------------------- */
.seal {
  display: inline-flex; align-items: center; gap: 12px;
  border: 1px solid rgba(109,143,224,.45);
  background: rgba(61,90,166,.12);
  padding: 11px 20px;
  clip-path: var(--cut);
  font-family: var(--font-cond); text-transform: uppercase;
  letter-spacing: .16em; font-size: .84rem; color: var(--blue-bright);
}
.seal .bowtie { color: var(--blue-bright); font-size: 1.1em; }

/* --------------------------------------------------------------------------
   18. NOTICES
   -------------------------------------------------------------------------- */
.notice {
  border-left: 4px solid var(--blue-bright);
  background: rgba(61,90,166,.12);
  padding: 16px 20px; font-size: .96rem; color: var(--silver);
}
.notice strong { color: var(--white); }
.section--light .notice { background: rgba(61,90,166,.08); color: #3A4051; }
.section--light .notice strong { color: var(--graphite); }

/* --------------------------------------------------------------------------
   19. FOOTER
   -------------------------------------------------------------------------- */
/* The whole footer is white, at every width. That is why there is no longer a
   leaning white plate behind the brand column - the plate existed to put white
   under a mark drawn for white, and the footer is that now, so the plate and
   its slant had nothing left to do. The -100vw bleed and the overflow clip it
   needed went with it.

   Every colour here was measured against white, not guessed. The lowest is
   #5A6274 at 6.1:1 - the token the light sections already use. */
.site-footer {
  position: relative;
  --footer-pad-t: clamp(46px, 6vw, 72px);
  background: #FFFFFF; border-top: 1px solid rgba(20, 22, 31, .14);
  padding: var(--footer-pad-t) 0 0;
}
.footer-brand p { color: var(--graphite); }          /* 18.9:1 */
.footer-hours   { color: #5A6274; }
.socials a { border-color: rgba(20, 22, 31, .22); color: var(--graphite); }
.socials a:hover { border-color: var(--blue); color: var(--blue); background: rgba(61, 90, 166, .08); }

/* Positioned, so the columns paint above the panel rather than under it. */
.site-footer > .wrap { position: relative; }
.footer-grid { display: grid; gap: clamp(26px, 4vw, 48px); grid-template-columns: 1.4fr 1fr 1fr 1.2fr; }
@media (max-width: 940px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; } }

.site-footer h2 { font-family: var(--font-cond); font-weight: 700; font-size: .88rem; letter-spacing: .2em; color: var(--blue); margin-bottom: 16px; }
.site-footer ul { display: grid; gap: 10px; }
.site-footer a { color: #5A6274; font-size: .98rem; transition: color .2s var(--ease); }
.site-footer a:hover { color: var(--blue); }
/* .site-footer a is (0,1,1) and beats .btn--club and .socials a, both (0,1,0).
   It was quietly repainting the Manage Membership label and the social glyphs
   in link grey - the button had a grey label on a blue fill. Matched here so
   they keep their own colour. */
.site-footer .btn--club { color: var(--white); }
.site-footer .btn--club:hover { color: var(--white); }
.site-footer .socials a { color: var(--graphite); }
.site-footer .socials a:hover { color: var(--blue); }
.footer-logo { display: inline-block; }
.footer-brand img { height: 52px; width: auto; margin-bottom: 18px; display: block; }
.footer-brand p { font-size: .95rem; max-width: 300px; }

.socials { display: flex; gap: 12px; margin-top: 18px; }
.socials a {
  width: 42px; height: 42px; display: grid; place-items: center;
  border: 1px solid var(--ink-4); color: var(--silver);
  transition: all .25s var(--ease);
}
.socials a:hover { border-color: var(--blue-bright); color: var(--blue-bright); background: rgba(61,90,166,.14); }

/* One centred line, pipe separated, matching the fleet standard. */
.footer-bottom {
  margin-top: clamp(34px, 4vw, 52px); padding: 22px 0;
  border-top: 1px solid rgba(20, 22, 31, .14);
  text-align: center;
}
.footer-bottom p {
  margin: 0; font-size: .87rem; line-height: 2;
  color: #5A6274;                     /* 6.1:1 on white */
}
.footer-bottom a {
  color: #5A6274;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
  transition: color .2s var(--ease);
}
.footer-bottom a:hover { color: var(--blue-bright); }
.footer-bottom .sep { padding: 0 7px; opacity: .45; }
/* Keep each item whole. Without this a wrap splits "Terms of Service" across
   two lines, and the separator strands itself at the end of a line. */
.footer-bottom a,
.footer-bottom .fb-unit { white-space: nowrap; }
/* On a phone the line has to wrap several times, and a pipe stranded at the
   end of a wrapped line looks like a mistake. Below 620px the row becomes a
   centred flex wrap with real gaps and the separators are dropped entirely:
   the copyright takes its own row, the credit and the legal links flow under
   it. */
@media (max-width: 620px) {
  .footer-bottom p {
    display: flex; flex-wrap: wrap;
    justify-content: center; align-items: baseline;
    gap: 6px 16px;
    font-size: .82rem; line-height: 1.7;
  }
  .footer-bottom .sep { display: none; }
  .footer-bottom .fb-copy { flex: 0 0 100%; margin-bottom: 4px; }
}

/* --------------------------------------------------------------------------
   20. SCROLL REVEAL — fail-safe
   Content is VISIBLE by default. js/main.js adds .js-reveal to <html> only
   once it is running, which is what hides it. If JS never runs, or the
   observer never fires, copy can still never end up permanently invisible.
   -------------------------------------------------------------------------- */
.js-reveal .reveal { opacity: 0; transform: translateY(20px); }
.js-reveal .reveal.in,
.reveal { transition: opacity .6s var(--ease), transform .6s var(--ease); }
.js-reveal .reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js-reveal .reveal { opacity: 1 !important; transform: none !important; }
}

/* --------------------------------------------------------------------------
   21. LANDING PAGES (free wash / thank you)
   -------------------------------------------------------------------------- */
.lander {
  min-height: 100vh; display: grid; place-items: center;
  grid-template-columns: minmax(0, 1fr);
  padding: 44px var(--gutter);
  background: radial-gradient(1000px 640px at 50% -10%, rgba(61,90,166,.34), transparent 70%), var(--ink);
  text-align: center;
}
.lander__inner { width: 100%; max-width: 640px; }
.lander__logo { height: 66px; margin: 0 auto 26px; width: auto; }
.lander h1 { font-size: clamp(2.1rem, 6vw, 3.4rem); margin-bottom: 14px; }
.lander p { color: var(--silver); }
.lander .embed-slot { margin-top: 28px; text-align: center; }

/* --- light lander -------------------------------------------------------- */
/* The standalone pages go white so the client's ORIGINAL mark can sit on the
   white it was drawn for, instead of the generated reverse variant. Swapping
   the ground is not enough on its own: .lander p is --silver and the inline
   link colours are --blue-bright, both of which are tuned for the dark ground
   and go illegible on white. Every one of them is re-stated here.

   Colours are the same two the light sections already use and that the brand
   guide documents: #5A6274 at 6.1:1 and --blue #3D5AA6 at 6.55:1 on white. */
.lander--light {
  background: #FFFFFF;
  color: var(--graphite);
}
.lander--light h1,
.lander--light h2,
.lander--light h3 { color: var(--graphite); }
.lander--light p  { color: var(--graphite); }
.lander--light .muted { color: #5A6274; }
/* :not(.btn) matters. `.lander--light a` is (0,1,1) and outranks `.btn--club`
   at (0,1,0), so without it the button label is painted --blue on a --blue
   fill and vanishes. Same trap as `.site-footer a` further up this file. */
.lander--light a:not(.btn) { color: var(--blue); }
.lander--light .embed-slot { background: rgba(61,90,166,.06); border-color: var(--blue); }
.lander--light .embed-slot h2,
.lander--light .embed-slot h3 { color: var(--graphite); }
.lander--light .embed-slot p  { color: #5A6274; }
.lander--light .embed-slot code { color: var(--blue-deep); background: var(--paper); }

/* WCAG 1.4.1: a link inside a block of text cannot be told apart by colour
   alone unless it differs from the surrounding text by 3:1. --blue #3D5AA6
   against the body copy #5A6274 is 1.07:1 - nowhere near. On the dark ground
   these pages used to have, --blue-bright carried enough separation; taking
   them white removed it. Underline them. */
.lander p a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* --- the thank-you card --------------------------------------------------
   The page is white so the logo works, but the content keeps its dark ground
   and gains a border, so it reads as one object sitting on the page rather
   than copy floating in space. The logo stays OUTSIDE the card, on the white.

   Everything inside is back on a dark ground, so the light rules above have to
   be reversed again for the card's contents - otherwise --graphite text lands
   on --ink and disappears. */
.lander__card {
  background: var(--ink);
  border: 1px solid var(--ink-4);
  box-shadow: 0 18px 50px rgba(11, 13, 20, .16);
  padding: clamp(30px, 5vw, 52px) clamp(22px, 4vw, 44px);
  text-align: center;
}
.lander--light .lander__card h1,
.lander--light .lander__card h2,
.lander--light .lander__card h3 { color: var(--white); }
.lander--light .lander__card p  { color: var(--silver); }
.lander--light .lander__card .muted { color: var(--silver-dim); }
.lander--light .lander__card a:not(.btn) { color: var(--blue-bright); }
/* The card is narrower than the full-width lander the h1 was sized for, so
   "Congratulations!" broke its own exclamation mark onto a second line. */
.lander__card h1 { font-size: clamp(1.75rem, 4.2vw, 2.5rem); }

/* --------------------------------------------------------------------------
   24. STATEMENT BLOCK — the section directly under the hero

   Editorial two-column: the heading holds the left rail while the copy runs
   down the right, then one oversized line closes the section. The heading and
   the closing line are both display italic, so the rule and bolt between them
   are what stop the section reading as one long shout.
   -------------------------------------------------------------------------- */
.statement {
  display: grid; align-items: start;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: clamp(26px, 5vw, 78px);
}
@media (max-width: 900px) { .statement { grid-template-columns: minmax(0, 1fr); gap: 20px; } }
.statement h2 { margin: 0; }
.statement .eyebrow { display: block; margin-bottom: 14px; }
.statement__copy p { margin: 0 0 17px; line-height: 1.7; }
.statement__copy p:last-child { margin-bottom: 0; }
/* The opening line is the thesis, so it carries a little more weight than the
   two that explain it. */
.statement__copy p:first-child { color: var(--white); font-size: 1.16rem; }

.bigline { margin-top: clamp(42px, 6vw, 74px); text-align: center; }
.bigline__rule {
  display: flex; align-items: center; gap: 18px;
  color: var(--ink-4); margin-bottom: clamp(24px, 3.4vw, 38px);
}
.bigline__rule::before,
.bigline__rule::after { content: ''; flex: 1; height: 1px; background: currentColor; }
.bigline__rule .bolt { width: 21px; height: 21px; color: var(--blue-bright); }
.bigline__text {
  margin: 0;
  font-family: var(--font-display); font-style: italic;
  text-transform: uppercase; line-height: .94; letter-spacing: .005em;
  font-size: clamp(2.35rem, 6.8vw, 4.9rem);
  color: var(--white);
}
.bigline__text span { display: block; }

/* --------------------------------------------------------------------------
   23. REVIEWS — two treatments, one per page

   Real Google reviews. Quotes are VERBATIM contiguous sentences: to shorten
   one, cut at a sentence boundary, never reword inside it. No dates are shown
   - a static page cannot keep "3 weeks ago" true, and inventing a calendar
   date to replace it would be making up a fact. The rating link is the proof.

   Stars are white, not --volt. Gold is the Free Wash signal and nothing else
   (see CLAUDE.md); a rating block is exactly the kind of place that would
   quietly spend it. The numeral carries the weight instead.
   -------------------------------------------------------------------------- */

/* Fractional star row. Two stacked copies of the same five glyphs; the filled
   copy is clipped to rating/5 so 4.6 renders as 4.6, not "about 5". */
.stars { position: relative; display: inline-block; line-height: 1; white-space: nowrap;
  letter-spacing: .1em; font-size: 1rem; }
.stars span { display: block; }
.stars .off { color: rgba(255, 255, 255, .26); }
.stars .on  { position: absolute; inset: 0 auto 0 0; overflow: hidden; color: #FFFFFF; }
.section--light .stars .off { color: rgba(20, 22, 31, .22); }
.section--light .stars .on  { color: var(--blue); }

/* --- Homepage: a score plate and three quote cards, one row --------------- */
.raves {
  display: grid; gap: clamp(11px, 1.1vw, 16px);
  grid-template-columns: minmax(0, .88fr) repeat(3, minmax(0, 1fr));
  align-items: stretch;
}
@media (max-width: 1100px) { .raves { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .raves { grid-template-columns: minmax(0, 1fr); } }

/* The plate leans off its right edge, the same lean as the logo plate in the
   header and the cut on the buttons. */
.rave-score {
  display: flex; flex-direction: column; justify-content: center;
  padding: 22px 34px 22px 26px;
  background: linear-gradient(145deg, var(--blue) 0%, var(--blue-deep) 100%);
  clip-path: polygon(0 0, 100% 0, calc(100% - 20px) 100%, 0 100%);
}
@media (max-width: 1100px) { .rave-score { grid-column: 1 / -1; } }
/* Once it is full width there is no reason for it to be tall too - lay it on
   its side and give the height back to the quotes. */
@media (max-width: 640px) {
  .rave-score { flex-direction: row; align-items: center; flex-wrap: wrap;
                gap: 6px 18px; padding: 16px 34px 16px 22px; }
  .rave-score__num { font-size: 2.8rem; }
  .rave-score .stars { margin: 0; }
  .rave-score__meta { flex: 1 0 100%; }
}
.rave-score__num {
  font-family: var(--font-display); font-style: italic; line-height: .85;
  font-size: clamp(3rem, 5.5vw, 3.9rem); color: var(--white);
}
.rave-score .stars { font-size: 1.05rem; margin: 10px 0 8px; }
.rave-score__meta { margin: 0; font-size: .88rem; color: rgba(255, 255, 255, .88); }
.rave-score__meta a { color: var(--white); text-decoration: underline;
  text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* Chamfered top-left corner + a bolt for a quote mark. */
.rave {
  position: relative; display: flex; flex-direction: column;
  padding: 26px 22px 20px;
  background: var(--ink-3);
  clip-path: polygon(20px 0, 100% 0, 100% 100%, 0 100%, 0 20px);
}
.rave__bolt { color: var(--blue-bright); width: 17px; height: 17px; margin-bottom: 11px; }
.rave blockquote { margin: 0 0 15px; font-size: .95rem; line-height: 1.55; color: var(--silver); }
.rave figcaption {
  margin-top: auto; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding-top: 13px; border-top: 1px solid var(--ink-4);
  font-family: var(--font-cond); text-transform: uppercase; letter-spacing: .07em;
  font-size: .84rem; color: var(--silver-dim);
}
.rave .stars { font-size: .78rem; }

/* --- Location page: quotes as strips of tape ------------------------------ */
/* Deliberately not the homepage treatment - the two pages carry different
   reviews and should not look like the same widget twice. */
.tape { display: grid; gap: 9px; }
.tape__row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: clamp(14px, 2vw, 26px); align-items: center;
  padding: 15px 26px 15px 0;
  background: var(--ink-3);
  /* No border: a clip-path slices the side borders off and leaves two floating
     rules, the same trap that keeps the ghost buttons square. */
  clip-path: polygon(18px 0, 100% 0, calc(100% - 18px) 100%, 0 100%);
}
.tape__row:nth-child(even) { background: var(--ink-2); }
/* The tab walks down the blue ramp so the stack reads as one object. */
.tape__tab {
  display: flex; align-items: center; justify-content: center;
  width: clamp(48px, 6vw, 62px); align-self: stretch;
  margin-left: -1px; color: var(--white);
  background: var(--blue-deep);
  clip-path: polygon(18px 0, 100% 0, calc(100% - 18px) 100%, 0 100%);
}
.tape__row:nth-child(2) .tape__tab { background: #2F4787; }
.tape__row:nth-child(3) .tape__tab { background: var(--blue); }
.tape__row:nth-child(4) .tape__tab { background: #4A69B8; }
.tape__tab .bolt { width: 18px; height: 18px; }
.tape blockquote { margin: 0; font-size: .95rem; line-height: 1.5; color: var(--silver); }
.tape__who { text-align: right; flex-shrink: 0; }
.tape__who b {
  display: block; font-family: var(--font-cond); font-weight: 600;
  text-transform: uppercase; letter-spacing: .07em; font-size: .84rem;
  color: var(--silver-dim); margin-bottom: 4px;
}
.tape__who .stars { font-size: .74rem; }

@media (max-width: 760px) {
  .tape__row { grid-template-columns: auto minmax(0, 1fr); padding: 14px 18px 14px 0; row-gap: 9px; }
  /* The tab is in grid row 1 only once the caption wraps below the quote, so
     align-self: stretch stops filling the strip. Span every row instead. */
  .tape__tab { grid-row: 1 / -1; }
  .tape__who { grid-column: 2; text-align: left; display: flex; align-items: center; gap: 10px; }
  .tape__who b { margin-bottom: 0; }
}

/* Small rating chip, for sitting next to a heading rather than in a plate. */
.rating-chip {
  display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap;
  justify-content: center; margin-top: 14px;
  font-family: var(--font-cond); text-transform: uppercase; letter-spacing: .07em;
  font-size: .86rem; color: var(--silver-dim);
}
.rating-chip b { color: var(--white); font-size: 1.05rem; }
.rating-chip a { color: var(--blue-bright); }

/* --------------------------------------------------------------------------
   26. MEMBERSHIP AGREEMENT — the client's own terms, quoted

   Set as a quotation, not as site copy, because that is what it is: the text
   from their NXT Wash checkout, reproduced word for word. The blue rule down
   the left is the visual cue that these are someone else's words.
   -------------------------------------------------------------------------- */
.agreement { max-width: 840px; margin: 0 auto; }
.agreement blockquote {
  margin: 0; padding: clamp(22px, 3vw, 32px) clamp(20px, 3vw, 34px);
  background: var(--ink-3); border-left: 3px solid var(--blue);
}
.agreement blockquote p { margin: 0 0 15px; font-size: .96rem; line-height: 1.68; color: var(--silver); }
.agreement blockquote p:last-child { margin-bottom: 0; }
.agreement__source {
  margin: 14px 0 0; text-align: right; font-size: .87rem; color: var(--silver-dim);
}
.agreement__source a { color: var(--blue-bright); }

/* --------------------------------------------------------------------------
   27. BAND — a slim full-width promo strip

   Lifts the pattern the homepage fleet strip was doing with inline styles, so
   the gift-card banner and anything like it share one definition instead of
   each carrying its own copy.
   -------------------------------------------------------------------------- */
.band {
  display: flex; flex-wrap: wrap; gap: 20px;
  align-items: center; justify-content: space-between;
}
.band h2 { font-size: clamp(1.55rem, 3vw, 2.2rem); }
.band p { color: rgba(255, 255, 255, .9); margin-top: 8px; max-width: 560px; }
.band .btn { flex-shrink: 0; }
/* On a blue ground the ghost outline needs to be white, not brand blue. */
.band .btn--ghost { border-color: rgba(255, 255, 255, .8); color: var(--white); }
.band .btn--ghost:hover { background: var(--white); color: var(--blue-deep); border-color: var(--white); }

/* --------------------------------------------------------------------------
   28. PHOTO BEHIND A BAND, A HERO OR A CARD

   The fleet photo is a bright one - blue sky, white cloud, pale asphalt - so
   every placement carries a real scrim rather than a token tint. The values
   below were set against the brightest part of the image, the cloud, not
   against its average.
   -------------------------------------------------------------------------- */

/* --- inner page hero with a photo ---------------------------------------- */
/* --focus is where the subject's face sits vertically in the source. The hero
   band is short, so cover trims a lot of height and a centred crop decapitates
   anyone framed high. Set it per page; 50% is centre. */
.page-hero__media { position: absolute; inset: 0; z-index: 0; --focus: 50%; }
.page-hero__media img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% var(--focus);
}
/* Left-weighted, because .page-hero__inner is capped at 780px and sits left. */
.page-hero__media::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(95deg, rgba(11,13,20,.96) 0%, rgba(11,13,20,.88) 48%, rgba(11,13,20,.55) 100%),
    linear-gradient(0deg, rgba(11,13,20,.88) 0%, transparent 58%);
}
/* The scrim above is left-weighted because .page-hero__inner is capped at
   780px and sits left, so its lightest stop (.55) falls on empty photo. On a
   phone the copy spans the full width and runs straight into that stop - the
   survey eyebrow measured 3.71:1 on the brightest photo. Flatten the
   horizontal ramp here rather than darkening it for everyone. */
@media (max-width: 900px) {
  .page-hero__media::after {
    background:
      linear-gradient(95deg, rgba(11,13,20,.96) 0%, rgba(11,13,20,.95) 48%, rgba(11,13,20,.94) 100%),
      linear-gradient(0deg, rgba(11,13,20,.92) 0%, transparent 62%);
  }
}

/* --- full-width band with a photo ---------------------------------------- */
/* Keeps the brand-blue band reading as a brand-blue band; the vans show
   through it rather than replacing it. */
.band-media { position: relative; overflow: hidden; }
/* `> picture` as well as `> img`: every photo is a <picture> now, for the
   WebP fallback, and the direct-child combinator does not reach through it.
   The <picture> becomes the positioned box; the <img> fills it. */
.band-media > img,
.band-media > picture {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
}
.band-media > picture > img { width: 100%; height: 100%; object-fit: cover; }
.band-media::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(100deg, rgba(24,42,92,.96) 0%, rgba(36,55,107,.88) 100%);
}
.band-media > .wrap { position: relative; z-index: 2; }

/* --- card with a photo behind it ----------------------------------------- */
.card--media { overflow: hidden; }
.card--media > img,
.card--media > picture {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
}
.card--media > picture > img { width: 100%; height: 100%; object-fit: cover; }
.card--media::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(11,13,20,.74) 0%, rgba(11,13,20,.94) 58%);
}
/* :not(picture) too, or the wrapper gets lifted to z-index 2 and covers the
   card's own text. */
.card--media > *:not(img):not(picture) { position: relative; z-index: 2; }
/* --silver-dim is tuned for the flat card ground and goes muddy over a photo. */
.card--media p { color: var(--silver); }

/* --------------------------------------------------------------------------
   25. MOBILE — WHITE HEADER

   On a phone the bar goes white too. The footer is already white at every
   width (section 19), so this block only has the header and its nav panel to
   invert.

   Breakpoint is 900px: the point where the split layouts have already stacked
   and the page is in its one-column form. The hamburger appears earlier, at
   1299px, so between 901 and 1299 the bar stays dark with a hamburger in it -
   that is the existing desktop look, left alone on purpose.
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .site-header,
  .site-header.scrolled {
    background: #FFFFFF;
    border-bottom-color: rgba(20, 22, 31, .14);
    box-shadow: 0 6px 22px rgba(11, 13, 20, .13);
  }
  /* The logo plate exists to put white under a mark drawn for white. The whole
     bar is that now, so the plate and its slant have nothing left to do. */
  .site-header::before { display: none; }
  .nav-toggle span { background: var(--graphite); }

  /* The nav panel is a full-screen takeover starting right under the bar. Left
     dark it would read as a broken seam, so it inverts with everything else. */
  .primary-nav { background: #FFFFFF; }
  .primary-nav a { color: var(--graphite); }
  .primary-nav a:hover,
  .primary-nav a[aria-current="page"] { color: var(--blue); }
  .primary-nav > ul > li { border-bottom-color: rgba(20, 22, 31, .12); }
  .nav-drop ul a:hover { background: rgba(61, 90, 166, .10); color: var(--blue); }
}

/* --------------------------------------------------------------------------
   29. BUTTONS — DISABLED
   Nothing on the site is disabled today. This exists because the six form
   embeds are next, and a submit button with nothing to submit needs a state.

   It has three jobs:
     1. Stop the motion. .btn--free glows and sweeps on a loop. A button that
        pulses for attention and then refuses the click is a lie, so both
        animations are killed, not slowed.
     2. Drop the affordances - no hover lift, no press, cursor: not-allowed.
     3. Stay readable. WCAG 1.4.3 exempts disabled controls from the contrast
        minimum. A label nobody can read is still not a design, so both pairs
        below were measured and clear 4.5:1 anyway:
          --silver-dim #8C97AE on --ink-4 #232840 = 4.96:1   (dark sections)
          #5A6274      on        #DDE2EC          = 4.76:1   (light sections)

   Shape is deliberately kept. The angled cut is how a Butler button is
   recognised; a disabled one is the same button turned off, not a different
   component.

   Usage: [disabled] on a <button>. On an <a>, aria-disabled="true" - and add
   tabindex="-1", because pointer-events alone still leaves it tabbable.
   -------------------------------------------------------------------------- */
.btn:disabled,
.btn[disabled],
.btn[aria-disabled="true"] {
  background: var(--ink-4);
  background-image: none;              /* kills the --free gradient */
  color: var(--silver-dim);
  border-color: transparent;
  box-shadow: none;
  animation: none;
  transform: none;
  cursor: not-allowed;
  pointer-events: none;                /* an <a> has no disabled attribute */
}
/* The hover rules are (0,2,0) and some sit later in the file, so these repeat
   at (0,3,0) rather than relying on source order. */
.btn:disabled:hover,
.btn[disabled]:hover,
.btn[aria-disabled="true"]:hover {
  background: var(--ink-4);
  background-image: none;
  color: var(--silver-dim);
  border-color: transparent;
  transform: none;
  box-shadow: none;
}
/* The light sweep is a pseudo-element, so it has to be switched off by name. */
.btn:disabled::after,
.btn[disabled]::after,
.btn[aria-disabled="true"]::after { display: none; }
/* The bolt glyph inherits #14161F from .btn--free. */
.btn:disabled .bolt,
.btn[disabled] .bolt,
.btn[aria-disabled="true"] .bolt { color: var(--silver-dim); }

/* Outlined buttons keep their outline - filling them in would read as enabled. */
.btn--ghost:disabled,
.btn--ghost[disabled],
.btn--ghost[aria-disabled="true"],
.btn--ghost[aria-disabled="true"]:hover {
  background: transparent;
  border-color: var(--ink-4);
  color: var(--silver-dim);
}

.section--light .btn:disabled,
.section--light .btn[disabled],
.section--light .btn[aria-disabled="true"],
.section--light .btn[aria-disabled="true"]:hover {
  background: #DDE2EC;
  background-image: none;
  color: #5A6274;
}
.section--light .btn--ghost[aria-disabled="true"],
.section--light .btn--ghost[disabled] {
  background: transparent;
  border-color: #C2C9D6;
  color: #5A6274;
}

/* --------------------------------------------------------------------------
   22. PRINT
   -------------------------------------------------------------------------- */
@media print {
  .site-header, .site-footer, .scroll-cue, .ticker, .btn { display: none !important; }
  body { background: #fff; color: #000; }
  h1, h2, h3, h4 { color: #000; }
}
