/* ==========================================================================
   Fonts
   Retro Stereo Wide — the display face. Not on Google Fonts, so it is
   self-hosted from assets/fonts/. See assets/fonts/README.md for the exact
   filenames to drop in.
   Open Sans — body + UI, loaded from Google Fonts in each page's <head>.
   ========================================================================== */
@font-face {
  font-family: 'Retro Stereo Wide';
  src: url('../assets/fonts/retro-stereo-wide.woff2') format('woff2'),
       url('../assets/fonts/retro-stereo-wide.ttf')   format('truetype');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Retro Mono Wide';
  src: url('../assets/fonts/retro-mono-wide.woff2') format('woff2'),
       url('../assets/fonts/retro-mono-wide.ttf')    format('truetype');
  font-weight: 400; font-style: normal; font-display: swap;
}

/* ==========================================================================
   Classic Clean Express Car Wash — Design System
   Vibe: beach boutique / Seaside FL — airy, striped, sun-bleached, coastal.
   Colors sampled from the Classic Clean logo (bright red + sky blue) and the
   striped brand-guide swatch.
   ========================================================================== */

/* ---------- Tokens ----------
   STRICT PALETTE. These five are the only colours on the site:
     red  ·  light blue  ·  white  ·  dark blue  ·  the pinstripe
   Red and light blue are sampled from the client's own artwork. Dark blue is
   matched to the supplied swatch. --red-ink is the same brand red darkened
   only so white text on it clears WCAG AA; pure #FF0000 reaches just 4.00:1.
   ------------------------------------------------------------------------ */
:root {
  --red:        #FF0000;   /* brand red — logo #FF0000, divider art #F80000 */
  --red-ink:    #CC0000;   /* AA-safe red: anything with text on it */
  --blue:       #A9CCE5;   /* light blue — pinstripe base, sampled */
  --blue-light: #C1DAED;   /* pinstripe light tone, sampled */
  --navy:       #1B2A3B;   /* dark blue — contrast + type */
  --navy-deep:  #142131;   /* dark blue, deeper for large grounds */
  --white:      #FFFFFF;

  /* Legacy aliases so existing class names keep resolving. Every one of these
     now points at a palette colour — no sand, sun, teal or grey remains. */
  --cream:      var(--white);
  --sand:       var(--blue);
  --sand-deep:  rgba(27, 42, 59, .18);
  --sky:        var(--blue);
  --sky-soft:   var(--blue-light);
  --sky-wash:   var(--blue-light);
  --logo-blue:  var(--blue);
  --slate:      rgba(27, 42, 59, .78);  /* the dark blue, lightened — not a grey */

  /* Type */
  --font-display: 'Retro Mono Wide', 'Arial Black', Impact, sans-serif;
  --font-retro:   'Retro Mono Wide', 'Arial Black', Impact, sans-serif;
  --font-inline:  'Retro Stereo Wide', 'Arial Black', Impact, sans-serif;
  --font-heading: 'Open Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body:    'Open Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-accent:  'Open Sans', system-ui, sans-serif;

  /* Scale */
  --step-xs: 0.8125rem;
  --step-sm: 0.9375rem;
  --step-md: 1.0625rem;
  --step-lg: clamp(1.15rem, 0.6vw + 1rem, 1.35rem);
  --h3:      clamp(1.18rem, .7vw + 1rem, 1.42rem);
  --h2:      clamp(1.3rem, 1.4vw + .8rem, 2.05rem);
  --h1:      clamp(1.6rem, 2.8vw + .8rem, 3rem);

  /* Space + shape */
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --section-y: clamp(3.5rem, 7vw, 6.5rem);
  --wrap: 1180px;
  --wrap-narrow: 780px;
  --radius: 14px;
  --radius-lg: 22px;
  --pill: 999px;

  --shadow-sm: 0 2px 8px rgba(27, 42, 59, .08);
  --shadow-md: 0 10px 30px rgba(27, 42, 59, .12);
  --shadow-lg: 0 22px 60px rgba(27, 42, 59, .16);
  --shadow-hard: 6px 6px 0 var(--navy);
  --shadow-hard-red: 6px 6px 0 var(--red);

  --header-h: 88px;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--step-md);
  line-height: 1.65;
  color: var(--navy);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
picture { display: contents; }
/* <source> is metadata, but it computes to display:block, so display:contents
   on the picture hoists it into the parent as a real zero-height flex/grid
   item - and any gap on that parent then opens above the image. */
picture > source { display: none; }
a { color: var(--red-ink); text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:hover { color: var(--navy); }   /* neither remaining red both darkens and clears AA */

h1, h2, h3, h4 {
  color: var(--navy);
  margin: 0 0 .6em;
  text-wrap: balance;
}
/* Retro Mono Wide is NOT caps-only: it carries 26 distinct lowercase glyphs,
   cap-height but drawn differently from the capitals (lowercase 'a' is 2420
   units wide against 'A' at 2040). Left in sentence case, a heading renders a
   mix of the two sets and stops matching the brand specimen — so display
   headings are forced to the uppercase set. */
h1, h2 {
  font-family: var(--font-display);
  font-weight: 400; line-height: 1.08; letter-spacing: .01em;
  text-transform: uppercase;
}
/* Smaller headings stay on the body face so the display face stays special. */
h3, h4 {
  font-family: var(--font-heading);
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -.005em;
}
h1 { font-size: var(--h1); }
h2 { font-size: var(--h2); }
h3 { font-size: var(--h3); }
p  { margin: 0 0 1.1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

/* Accessibility */
:focus-visible {
  outline: 3px solid var(--red);
  outline-offset: 3px;
  border-radius: 4px;
}
.skip-link {
  position: absolute; left: 50%; top: 0; transform: translate(-50%, -120%);
  z-index: 200; background: var(--navy); color: var(--white);
  padding: .8rem 1.4rem; border-radius: 0 0 var(--radius) var(--radius);
  font-weight: 700; text-decoration: none;
}
.skip-link:focus { transform: translate(-50%, 0); color: var(--white); }
.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;
}

/* ---------- Layout ---------- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: var(--wrap-narrow); }
.wrap--wide { max-width: 1340px; }
/* Edge-to-edge: only the gutter holds content off the viewport edge. */
.wrap--full { max-width: none; }
.section { padding-block: var(--section-y); }
/* The hero's arch is drawn inside the hero, so its white curve already sits
   above the next section. Left as-is, the gap over that section's first line
   reads as the arch plus a full pad, roughly double the gap under its last
   line. Take the arch's depth back off the top. */
.hero + .section,
.has-arch + .section { padding-top: max(0.75rem, calc(var(--section-y) - clamp(40px, 6vw, 96px))); }
.section--sand { background: var(--sand); }
.section--sky  { background: var(--sky-wash); }
.section--navy { background: var(--navy-deep); color: var(--blue); }
.section--navy h1, .section--navy h2, .section--navy h3 { color: var(--white); }

.grid { display: grid; gap: clamp(1.25rem, 3vw, 2.25rem); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }

.stack > * + * { margin-top: 1.1rem; }
.center { text-align: center; }
.center .eyebrow { justify-content: center; }
.section-head { max-width: 46rem; margin-bottom: clamp(2rem, 4vw, 3rem); }
.center .section-head, .section-head.center { margin-inline: auto; }

/* ---------- Striped awning motif (the Seaside signature) ---------- */
.stripe-rule {
  height: 10px; border: 0; margin: 0;
  /* Same two layers as .section--striped - the pinstripe tile over a gradient
     on the tile's own 43px period - so the band under the header reads as a
     slice of the striped sections rather than its own separate pattern. */
  background:
    url("../assets/images/brand/pinstripe-tile.png") repeat top left,
    repeating-linear-gradient(90deg, var(--sky) 0 31px, var(--sky-soft) 31px 43px);
}
.stripe-rule--red {
  background: repeating-linear-gradient(90deg,
    var(--red) 0 14px, var(--white) 14px 28px);
}
.striped-bg {
  background: repeating-linear-gradient(90deg,
    var(--sky) 0 16px, var(--sky-soft) 16px 32px);
}

/* ---------- Eyebrow label ---------- */
.eyebrow {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--font-accent); font-weight: 700;
  font-size: var(--step-xs); letter-spacing: .2em; text-transform: uppercase;
  color: var(--red-ink); margin: 0 0 .9rem;
}
.eyebrow::before {
  content: ""; width: 28px; height: 3px; border-radius: 2px; background: var(--red);
}
.section--navy .eyebrow { color: var(--sky); }
.section--navy .eyebrow::before { background: var(--sky); }
/* --striped sets its own eyebrow colour further down; it is listed here only
   for the tinted grounds. Neither remaining red clears 4.5:1 on #A9CCE5 at
   13px, so the label goes navy and the dash keeps the brand red. */
.section--sand .eyebrow { color: var(--navy); }

/* ---------- Buttons (locked system — nothing else may look like these) ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font-family: var(--font-heading); font-weight: 700; font-size: 1.2rem;
  line-height: 1; text-decoration: none; cursor: pointer;
  padding: 1rem 1.9rem; border-radius: var(--radius); border: 2px solid transparent;
  min-height: 52px; /* comfortable mobile tap target */
  white-space: nowrap; text-align: center;
  transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .btn:hover { transform: none; } }

/* PRIMARY #1 marketing CTA — Free Wash.
   Uses --red-ink, not the raw #FF0000: every red fill on the site carries text,
   and one consistent red beats two near-identical ones sitting side by side. */
.btn--free {
  /* Gradient runs from the pure brand red down into the AA-safe red. The
     label is 1.2rem bold (>=18.66px bold), which WCAG counts as large text,
     so white on the lightest stop clears the 3:1 bar. */
  background: linear-gradient(180deg, var(--red) 0%, var(--red-ink) 100%);
  color: var(--white);
  box-shadow: 0 8px 24px rgba(204, 0, 0, .34);
}
.btn--free:hover {
  background: var(--red-ink);
  color: var(--white); box-shadow: 0 12px 32px rgba(204, 0, 0, .42);
}

/* PRIMARY #2 — Join the Unlimited Club. Navy solid. */
.btn--club { background: var(--navy); color: var(--white); box-shadow: var(--shadow-sm); }
/* The light blue from the logo. It needs a dark label - white on #A9CCE5 is
   only 1.7:1 - so the wordmark navy carries the text at 9.6:1. */
.btn--logo-blue {
  background: var(--blue); color: var(--navy-deep);
  border-color: var(--white); box-shadow: var(--shadow-sm);
}
.btn--logo-blue:hover { background: var(--blue-light); color: var(--navy-deep); }
.btn--club:hover { background: var(--navy-deep); color: var(--white); }

/* Secondary — outline, never competes with the two above */
.btn--ghost { background: transparent; color: var(--navy); border-color: var(--navy); }
.btn--ghost:hover { background: var(--navy); color: var(--white); }
.btn--ghost-light { background: transparent; color: var(--white); border-color: rgba(255,255,255,.6); }
.btn--ghost-light:hover { background: var(--white); color: var(--navy); border-color: var(--white); }

/* Icons inside buttons: the global img/svg reset gives them height:auto and
   display:block, which collapses an inline SVG with no intrinsic size. */
.btn svg { width: 1.05em; height: 1.05em; flex-shrink: 0; }
.btn--sm { padding: .62rem 1.15rem; font-size: 1rem; min-height: 44px; }
.btn--block { width: 100%; }
.btn-row { display: flex; flex-wrap: wrap; gap: .85rem; }
.center .btn-row { justify-content: center; }

/* ---------- Header ---------- */
/* Not sticky — the header scrolls away with the page. It still needs a
   stacking context so the oversized logo can hang over the stripe rule and
   the hero below it. */
.site-header {
  position: relative; z-index: 100;
  background: var(--cream);
  border-bottom: 1px solid var(--sand-deep);
}
.site-header__bar {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  min-height: 64px;
}
/* The badge is deliberately taller than the header and hangs past its bottom
   edge, overlapping the stripe rule and the top of the next section. The
   negative margin keeps it from growing the header: the bar ends up roughly
   48% of the logo height. The radial disc guarantees the mark stays legible
   where it overlaps a dark hero photo. */
.brand {
  display: flex; align-items: center; gap: .7rem; text-decoration: none;
  flex-shrink: 0; position: relative; z-index: 3;
}
.brand img {
  --logo-h: clamp(96px, 11vw, 158px);
  height: var(--logo-h); width: auto;
  /* Negative margins on BOTH sides: the badge rides up over the dark topbar
     and hangs down over the stripe rule into the section below, without
     either margin growing the header bar itself. */
  margin-top: calc(var(--logo-h) * -0.20);
  margin-bottom: calc(var(--logo-h) * -0.52);
  background: radial-gradient(circle at 50% 50%,
    var(--cream) 0 46%, rgba(253,251,247,0) 47%);
}
.brand__fallback {
  font-family: var(--font-retro); font-weight: 400; font-size: .95rem;
  color: var(--red); line-height: 1.05; letter-spacing: -.02em; text-transform: uppercase;
}
.brand__fallback span { display: block; font-family: var(--font-accent); font-weight: 500;
  font-size: .6rem; letter-spacing: .18em; color: var(--navy); }

.nav { display: flex; align-items: center; gap: clamp(.3rem, .85vw, .95rem); }
.nav__links { display: flex; align-items: center; gap: clamp(.3rem, .85vw, .95rem); }
/* Desktop only. The bar gives the nav all the room left of the logo, and the
   nav splits it: links take the free space and centre in it, the CTA sits at
   the far right. Before this the links were packed against the button. The
   button has to stay inside <nav> because the burger panel contains it, so
   the centring happens inside the nav rather than on the bar. */
@media (min-width: 1231px) {
  .site-header__bar { display: grid; grid-template-columns: auto minmax(0, 1fr); }
  .nav {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    column-gap: clamp(1.5rem, 4vw, 4rem);
  }
  .nav__links { justify-content: center; flex-wrap: wrap; }
}
.nav a:not(.btn) {
  font-family: var(--font-body); font-weight: 700; font-size: .875rem;
  color: var(--navy); text-decoration: none; padding: .5rem .15rem; white-space: nowrap;
  border-bottom: 2px solid transparent;
}

/* ---------- Locations submenu ----------------------------------------------
   Two locations do not warrant a hub page, so the parent is a button with no
   destination of its own. Opens on hover for pointers and on click/Enter for
   everyone else; Escape and an outside click close it. */
.nav__group { position: relative; }
.nav__sub-toggle {
  display: inline-flex; align-items: center; gap: .3rem;
  background: none; border: 0; cursor: pointer;
  font-family: var(--font-body); font-weight: 700; font-size: .875rem;
  color: var(--navy); padding: .5rem .15rem; white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.nav__sub-toggle[data-current="true"] { border-bottom-color: var(--red); }
.nav__chev { width: 14px; height: 14px; transition: transform .18s ease; }
.nav__sub-toggle[aria-expanded="true"] .nav__chev { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .nav__chev { transition: none; } }

.nav__sub {
  list-style: none; margin: 0; padding: .35rem;
  position: absolute; top: 100%; left: 0; z-index: 30;
  min-width: 15.5rem;
  background: var(--cream);
  border: 2px solid var(--navy); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.nav__sub[hidden] { display: none; }
.nav .nav__sub a {
  display: block; padding: .6rem .7rem; border-radius: 8px;
  border-bottom: 0; white-space: nowrap;
}
.nav .nav__sub a:hover,
.nav .nav__sub a:focus-visible { background: var(--blue); }
.nav .nav__sub a[aria-current="page"] { background: var(--blue); }

@media (max-width: 1230px) {
  /* Inside the burger panel it is just an indented list, not a floating card. */
  .nav__group { width: 100%; }
  .nav__sub-toggle {
    width: 100%; justify-content: space-between;
    padding: .95rem .25rem; font-size: 1.05rem;
    border-bottom: 1px solid var(--sand-deep);
  }
  .nav__sub {
    position: static; min-width: 0; padding: 0 0 0 .9rem;
    background: none; border: 0; border-bottom: 1px solid var(--sand-deep);
    box-shadow: none; border-radius: 0;
  }
  .nav .nav__sub a { padding: .8rem .25rem; font-size: 1rem; border-radius: 0; }
}
.nav a:not(.btn):hover { color: var(--red-ink); border-bottom-color: var(--red-ink); }
.nav a[aria-current="page"] { color: var(--red-ink); border-bottom-color: var(--red-ink); }

.nav-toggle {
  display: none; background: none; border: 0; cursor: pointer;
  padding: .6rem; border-radius: 8px; color: var(--navy);
}
.nav-toggle svg { width: 30px; height: 30px; }
.nav-toggle .icon-x { display: none; }
.nav-toggle[aria-expanded="true"] .icon-x { display: block; }
.nav-toggle[aria-expanded="true"] .icon-menu { display: none; }

@media (max-width: 1230px) {
  .nav-toggle { display: block; }
  /* In the burger panel the links stack; left as a row they measured 755px
     and pushed the whole page into horizontal scroll. */
  .nav__links { flex-direction: column; align-items: stretch; gap: 0; width: 100%; }
  .nav {
    /* Anchored under the header, not the viewport: with a non-sticky header a
       fixed panel would detach and float once the page scrolled. */
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--cream); border-bottom: 4px solid var(--red);
    padding: 1rem var(--gutter) 2rem;
    box-shadow: var(--shadow-lg);
    max-height: none;
    transform: translateY(-130%); transition: transform .28s ease;
  }
  .nav[data-open="true"] { transform: translateY(0); }
  .nav a:not(.btn) {
    padding: .95rem .25rem; border-bottom: 1px solid var(--sand-deep);
    font-size: 1.05rem;
  }
  .nav a:not(.btn):hover, .nav a[aria-current="page"] { border-bottom-color: var(--sand-deep); }
  .nav .btn { margin-top: 1rem; }
  @media (prefers-reduced-motion: reduce) { .nav { transition: none; } }
}

/* Header utility strip */
.topbar {
  position: relative; z-index: 1;   /* below .site-header's z-index 100 */
  background: var(--navy-deep); color: var(--blue);
  font-size: var(--step-xs); font-family: var(--font-accent);
  letter-spacing: .06em; text-transform: uppercase;
}
.topbar__inner { display: flex; flex-wrap: wrap; gap: .4rem 1.5rem; justify-content: center; padding-block: .55rem; }
/* On a phone these four items wrapped to three lines, and a bar that tall sits
   under the browser's own floating URL bar - the top line reads as cut off.
   Keep the one item worth a tap here; hours, both addresses and Manage My Plan
   are all in the footer. */
@media (max-width: 700px) {
  .topbar__wide { display: none; }
  .topbar__inner { flex-wrap: nowrap; white-space: nowrap; }
}
.topbar a { color: var(--white); text-decoration: none; font-weight: 500; }
.topbar a:hover { color: var(--sky); text-decoration: underline; }

/* ---------- Hero ---------- */
.hero { position: relative; background: var(--navy-deep); overflow: hidden; }
.hero__media { position: absolute; inset: 0; overflow: hidden; }
/* Parallax layer. Oversized by 28% and pulled up half of that, so the JS can
   drift it +/-11.5% of the section height without ever exposing an edge. The
   ::after overlay is a pseudo of .hero__media, not a child, so it stays put
   while the photo moves under it. */
.hero__media img,
.hero__media > .img-placeholder {
  position: absolute; left: 0; right: 0; top: -14%;
  width: 100%; height: 128%; object-fit: cover;
}
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(20,41,61,.72) 0%, rgba(20,41,61,.55) 45%, rgba(20,41,61,.85) 100%);
}
.hero__inner {
  position: relative; z-index: 1;
  padding-top: clamp(4rem, 12vw, 8.5rem);
  /* extra room at the foot so the arch never rides over the CTA row */
  padding-bottom: clamp(6rem, 15vw, 11rem);
  max-width: 46rem; color: var(--white);
}
/* Arch divider: the section below rises into the hero as a shallow dome.
   Wider than the hero so the curve stays gentle instead of pinching at the
   corners; .hero already clips the overhang. */
/* The arch that scoops the bottom edge of a hero into the section below.
   .has-arch puts it on any top-of-page band; --arch is the colour of whatever
   comes next, so the curve reads as that section rising into this one. The
   extra bottom padding is the arch's own height, so copy never runs under it. */
.hero, .has-arch { position: relative; overflow: hidden; }
.has-arch { padding-bottom: calc(var(--section-y) + clamp(40px, 6vw, 96px)); }
.has-arch--red { --arch: var(--red-ink); }
.hero::after,
.has-arch::after {
  content: ""; position: absolute; z-index: 2; pointer-events: none;
  left: -6%; right: -6%; bottom: -2px;
  height: clamp(40px, 6vw, 96px);
  background: var(--arch, var(--white));
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
}
.hero h1 { color: var(--white); text-shadow: 0 2px 20px rgba(0,0,0,.35); }
/* Kicker above the headline. Bigger than .eyebrow, which is 13px fine print --
   this line is doing too much work for that. */
.hero__kicker {
  font-family: var(--font-accent); font-weight: 700; text-transform: uppercase;
  font-size: var(--step-xs); letter-spacing: .2em; line-height: 1.3;
  /* White, not --sky: over a blown-out sky the overlay only gets the ground to
     #566573, where --sky is 3.55:1 -- under AA once this clamps down to 16px on
     a phone. White holds at 5.99:1 whatever photo goes behind it. */
  color: var(--white); margin: 0 0 .6rem;
  text-shadow: 0 2px 14px rgba(0, 0, 0, .35);
}
.hero__sub {
  font-size: var(--step-lg); color: var(--white);
  margin-bottom: 1.2rem; max-width: 38rem;
}
/* Closing line of the prep section, same voice as the hero tagline. */
/* The four "Wash it." lines. No markers and tight leading, so they read as a
   run of short beats rather than a feature list. */
.wash-it {
  list-style: none; margin: 1.1rem 0 0; padding: 0;
  display: grid; gap: .35rem;
  font-size: var(--step-md); color: var(--navy);
}

.prep-tagline {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: clamp(1rem, 1.7vw, 1.3rem); letter-spacing: .03em; line-height: 1.2;
  color: var(--red-ink); margin: 1.4rem 0 0;
}
.hero__tagline {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: clamp(.95rem, 1.6vw, 1.2rem); letter-spacing: .04em;
  color: var(--white); margin: 0 0 2rem;
  text-shadow: 0 2px 14px rgba(0, 0, 0, .35);
}
.hero .eyebrow { color: var(--sky); }
.hero .eyebrow::before { background: var(--sky); }
.hero__note { margin-top: 1.4rem; font-size: var(--step-sm); color: var(--white); }

@media (prefers-reduced-motion: reduce) {
  .hero__media img,
  .hero__media > .img-placeholder { transform: none !important; }
}

/* Placeholder styling — visible where a photo still needs to be dropped in */
.img-placeholder {
  display: grid; place-items: center; text-align: center;
  background:
    repeating-linear-gradient(45deg, var(--sky-soft) 0 12px, var(--sky-wash) 12px 24px);
  color: var(--navy); border: 2px dashed var(--sky);
  border-radius: var(--radius); padding: 2rem 1.25rem; min-height: 220px;
  font-family: var(--font-accent); font-size: var(--step-sm);
  letter-spacing: .08em; text-transform: uppercase; line-height: 1.5;
}
.img-placeholder code {
  display: block; margin-top: .5rem; font-family: ui-monospace, monospace;
  font-size: .72rem; letter-spacing: 0; text-transform: none; color: var(--slate);
}
.hero .img-placeholder {
  /* No height here: the parallax rule above sets it to 128% so the layer has
     room to drift. min-height keeps it filling the hero if that rule is ever
     removed. */
  min-height: 100%; border: 0; border-radius: 0;
  align-content: end; padding: 1rem;
  font-size: .68rem; letter-spacing: .04em; color: rgba(31,58,84,.55);
}
.hero .img-placeholder code { color: rgba(31,58,84,.5); font-size: .65rem; }

/* ---------- Cards ---------- */
.card {
  background: var(--white); border-radius: var(--radius-lg);
  border: 1px solid var(--sand-deep); box-shadow: var(--shadow-sm);
  padding: clamp(1.5rem, 3vw, 2.1rem);
  display: flex; flex-direction: column; gap: .85rem;
}
.card--flat { box-shadow: none; }
.card__icon {
  width: 52px; height: 52px; border-radius: var(--pill);
  display: grid; place-items: center; font-size: 1.5rem;
  background: var(--sky-wash); border: 2px solid var(--sky); flex-shrink: 0;
}
.card h3 { margin: 0; }
.card p { color: var(--slate); font-size: var(--step-sm); }
.card__spacer { margin-top: auto; }

.card--photo { padding: 0; overflow: hidden; }
.card--photo img, .card--photo .img-placeholder {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border: 0; border-radius: 0; min-height: 0;
}
.card--photo .card__body { padding: clamp(1.4rem, 3vw, 1.9rem); display: flex; flex-direction: column; gap: .8rem; flex: 1; }

/* Feature list with checks */
.checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; }
.checklist li { display: flex; gap: .7rem; align-items: flex-start; font-size: var(--step-sm); }
.checklist li::before {
  content: "✓"; flex-shrink: 0; width: 22px; height: 22px; margin-top: .12rem;
  display: grid; place-items: center; border-radius: var(--pill);
  background: var(--red-ink); color: var(--white); font-size: .7rem; font-weight: 700;
}
.section--navy .checklist li::before { background: var(--sky); color: var(--navy-deep); }
.checklist--sky li::before { background: var(--sky); color: var(--navy-deep); }

/* ---------- Pricing / plan cards ---------- */
.plan {
  background: var(--white); border: 2px solid var(--sand-deep);
  border-radius: var(--radius-lg); padding: clamp(1.6rem, 3vw, 2.2rem);
  display: flex; flex-direction: column; gap: 1rem; position: relative;
}
.plan--featured { border-color: var(--red); box-shadow: var(--shadow-md); }
.plan__flag {
  position: absolute; top: -14px; left: 50%; transform: translateX(-50%);
  background: var(--red-ink); color: var(--white); border-radius: var(--pill);
  font-family: var(--font-accent); font-size: var(--step-xs);
  letter-spacing: .14em; text-transform: uppercase; padding: .35rem 1rem; white-space: nowrap;
}
.plan__name { font-family: var(--font-heading); font-weight: 800; font-size: var(--h3); margin: 0; }
.plan__price { display: flex; align-items: baseline; gap: .3rem; font-family: var(--font-heading); }
.plan__price b { font-size: clamp(2.2rem, 4vw, 3rem); font-weight: 800; line-height: 1; color: var(--red); }
.plan__price span { font-size: var(--step-sm); color: var(--slate); font-family: var(--font-body); }

/* Accordion (what's included) */
.acc { border-top: 1px solid var(--sand-deep); }
/* Open list, no card: the rules between rows are the only structure it needs,
   so the container closes the last one off. */
.faq-list { border-bottom: 1px solid var(--sand-deep); }
.acc__btn {
  width: 100%; background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1rem 0; text-align: left;
  font-family: var(--font-heading); font-weight: 700; font-size: var(--step-sm); color: var(--navy);
}
.acc__btn::after { content: "+"; font-size: 1.4rem; line-height: 1; color: var(--red-ink); flex-shrink: 0; }
.acc__btn[aria-expanded="true"]::after { content: "–"; }
.acc__panel { padding-bottom: 1.1rem; }
.acc__panel[hidden] { display: none; }

/* ---------- Table (wash menu) ---------- */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--radius); }
table { width: 100%; border-collapse: collapse; background: var(--white); min-width: 520px; }
th, td { padding: .95rem 1.1rem; text-align: left; border-bottom: 1px solid var(--sand-deep); font-size: var(--step-sm); }
th { font-family: var(--font-accent); text-transform: uppercase; letter-spacing: .09em;
     background: var(--navy-deep); color: var(--white); font-weight: 500; }
tbody tr:nth-child(even) { background: var(--sky-wash); }

/* ---------- Split (image + text) ---------- */
.split { display: grid; gap: clamp(1.75rem, 4vw, 3.5rem); align-items: center;
         grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }
.split__media img, .split__media .img-placeholder {
  border-radius: var(--radius-lg); aspect-ratio: 4 / 3; object-fit: cover; width: 100%;
}
.split--reverse .split__media { order: 2; }
@media (max-width: 720px) { .split--reverse .split__media { order: 0; } }

/* ---------- Stats ---------- */
.stat { text-align: center; }
.stat b { display: block; font-family: var(--font-retro); font-weight: 400;
          font-size: clamp(2rem, 4vw, 2.9rem); color: var(--red); line-height: 1; }
.section--navy .stat b { color: var(--sky); }
.stat span { font-family: var(--font-accent); text-transform: uppercase;
             letter-spacing: .12em; font-size: var(--step-xs); color: var(--slate); }
.section--navy .stat span { color: var(--blue); }

/* ---------- Location block ---------- */
.loc-card { display: flex; flex-direction: column; gap: 1rem; }
.loc-card address { font-style: normal; font-size: var(--step-sm); color: var(--slate); }
.loc-card__meta { display: grid; gap: .45rem; font-size: var(--step-sm); }
.loc-card__meta div { display: flex; gap: .6rem; }
.loc-card__meta dt { font-weight: 700; color: var(--navy); min-width: 4.5rem; }
.loc-card__meta dd { margin: 0; color: var(--slate); }
.map-embed {
  border-radius: var(--radius-lg); overflow: hidden; border: 1px solid var(--sand-deep);
  box-shadow: var(--shadow-sm); background: var(--sky-wash);
}
.map-embed iframe { width: 100%; height: clamp(280px, 40vh, 420px); border: 0; display: block; }

/* ---------- Forms / embeds ---------- */
.embed-slot {
  border: 2px dashed var(--red); border-radius: var(--radius-lg);
  background: var(--white); padding: clamp(1.5rem, 4vw, 2.5rem);
  text-align: center;
}
.embed-slot h3 { color: var(--red-ink); }
.embed-slot p { color: var(--slate); font-size: var(--step-sm); margin-bottom: .6rem; }
.embed-slot code {
  display: inline-block; font-family: ui-monospace, monospace; font-size: .78rem;
  background: var(--sky-wash); padding: .2rem .5rem; border-radius: 6px; color: var(--navy);
}

/* ---------- Footer ---------- */
.site-footer { background: var(--navy-deep); color: var(--navy); padding-block: clamp(2.75rem, 6vw, 4.25rem) 0; }
.site-footer h2 {
  font-family: var(--font-accent); font-weight: 500; text-transform: uppercase;
  letter-spacing: .14em; font-size: var(--step-xs); line-height: 1.25;
  color: var(--sky); margin-bottom: 1.1rem;
}
.site-footer a { color: var(--blue); text-decoration: none; }
.site-footer a:hover { color: var(--white); text-decoration: underline; }
.footer-grid { display: grid; gap: clamp(2rem, 5vw, 3rem);
               grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); }
.footer-nav { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; font-size: var(--step-sm); }
.footer-brand__logo { display: inline-block; margin-bottom: 1rem; }
.footer-brand img { height: 104px; width: auto; }
.footer-brand p { font-size: var(--step-sm); color: var(--navy); }
.socials { display: flex; gap: .7rem; margin-top: 1.1rem; }
.socials a {
  width: 42px; height: 42px; border-radius: var(--pill); display: grid; place-items: center;
  background: rgba(255,255,255,.09); border: 1px solid rgba(255,255,255,.18);
}
.socials a:hover { background: var(--red); border-color: var(--red); }
.socials svg { width: 20px; height: 20px; fill: currentColor; }
.footer-bottom {
  margin-top: clamp(2rem, 5vw, 3rem); border-top: 1px solid rgba(255,255,255,.14);
  padding-block: 1.5rem; display: flex; flex-wrap: wrap; gap: .6rem 1.5rem;
  justify-content: space-between; font-size: var(--step-xs); color: var(--navy);
}
.footer-bottom nav { display: flex; flex-wrap: wrap; gap: .6rem 1.25rem; }

/* ---------- Standalone landing pages (no nav) ---------- */
.bare { min-height: 100dvh; display: flex; flex-direction: column; }
/* With the site footer below it, a full-viewport landing block would push
   that footer off-screen. */
.bare--footer { min-height: 0; }
.bare__head { padding: clamp(1.75rem, 5vw, 3rem) 0 0; text-align: center; }
.bare__head img { height: clamp(90px, 18vw, 132px); width: auto; margin-inline: auto; }
.bare__body { flex: 1; display: flex; align-items: center; padding-block: clamp(2rem, 5vw, 3.5rem); }
/* Pinstripe ground over a whole landing block, top of the page down to the
   footer. Same two layers as .section--striped; no border, because the block
   already runs to the edges of the viewport. */
.bare--striped {
  background:
    url("../assets/images/brand/pinstripe-tile.png") repeat top left,
    repeating-linear-gradient(90deg, var(--sky) 0 31px, var(--sky-soft) 31px 43px);
}
.bare--striped h1,
.bare--striped h2 { color: var(--navy-deep); }
.bare--striped .lead,
.bare--striped .muted { color: var(--navy); }
.bare--striped .eyebrow { color: var(--navy-deep); }   /* red is only 3.49:1 here */
.bare--striped .eyebrow::before { background: var(--red); }
.bare__foot { padding-block: 1.5rem; text-align: center; font-size: var(--step-xs); color: var(--slate); }

/* ---------- Legal / long-form copy ---------- */
.prose { max-width: 70ch; }
.prose h2 { font-size: var(--h3); margin-top: 2.4rem; }
.prose h3 { font-size: var(--step-lg); margin-top: 1.8rem; }
.prose ul, .prose ol { padding-left: 1.3rem; }
.prose li { margin-bottom: .5rem; }
.prose--legal { font-size: var(--step-sm); color: var(--navy); }

/* ---------- Scroll reveal ---------- */
/* No-JS safe: content is visible by default and only hidden once the .js class
   confirms the observer can reveal it again. */
.reveal { opacity: 1; transform: none; }
html.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity .6s ease, transform .6s ease; }
html.js .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.js .reveal { opacity: 1; transform: none; transition: none; }
}

/* ---------- Equipment rig: numbered spec plates ---------- */
/* Four plates taped to the pinstripe wall. Each carries a punched-out icon
   medallion overlapping its top edge, a ghosted spec number, and a small
   alternating tilt that straightens on hover. */
.rig {
  list-style: none; margin: 3.6rem 0 0; padding: 0;
  display: grid; gap: clamp(2.6rem, 3.4vw, 3rem) clamp(1.1rem, 2vw, 1.6rem);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 1080px) { .rig { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .rig { grid-template-columns: minmax(0, 1fr); } }

.rig__item {
  --tilt: -1.4deg;
  position: relative; isolation: isolate;
  padding: 3.75rem 1.5rem 1.7rem;
  background: var(--white);
  border-radius: var(--radius-lg);
  border-bottom: 4px solid var(--red);
  box-shadow: 6px 6px 0 rgba(20, 33, 49, .16);
  transform: rotate(var(--tilt));
  transition: transform .28s ease, box-shadow .28s ease;
}
.rig__item:nth-child(even) { --tilt: 1.4deg; }
.rig__item:hover {
  transform: rotate(0deg) translateY(-7px);
  box-shadow: 9px 12px 0 rgba(20, 33, 49, .2);
}

/* Medallion punched through the top edge. The white ring keeps it readable
   whether it lands on a stripe or on the plate. */
.rig__badge {
  position: absolute; top: 0; left: 1.5rem;
  transform: translateY(-50%);
  width: 62px; height: 62px; display: grid; place-content: center;
  border-radius: var(--pill);
  background: var(--navy-deep); color: var(--white);
  border: 4px solid var(--white);
  box-shadow: 0 4px 0 rgba(20, 33, 49, .16);
  transition: transform .28s ease, background-color .28s ease;
}
.rig__badge svg { width: 27px; height: 27px; }
.rig__item:hover .rig__badge {
  transform: translateY(-50%) rotate(-10deg) scale(1.09);
  background: var(--red); color: var(--white);
}

/* Spec number, ghosted so the heading stays the loudest thing on the plate. */
.rig__no {
  position: absolute; top: .3rem; right: .95rem; z-index: -1;
  font-family: var(--font-heading); font-weight: 800;
  font-size: 2.6rem; line-height: 1;
  color: var(--sky); opacity: .5;
  transition: opacity .28s ease, transform .28s ease;
}
.rig__item:hover .rig__no { opacity: .85; transform: translateY(-2px); }

.rig__item h3 { font-size: var(--step-md); margin-bottom: .45rem; }
.rig__item p { font-size: var(--step-sm); color: var(--slate); margin: 0; line-height: 1.55; }

/* Cascade: each plate keys off the list's own reveal. */
html.js .rig.reveal .rig__item {
  opacity: 0; transform: rotate(var(--tilt)) translateY(20px);
  transition: opacity .5s ease, transform .5s ease, box-shadow .28s ease;
}
html.js .rig.reveal.is-visible .rig__item { opacity: 1; transform: rotate(var(--tilt)); }
html.js .rig.reveal.is-visible .rig__item:nth-child(1) { transition-delay: .06s; }
html.js .rig.reveal.is-visible .rig__item:nth-child(2) { transition-delay: .16s; }
html.js .rig.reveal.is-visible .rig__item:nth-child(3) { transition-delay: .26s; }
html.js .rig.reveal.is-visible .rig__item:nth-child(4) { transition-delay: .36s; }
html.js .rig.reveal.is-visible .rig__item:hover {
  transform: rotate(0deg) translateY(-7px); transition-delay: 0s;
}

@media (prefers-reduced-motion: reduce) {
  .rig__item, .rig__item:hover,
  html.js .rig.reveal .rig__item,
  html.js .rig.reveal.is-visible .rig__item,
  html.js .rig.reveal.is-visible .rig__item:hover { transform: none; }
  html.js .rig.reveal .rig__item { opacity: 1; transition: none; }
  .rig__badge, .rig__item:hover .rig__badge { transform: translateY(-50%); }
  .rig__item:hover .rig__no { transform: none; }
}

/* ---------- Utilities ---------- */
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.lead { font-size: var(--step-lg); color: var(--navy); }
.section--navy .lead { color: var(--blue); }
.muted { color: var(--slate); font-size: var(--step-sm); }
.tag {
  display: inline-block; font-family: var(--font-accent); font-size: var(--step-xs);
  letter-spacing: .12em; text-transform: uppercase; background: var(--sky-wash);
  color: var(--navy); border: 1px solid var(--sky); border-radius: var(--pill);
  padding: .3rem .8rem;
}
.desktop-only { display: block; }
.mobile-only  { display: none; }
@media (max-width: 720px) {
  .desktop-only { display: none; }
  .mobile-only  { display: block; }
}

/* ==========================================================================
   COASTAL RETRO LAYER
   1970s Gulf-coast postcard cues: sunset bands, arched
   frames, chunky offset print shadows. Applied through existing classes so
   the markup stays clean.
   ========================================================================== */

/* ---------- Sunset band divider (retro cousin of the awning stripe) ------- */
.sunset-rule {
  height: 12px; border: 0; margin: 0;
  background: linear-gradient(90deg,
    var(--red) 0 25%, var(--white) 25% 50%,
    var(--blue) 50% 75%, var(--navy) 75% 100%);
}

.section--navy { position: relative; overflow: hidden; }
.section--navy > .wrap { position: relative; z-index: 1; }

/* A warm horizon glow at the base of the hero. */
.hero__media::after {
  background:
    linear-gradient(180deg, rgba(20,41,61,.70) 0%, rgba(20,41,61,.50) 42%,
                            rgba(20,41,61,.86) 100%),
    linear-gradient(0deg, rgba(232,118,60,.30) 0%, transparent 38%);
}

/* ---------- Arched frames (Seaside archway / retro postcard) ---------- */
.split__media img,
.split__media .img-placeholder {
  border-radius: 190px 190px var(--radius) var(--radius);
  border: 3px solid var(--navy);
  box-shadow: var(--shadow-hard);
}
.section--sky .split__media img,
.section--sky .split__media .img-placeholder { box-shadow: var(--shadow-hard-red); }

/* Photo cards get an arched top too. */
.card--photo { border-radius: 150px 150px var(--radius-lg) var(--radius-lg); }
.card--photo img,
.card--photo .img-placeholder { border-radius: 147px 147px 0 0; }

/* ==========================================================================
   ENTRANCE MOTION
   Both effects animate `scale`, the standalone property, never `transform`.
   The reveal system, the rig plates and every :hover already own `transform`,
   and an animation on it would seize the property mid-transition and snap back
   when it ended. `scale` composes with all of them and needs no coordination.
   Where the browser does not support it the animation is simply skipped.
   ========================================================================== */

@keyframes btn-bounce {
  0%   { scale: .84; opacity: 0; }
  55%  { scale: 1.06; opacity: 1; }
  78%  { scale: .98; }
  100% { scale: 1; opacity: 1; }
}

/* Buttons outside a reveal - the header CTA, the hero pair, the banners - land
   on page load. No fill mode, so a button that never animates is simply a
   normal button rather than an invisible one. */
html.js .btn { animation: btn-bounce .58s cubic-bezier(.34, 1.4, .64, 1); }
/* Inside a reveal they wait for it, so the bounce reads as part of the entrance
   rather than firing off-screen where nobody sees it. */
html.js .reveal .btn { animation: none; }
html.js .reveal.is-visible .btn { animation: btn-bounce .58s cubic-bezier(.34, 1.4, .64, 1) .18s backwards; }
/* A row of buttons arrives one after the other. */
html.js .reveal.is-visible .btn-row .btn:nth-child(2) { animation-delay: .28s; }
html.js .reveal.is-visible .btn-row .btn:nth-child(3) { animation-delay: .38s; }

@keyframes card-pulse {
  0%, 100% { scale: 1; }
  50%      { scale: 1.035; }
}

/* Two beats, then it settles - short enough to read as a flourish and to stay
   clear of the pause-control rule that applies to motion running past five
   seconds. Opt in per section with `pulse` on the grid; the children are the
   cards, whatever the grid happens to be called. */
html.js .pulse.is-visible > * {
  animation: card-pulse .9s ease-in-out .5s 2;
}
html.js .pulse.is-visible > *:nth-child(2) { animation-delay: .62s; }
html.js .pulse.is-visible > *:nth-child(3) { animation-delay: .74s; }
html.js .pulse.is-visible > *:nth-child(4) { animation-delay: .86s; }
html.js .pulse.is-visible > *:nth-child(5) { animation-delay: .98s; }
html.js .pulse.is-visible > *:nth-child(6) { animation-delay: 1.1s; }

@media (prefers-reduced-motion: reduce) {
  html.js .btn,
  html.js .reveal.is-visible .btn,
  html.js .pulse.is-visible > * { animation: none; }
}

/* ---------- Retro print shadows on cards + plans ---------- */
.card { border-width: 2px; border-color: var(--navy); box-shadow: 4px 4px 0 rgba(31,58,84,.14); }
.card--flat { box-shadow: none; border-color: var(--sand-deep); }
/* Tinted card, for a card sitting on white: a white one would only be its
   own border. Red-ink is 4.07:1 on this tone and brand red 2.76:1, both under
   the 4.5:1 bar, so links inside are navy and lean on the underline. */
.card--tint { background: var(--sky-soft); }
.card--tint a:not(.btn) { color: var(--navy); }
.plan { border-width: 3px; box-shadow: 5px 5px 0 rgba(31,58,84,.13); }
.plan--featured { box-shadow: var(--shadow-hard-red); }
.section--navy .card { border-color: rgba(255,255,255,.22); box-shadow: none; }

/* Icon chips become sun-colored roundels. */
.card__icon {
  background: var(--blue); border-color: var(--navy); border-width: 2px;
  font-family: var(--font-display); font-weight: 400; color: var(--navy);
}
.section--navy .card__icon { background: var(--blue); border-color: var(--navy); color: var(--navy); }

/* ---------- Retro badge seal ---------- */
.badge-seal {
  display: grid; place-content: center; text-align: center;
  width: clamp(122px, 17vw, 168px); aspect-ratio: 1; border-radius: var(--pill);
  background: var(--blue); color: var(--navy);
  border: 3px solid var(--navy); box-shadow: var(--shadow-hard);
  font-family: var(--font-retro); font-weight: 400; line-height: 1.05;
  font-size: clamp(.78rem, 1.2vw, .95rem); padding: 1rem;
  text-transform: uppercase;
  transform: rotate(-7deg);
}
/* ==========================================================================
   INCLUDED WITH EVERY WASH
   Two columns: the photo carries the seal and a drift of foam, the perks
   cascade in beside it.
   ========================================================================== */
.perks__media { position: relative; }

/* Seal sits on the corner of the photo and breathes, like a sticker that has
   not quite settled. */
.badge-seal--float {
  position: absolute; right: -5%; bottom: -17%; z-index: 3;
  width: clamp(96px, 13vw, 148px);
  animation: seal-bob 5s ease-in-out infinite;
}
@keyframes seal-bob {
  0%, 100% { transform: rotate(-7deg)  translateY(0); }
  50%      { transform: rotate(-2.5deg) translateY(-8px); }
}

/* Foam drifting up the photo. Its own clip so the bubbles stay inside the
   arched frame while the seal, a sibling, is free to hang over the edge. */
.perks__foam {
  position: absolute; inset: 0; z-index: 2; overflow: hidden;
  border-radius: 190px 190px var(--radius) var(--radius);
  pointer-events: none;
}
.perks__foam i {
  position: absolute; bottom: -14%;
  border-radius: 50%;
  background: rgba(255, 255, 255, .55);
  border: 2px solid rgba(255, 255, 255, .85);
  animation: foam-rise 9s linear infinite;
}
.perks__foam i:nth-child(1) { left:  8%; width: 16px; height: 16px; animation-duration: 8s;  animation-delay: 0s; }
.perks__foam i:nth-child(2) { left: 22%; width: 26px; height: 26px; animation-duration: 11s; animation-delay: 1.6s; }
.perks__foam i:nth-child(3) { left: 37%; width: 11px; height: 11px; animation-duration: 7s;  animation-delay: 3.1s; }
.perks__foam i:nth-child(4) { left: 53%; width: 21px; height: 21px; animation-duration: 10s; animation-delay: .8s; }
.perks__foam i:nth-child(5) { left: 68%; width: 14px; height: 14px; animation-duration: 8.5s; animation-delay: 4.2s; }
.perks__foam i:nth-child(6) { left: 80%; width: 30px; height: 30px; animation-duration: 12s; animation-delay: 2.4s; }
.perks__foam i:nth-child(7) { left: 91%; width: 13px; height: 13px; animation-duration: 9s;  animation-delay: 5.5s; }
@keyframes foam-rise {
  0%   { transform: translateY(0) translateX(0) scale(.7); opacity: 0; }
  12%  { opacity: 1; }
  80%  { opacity: 1; }
  100% { transform: translateY(-115%) translateX(14px) scale(1); opacity: 0; }
}

/* Perk list: each row slides in behind the one above it. */
/* Two columns, filled top-to-bottom: the first three labels stay in the left
   column and the last three move alongside them. Three explicit rows plus
   column flow is what keeps that order - a plain 2-column grid would run
   1,2 / 3,4 / 5,6 across instead.

   The switch is a container query, not a media query: this list sits in one
   half of a split, so how much room it has depends on whether that split has
   collapsed, not on the viewport. Keyed off the viewport it went two-up at
   900px, where its half is only ~360px and every label wrapped.

   The threshold has headroom rather than being fitted to a measurement: these
   labels are Open Sans off Google Fonts, so their real widths are not what a
   local fallback reports. Columns are max-content inside minmax(0, ...), so
   the worst case if the live font runs wider is the longest label taking two
   lines - grid rows are shared, so the columns stay aligned either way, and
   it can never overflow. */
.perks {
  list-style: none; margin: 1.6rem 0 0; padding: 0;
  display: grid; gap: .1rem 1.25rem;
}
.perks-col { container-type: inline-size; }
@container (min-width: 31rem) {
  .perks {
    grid-template-columns: repeat(2, minmax(0, max-content));
    grid-template-rows: repeat(3, auto);
    grid-auto-flow: column;
  }
}
.perk {
  display: flex; align-items: center; gap: .85rem;
  padding: .7rem .6rem; border-radius: var(--radius);
  transition: background-color .2s ease, transform .2s ease;
}
.perk__tick {
  flex-shrink: 0; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--red-ink); color: var(--white);
  border: 2px solid var(--navy);
  transition: transform .2s ease;
}
.perk__tick svg { width: 16px; height: 16px; stroke: currentColor; stroke-width: 3; fill: none; }
.perk__text b {
  display: block; font-family: var(--font-heading); font-weight: 800;
  font-size: var(--step-sm); color: var(--navy); line-height: 1.25;
}
.perk__text { font-size: var(--step-sm); color: var(--slate); line-height: 1.5; }
.perk:hover { background: rgba(255, 255, 255, .55); transform: translateX(4px); }
.perk:hover .perk__tick { transform: scale(1.12) rotate(-8deg); }

/* Cascade: the row's own delay keys off the section's reveal. */
html.js .split.reveal .perk {
  opacity: 0; transform: translateX(-14px);
  transition: opacity .5s ease, transform .5s ease, background-color .2s ease;
}
html.js .split.reveal.is-visible .perk { opacity: 1; transform: none; }
html.js .split.reveal.is-visible .perk:nth-child(1) { transition-delay: .10s; }
html.js .split.reveal.is-visible .perk:nth-child(2) { transition-delay: .18s; }
html.js .split.reveal.is-visible .perk:nth-child(3) { transition-delay: .26s; }
html.js .split.reveal.is-visible .perk:nth-child(4) { transition-delay: .34s; }
html.js .split.reveal.is-visible .perk:nth-child(5) { transition-delay: .42s; }
html.js .split.reveal.is-visible .perk:nth-child(6) { transition-delay: .50s; }

@media (prefers-reduced-motion: reduce) {
  .badge-seal--float { animation: none; }
  .perks__foam { display: none; }
  .perk, .perk:hover { transform: none; }
  .perk:hover .perk__tick { transform: none; }
  html.js .split.reveal .perk { opacity: 1; transform: none; transition: none; }
}
/* The seal hangs off the photo's right edge, which is fine while the split is
   two columns -- it lands in the gap. Once the split collapses (measured: one
   column up to 768px, two from 800px) the photo is full width and that
   overhang pokes past the gutter, so keep the seal inboard below 800. */
@media (max-width: 799px) {
  .badge-seal--float { right: 3%; bottom: -13%; }
}

.badge-seal small {
  display: block; font-family: var(--font-accent); font-weight: 700;
  font-size: .58rem; letter-spacing: .16em; text-transform: uppercase;
  margin-top: .3rem; color: var(--navy);  /* red is only 3.49:1 on light blue */
}

/* ---------- Buttons: chunky retro edge ---------- */
.btn--free { border-color: var(--navy); box-shadow: 4px 4px 0 var(--navy); }
.btn--free:hover { box-shadow: 5px 5px 0 var(--navy); }
.btn--club { border-color: var(--navy); box-shadow: 4px 4px 0 var(--blue); }
.btn--club:hover { box-shadow: 5px 5px 0 var(--blue); }
.btn--sm { box-shadow: 3px 3px 0 var(--navy); }
.btn--club.btn--sm { box-shadow: 3px 3px 0 var(--blue); }


/* ---------- Tags + table headers pick up the retro tones ---------- */
.tag { background: var(--blue); border-color: var(--navy); font-weight: 700; }
th { background: var(--navy); }
tbody tr:nth-child(even) { background: var(--blue-light); }

/* ---------- Sand sections get a subtle horizon line ---------- */
.section--sand { border-bottom: 3px solid var(--sand-deep); }

/* ---------- Reduced motion / narrow screens keep it calm ---------- */
@media (max-width: 620px) {
  .brand img { --logo-h: clamp(84px, 22vw, 108px); }
  .split__media img, .split__media .img-placeholder { border-radius: 120px 120px var(--radius) var(--radius); }
  .card--photo { border-radius: 110px 110px var(--radius-lg) var(--radius-lg); }
  .card--photo img, .card--photo .img-placeholder { border-radius: 107px 107px 0 0; }
}

/* ---------- Brand divider (the wave + Bronco graphic) ------------------- */
/* Decorative only — always aria-hidden with empty alt. The PNG background was
   keyed to transparent, so it sits on any section colour. */
.brand-divider { line-height: 0; overflow: hidden; }
.brand-divider img {
  width: 100%; height: auto; display: block;
  /* Keeps the wave from collapsing to a sliver on very wide screens */
  min-height: 54px; object-fit: cover; object-position: center bottom;
}
.brand-divider--navy { background: var(--navy-deep); }
.brand-divider--sand { background: var(--sand); }
.brand-divider--sky  { background: var(--sky-wash); }


/* ==========================================================================
   BRIGHT COASTAL RETRO — "party on the coast"
   Turns the volume up: sunnier grounds, a light-blue footer taken from the
   logo's Bronco, bolder colour blocking.
   ========================================================================== */

/* ---------- Extra section ground ---------- */
.section--sun { background: var(--blue); }

/* ---------- Hero: brighter, less murk ---------- */
.hero__media::after {
  background:
    linear-gradient(180deg, rgba(20,41,61,.62) 0%, rgba(20,41,61,.38) 45%,
                            rgba(20,41,61,.78) 100%),
    linear-gradient(0deg, rgba(232,118,60,.34) 0%, transparent 42%);
}

/* ---------- FOOTER: the Bronco blue from the logo ---------- */
.site-footer { background: var(--logo-blue); color: var(--navy); }
.site-footer h2 { color: var(--navy); }
.site-footer a:not(.btn) { color: var(--navy); font-weight: 600; }
.site-footer a:not(.btn):hover { color: var(--red-ink); }
.footer-brand p { color: var(--navy); }
.socials a {
  background: rgba(255,255,255,.72);
  border: 2px solid var(--navy);
  color: var(--navy);
  box-shadow: 3px 3px 0 var(--navy);
}
.socials a:hover { background: var(--red); border-color: var(--navy); color: var(--white); }
.footer-bottom {
  border-top: 2px solid rgba(31,58,84,.28);
  color: var(--navy);
}
.footer-bottom a { color: var(--navy); }

/* The wave divider sits on cream above the blue footer so its own light-blue
   stroke stays visible instead of blending into the footer. */
.brand-divider--cream { background: var(--cream); }


/* "Everything in X, plus" ladder */

/* ---------- Promo banner ---------- */
.promo-banner {
  background: var(--red-ink); color: var(--white);
  border-block: 3px solid var(--navy);
  text-align: center; padding-block: clamp(1.5rem, 3.5vw, 2.4rem);
  position: relative; overflow: hidden;
}
.promo-banner > * { position: relative; z-index: 1; }
.promo-banner h2 { color: var(--white); margin-bottom: .35rem; }
.promo-banner p { color: var(--white); font-weight: 600; }

/* ==========================================================================
   ANNUAL PLANS  —  "Year-Long Freedom"
   Ocean-at-dusk navy, a low sun behind the heading, and five passes with a
   wave breaking along the foot of each one.
   ========================================================================== */
.annual { background: var(--white); }

.annual-grid {
  display: grid; gap: clamp(.7rem, 1.4vw, 1.1rem);
  grid-template-columns: repeat(auto-fit, minmax(min(48%, 180px), 1fr));
}
@media (min-width: 1000px) { .annual-grid { grid-template-columns: repeat(5, 1fr); } }

/* Each plan is a beach pass: white ticket, red price, wave along the bottom. */
.pass {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: .3rem; padding: clamp(1.1rem, 2.2vw, 1.5rem) .9rem 0;
  background: var(--white); color: var(--navy); text-decoration: none;
  border: 3px solid var(--navy); border-radius: var(--radius-lg);
  box-shadow: 5px 6px 0 rgba(27, 42, 59, .20);
  overflow: hidden;
  transition: transform .2s ease, box-shadow .2s ease;
}
.pass:hover, .pass:focus-visible {
  transform: translateY(-6px);
  box-shadow: 5px 12px 0 var(--red);
}
@media (prefers-reduced-motion: reduce) { .pass:hover { transform: none; } }

.pass__name {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: clamp(.85rem, .85vw, .95rem); letter-spacing: .02em;
  line-height: 1.15; color: var(--navy);
}
.pass__price {
  font-family: var(--font-heading); font-weight: 800; line-height: 1;
  font-size: clamp(1.6rem, 2.6vw, 2.4rem); color: var(--red-ink);
}
.pass__price--todo { color: var(--slate); letter-spacing: -.04em; }
.pass__per {
  font-family: var(--font-accent); font-weight: 700; text-transform: uppercase;
  font-size: .72rem; letter-spacing: .1em; color: var(--slate);
  margin-bottom: .9rem;
}
/* Scalloped crest: a row of circles bitten out of the TOP of a blue band, so
   the solid edge is the one that meets the card. align-self overrides the
   card's align-items:center (which would collapse an empty span to zero width)
   and the negative inline margin cancels the card's side padding, so the band
   runs edge to edge; the card's own overflow:hidden rounds it into the bottom
   corners. */
.pass__wave {
  display: block; height: 18px; margin-top: auto;
  align-self: stretch; margin-inline: -.9rem;
  background:
    radial-gradient(circle at 9px 0, transparent 9px, var(--blue) 9px)
    0 0 / 18px 18px repeat-x;
}
.pass:hover .pass__wave { background-position-x: 9px; }

.annual__todo {
  margin-top: 1.6rem; font-size: .78rem; color: var(--slate);
}

/* ==========================================================================
   GIFT CARD BANNER  (location pages + contact)
   ========================================================================== */
.gift-banner {
  background: var(--red-ink);
  border-block: 3px solid var(--white);
  padding-block: clamp(1.6rem, 3.5vw, 2.6rem);
  position: relative; overflow: hidden;
}
.gift-banner > * { position: relative; z-index: 1; }
.gift-banner__inner {
  display: flex; align-items: center; gap: clamp(1rem, 2.5vw, 2rem);
  flex-wrap: wrap; justify-content: center; text-align: left;
}
.gift-banner__icon {
  flex-shrink: 0; display: grid; place-items: center;
  width: 62px; height: 62px; border-radius: 50%;
  background: var(--white); border: 3px solid var(--white);
}
.gift-banner__icon svg { width: 30px; height: 30px; stroke: var(--red-ink); fill: none; stroke-width: 2; }
.gift-banner__copy { flex: 1 1 20rem; }
.gift-banner__copy h2 { color: var(--white); margin: 0 0 .3rem; }
.gift-banner__copy p { color: var(--white); margin: 0; max-width: 34rem; }
@media (max-width: 620px) {
  .gift-banner__inner { text-align: center; }
  .gift-banner__copy { flex-basis: 100%; }
  .gift-banner .btn { width: 100%; }
}

/* ==========================================================================
   PRICE-BOARD STYLE SYSTEM
   Lifted from the client's Grand Opening mailer and wash-menu artwork:
   two-tone headings and white-on-red card blocks.
   ========================================================================== */

/* ---------- Two-tone heading: bold red word + navy word ---------- */
.title-duo { text-transform: uppercase; }
.title-duo b { color: var(--red-ink); font-weight: inherit; }
.title-duo span { color: var(--navy); font-weight: inherit; }
.section--red .title-duo b,
.section--navy .title-duo b { color: var(--white); }
.section--red .title-duo span,
.section--navy .title-duo span { color: var(--sky); }

/* ---------- Solid red section with white cards (the Fleet Plans look) --- */
.section--red {
  background: var(--red-ink); color: var(--white);
  position: relative; overflow: hidden;
}
.section--red h1, .section--red h2, .section--red h3 { color: var(--white); }
.section--red .lead { color: var(--white); }
.section--red .eyebrow { color: var(--white); }
.section--red .eyebrow::before { background: var(--white); }
.section--red > .wrap { position: relative; z-index: 1; }
.card--onred {
  background: var(--white); border: 3px solid var(--white);
  color: var(--red-ink); text-align: center; align-items: center;
  box-shadow: 6px 6px 0 rgba(0,0,0,.18);
}
.card--onred h3 { color: var(--red-ink); text-transform: uppercase; }
.card--onred p { color: var(--red-ink); font-size: var(--step-sm); }
.card--onred .card__icon {
  background: var(--white); border: 3px solid var(--red-ink);
  color: var(--red-ink); font-size: 1.7rem; width: 62px; height: 62px;
}

/* ---------- Offset display shadow, straight off the brand artwork --------
   White type on red with a soft white offset dropped down-right. */
.headline-punch,
.section--red h1, .section--red h2,
.promo-banner h2 {
  color: var(--white);
  text-shadow: .07em .07em 0 rgba(255, 255, 255, .34);
}
.section--navy h1, .section--navy h2 {
  text-shadow: .07em .07em 0 rgba(169, 204, 229, .3);
}

/* ---------- Wash-menu rows (mirrors the Grand Opening mailer layout) ---- */
.menu-rows { display: grid; gap: clamp(.85rem, 1.8vw, 1.25rem); }
.menu-row {
  display: grid; gap: clamp(.9rem, 2vw, 1.4rem); align-items: center;
  grid-template-columns: 1fr;
  background: repeating-linear-gradient(90deg,
    var(--sky) 0 16px, var(--sky-soft) 16px 32px);
  border: 3px solid var(--white);
  border-radius: var(--radius-lg);
  padding: clamp(1.1rem, 2.4vw, 1.6rem);
  box-shadow: 5px 5px 0 rgba(31, 58, 84, .2);
}
@media (min-width: 900px) {
  .menu-row { grid-template-columns: 1fr auto auto; }
  .menu-row__head { grid-column: 1 / -1; }
}
.menu-row__name {
  font-family: var(--font-retro); font-weight: 400;
  font-size: clamp(1.35rem, 2.4vw, 2rem); line-height: 1;
  margin: 0 0 .2rem; text-transform: uppercase; text-align: center;
}
.menu-row__blurb {
  text-align: center; font-size: var(--step-sm); color: var(--navy);
  margin: 0 auto; max-width: 60ch; font-weight: 600;
}
/* Red price badge + white single-wash box, straight off the mailer */
.menu-row__price {
  background: var(--red-ink); color: var(--white);
  border: 3px solid var(--white); border-radius: var(--radius);
  padding: .7rem 1.1rem; text-align: center; min-width: 132px;
  box-shadow: 3px 3px 0 rgba(31,58,84,.25);
}
.menu-row__price .lbl {
  display: block; font-family: var(--font-retro); font-size: .82rem;
  letter-spacing: .04em; text-transform: uppercase; line-height: 1;
}
.menu-row__price .was {
  display: block; font-weight: 800; font-size: 1rem; margin-top: .15rem;
  text-decoration: line-through; text-decoration-thickness: 2px;
}
.menu-row__price .now {
  display: block; font-family: var(--font-heading); font-weight: 800;
  font-size: 1.6rem; line-height: 1.05;
}
.menu-row__price .now small { font-size: .72rem; font-weight: 700; }
.menu-row__price .fine {
  display: block; font-family: var(--font-retro); font-size: .68rem;
  letter-spacing: .04em; text-transform: uppercase; margin-top: .1rem; line-height: 1.15;
}
.menu-row__single {
  background: var(--white); color: var(--navy);
  border: 3px solid var(--white); border-radius: var(--radius);
  padding: .8rem 1.1rem; text-align: center; min-width: 108px;
  box-shadow: 3px 3px 0 rgba(31,58,84,.25);
}
.menu-row__single .lbl {
  display: block; font-family: var(--font-retro); font-size: .78rem;
  letter-spacing: .06em; text-transform: uppercase; color: var(--navy); line-height: 1;
}
.menu-row__single .amt {
  display: block; font-family: var(--font-heading); font-weight: 800;
  font-size: 1.7rem; color: var(--navy); line-height: 1.1;
}

/* Line icons inherit the card's colour and sit centred in the roundel. */
.card__icon svg { width: 60%; height: 60%; display: block; }
.card--onred .card__icon svg { width: 62%; height: 62%; }

/* ---------- Full-bleed pinstripe section (the brand-guide swatch) -------
   The client's own Pinstripes.png, cut to a single 43px period. The shipped
   493px artwork is not a whole number of periods, so tiling it seams every
   493px; one period tiles cleanly and weighs 137 bytes. The gradient behind
   it is the same two sampled colours, so a blocked image is invisible.
   Small red and muted grey only reach 3.5:1 / 3.3:1 on the stripe — navy is
   the only colour that clears AA directly on it. */
.section--striped {
  background:
    url("../assets/images/brand/pinstripe-tile.png") repeat top left,
    repeating-linear-gradient(90deg, var(--sky) 0 31px, var(--sky-soft) 31px 43px);
  border-block: 3px solid var(--white);
}
.section--striped h1,
.section--striped h2,
.section--striped h3 { color: var(--navy-deep); }
.section--striped .lead { color: var(--navy); }
.section--striped .eyebrow { color: var(--navy-deep); }   /* red is only 3.49:1 here */
.section--striped .eyebrow::before { background: var(--red); }
.section--striped .muted { color: var(--navy); }

/* An arch already closes a section into the one below it, so a border across
   that same edge draws a line through the curve. Invisible where both sides
   are white; a stripe on fleet, where the arch is red. Declared after
   .section--striped so it wins - border-block sets both edges. */
.has-arch { border-bottom: 0; }

/* The small free-wash CTA in the header and footer carries the same
   full-brightness gradient as the hero button. White on #FF0000 is 4.00:1 --
   over the 3:1 large-text bar, under the 4.5:1 small-text one -- so the label
   is pushed to 1.175rem bold, the point where WCAG counts it as large text.
   Every other .btn--sm keeps its own size. */
.btn--free.btn--sm { font-size: 1.175rem; }

/* ---------- All-caps UI type -------------------------------------------
   CTAs, the header menu and the footer menus set in caps to match the brand's
   marketing voice. Done with text-transform so the HTML stays sentence case
   and screen readers still announce normal words. Caps need a little tracking
   to stay legible at these sizes. */
.btn {
  text-transform: uppercase;
  letter-spacing: .035em;
}
.nav a:not(.btn),
.nav__sub-toggle {
  text-transform: uppercase;
  letter-spacing: .035em;
}
.footer-nav li,
.footer-bottom nav a {
  text-transform: uppercase;
  letter-spacing: .05em;
}

/* Third-party form embeds (Paperform). The vendor injects its own markup, so
   we only own the wrapper: give it room and let it fill the column. */
.form-embed { margin-top: 1rem; text-align: left; min-height: 240px; }
.form-embed > div { width: 100%; }

/* ---------- Phone CTAs ---------------------------------------------------
   .btn carries white-space: nowrap so labels never break mid-phrase, but in
   caps "JOIN THE UNLIMITED CLUB" measures 364px — wider than a 360px screen,
   which pushed the page sideways. Below 560px the CTAs stack full width and
   are allowed to wrap, which also gives a bigger tap target. */
@media (max-width: 560px) {
  .btn { white-space: normal; padding-inline: 1.1rem; text-align: center; }
  .btn-row { flex-direction: column; align-items: stretch; }
  .btn-row .btn { width: 100%; }
  /* The header CTA inside the mobile nav panel is already full width there. */
  .nav .btn { width: 100%; }
}

/* Centred section heads: the markup puts .center ON .section-head, so a
   descendant selector never matched and the 46rem block stayed left-aligned
   even though its text was centred. */
.section-head.center { margin-inline: auto; }

/* ==========================================================================
   REVIEWS — scrolling wall
   Two rows drift in opposite directions and pause on hover or keyboard
   focus. The track holds the card set twice and animates to -50%, so the
   loop is seamless; the second copy is aria-hidden so screen readers and
   search engines see each review once.
   ========================================================================== */
/* "Read them all on Google", under the section lead */
.rev-more { margin: .85rem 0 0; font-size: .82rem; }
.rev-more a {
  font-family: var(--font-heading); font-weight: 800; text-transform: uppercase;
  letter-spacing: .06em; font-size: .78rem; color: var(--red-ink);
  text-underline-offset: 3px;
}

/* Stars */
.stars { display: inline-flex; gap: 1px; color: var(--red); line-height: 1; }
.stars svg { width: 1em; height: 1em; fill: currentColor; }
.rev-card .stars { font-size: .88rem; }

/* Rows */
.rev-rows {
  display: grid; gap: clamp(.7rem, 1.4vw, 1rem);
  margin-top: clamp(1.5rem, 3.5vw, 2.25rem);
}
/* No mask fade: the rows are meant to run the full width of the screen, so a
   card simply drives off one edge while another drives in from the other. */
.rev-marquee { overflow: hidden; }
.rev-track {
  display: flex; gap: clamp(.7rem, 1.4vw, 1rem); width: max-content;
  animation: rev-scroll 68s linear infinite;
}
.rev-marquee--reverse .rev-track { animation-direction: reverse; }
.rev-marquee:hover .rev-track,
.rev-marquee:focus-within .rev-track { animation-play-state: paused; }
@keyframes rev-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* No motion: stop the drift and let the row scroll by hand instead. */
@media (prefers-reduced-motion: reduce) {
  .rev-track { animation: none; width: auto; }
  .rev-marquee { overflow-x: auto; }
}

/* Phones scroll these by hand. The animated track is 3800-4400px wide, and
   iOS Safari blanks a composited layer that large - which is why the second
   row rendered as empty space on a phone while the first one played. Dropping
   the animation drops the huge layer with it. The duplicate set exists only to
   make the loop seamless, so it comes out too: with no loop it is the same
   reviews twice. */
@media (max-width: 700px) {
  .rev-track {
    animation: none; width: auto;
    scroll-snap-type: x mandatory;
  }
  .rev-marquee {
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    padding-inline: var(--gutter);
    scrollbar-width: none;
  }
  .rev-marquee::-webkit-scrollbar { display: none; }
  .rev-track > .rev-card[aria-hidden="true"] { display: none; }
  .rev-card { scroll-snap-align: center; }
}

/* Card */
.rev-card {
  /* Wider and tighter than a normal card on purpose: the extra width is what
     pulls a long review up from eight lines to five, which is the only way to
     make these shorter without trimming anybody's words. */
  flex: 0 0 clamp(288px, 30vw, 404px);
  background: var(--white); border: 2px solid var(--navy);
  border-radius: var(--radius-lg); box-shadow: 4px 4px 0 var(--blue);
  padding: .8rem .95rem; display: flex; flex-direction: column; gap: .4rem;
  transition: transform .2s ease, box-shadow .2s ease;
}
.rev-card:hover { transform: translateY(-3px); box-shadow: 4px 7px 0 var(--red); }
@media (prefers-reduced-motion: reduce) { .rev-card:hover { transform: none; } }

.rev-card__head { display: flex; align-items: center; gap: .5rem; }
.rev-card__avatar {
  width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--blue); border: 2px solid var(--navy);
  font-family: var(--font-heading); font-weight: 800; font-size: .82rem; color: var(--navy);
}
.rev-card__who { min-width: 0; }
.rev-card__name {
  font-family: var(--font-heading); font-weight: 800; font-size: .82rem;
  color: var(--navy); line-height: 1.2; margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rev-card__when { font-size: .68rem; color: var(--slate); }
.rev-card__text {
  /* auto top and bottom: every card in a row is as tall as the longest review
     in it, so the shorter ones centre their text in the slack instead of
     leaving a hole above the footer. */
  font-size: .8rem; line-height: 1.45; color: var(--navy); margin: auto 0;
}
.rev-card__foot {
  padding-top: .4rem; border-top: 2px dashed var(--sand-deep);
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  font-size: .64rem; color: var(--slate);
}
.rev-card__verified {
  display: inline-flex; align-items: center; gap: .28rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--navy);
}
.rev-card__verified svg { width: .76rem; height: .76rem; fill: var(--red-ink); }
.rev-card__where {
  font-family: var(--font-heading); font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--navy);
}

/* Phones */
@media (max-width: 640px) {
  .rev-card { flex: 0 0 300px; }
  .rev-card__name,
  .rev-card__text { font-size: .875rem; }
  .rev-card__when { font-size: .75rem; }
  .rev-card__foot { font-size: .72rem; }
  .rev-card__verified { letter-spacing: .03em; }
}

/* ==========================================================================
   WASH TIERS
   Replaces the surfboard artwork. The prices used to be baked into those PNGs,
   so the only way to retire the sale was to retire the images - which is also
   what makes the menu readable to a screen reader and translatable.

   Mobile-first, and the phone layout is the reference: wash name, what it
   includes, then the two prices side by side. Desktop keeps that exact
   composition and only grows into it - everything below 641px is the base and
   is deliberately left alone.

   Colour follows the two-red rule: on the light blue band the name is red and
   never smaller than 24px, where 3:1 is the bar it has to clear (it measures
   4.07); every small line there is navy, which clears 4.5.
   ========================================================================== */
.tiers { display: grid; gap: clamp(.9rem, 1.8vw, 1.3rem); margin-top: clamp(1.6rem, 3vw, 2.4rem); }

.tier { position: relative; }
.tier__link {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: .9rem 1rem;
  padding: clamp(1.1rem, 2.6vw, 1.7rem) clamp(1rem, 2.6vw, 1.8rem);
  background: var(--blue-light);
  border: 3px solid var(--navy);
  border-radius: var(--radius-lg);
  box-shadow: 5px 6px 0 rgba(27, 42, 59, .20);
  text-decoration: none;
  transition: transform .2s ease, box-shadow .2s ease;
}
.tier__link:hover, .tier__link:focus-visible {
  transform: translateY(-3px);
  box-shadow: 6px 9px 0 rgba(27, 42, 59, .24);
}
@media (prefers-reduced-motion: reduce) { .tier__link:hover { transform: none; } }

/* The name block spans the row above the prices. It leads in the markup too,
   so a screen reader hears the wash before its two prices. */
.tier__mid { grid-column: 1 / -1; text-align: center; min-width: 0; }
.tier__name {
  font-family: var(--font-display); font-weight: 400; text-transform: uppercase;
  /* 24px floor: below that the red would need 4.5:1 on this band, not 3:1. */
  font-size: clamp(1.5rem, 3.2vw, 2.1rem);
  line-height: 1.1; letter-spacing: .01em;
  color: var(--red-ink); margin: 0;
}
.tier__includes {
  margin: .45rem 0 0; color: var(--navy);
  font-size: var(--step-sm); line-height: 1.45;
}

.tier__price {
  display: grid; justify-items: center; gap: .1rem;
  width: 100%;
  padding: .6rem .85rem; border-radius: 12px;
  border: 2px solid var(--white);
}
.tier__plabel {
  font-family: var(--font-accent); font-weight: 700; text-transform: uppercase;
  font-size: .68rem; letter-spacing: .12em;
}
.tier__price b {
  font-family: var(--font-heading); font-weight: 800; line-height: 1;
  font-size: clamp(1.35rem, 2.6vw, 1.8rem);
  font-variant-numeric: tabular-nums;
}
.tier__price--monthly { background: var(--red-ink); color: var(--white); }
.tier__price--single  { background: var(--white);  color: var(--navy); }

/* The top tier carries the red band, so its boxes invert. */
.tier--top .tier__link { background: var(--red-ink); }
.tier--top .tier__name,
.tier--top .tier__includes { color: var(--white); }
.tier--top .tier__price--monthly { background: var(--navy); color: var(--white); }
.tier--top .tier__price--single  { background: var(--blue); color: var(--navy); }

.tier__flag {
  position: absolute; left: 50%; bottom: -13px; transform: translateX(-50%);
  background: var(--navy); color: var(--white);
  font-family: var(--font-accent); font-weight: 700; text-transform: uppercase;
  font-size: .68rem; letter-spacing: .12em;
  padding: .3rem .85rem; border-radius: var(--pill);
  border: 2px solid var(--white); white-space: nowrap;
}
.tier--top { margin-bottom: 14px; }

/* Desktop. The phone's composition - name, contents, prices - but laid out
   across the page instead of down it, so each wash is a squarish card rather
   than a long stripe. auto-fit gives three across at full width and two on a
   narrow laptop, and the last row centres rather than stretching. */
@media (min-width: 641px) {
  /* Flex rather than grid: with five cards the last row holds two, and a grid
     would pin them to the left of three empty tracks. A wrapped flex line
     centres its own leftovers. */
  .tiers {
    display: flex; flex-wrap: wrap; justify-content: center;
    max-width: 1120px; margin-inline: auto;
    gap: clamp(1.1rem, 2vw, 1.6rem);
  }
  .tier { flex: 1 1 290px; max-width: 356px; display: flex; flex-direction: column; }
  /* Cards in a row match the tallest, so the price boxes line up across them. */
  .tier__link {
    flex: 1;
    align-content: center;
    gap: clamp(.9rem, 1.2vw, 1.1rem);
    padding: clamp(1.6rem, 2.2vw, 2.1rem) clamp(1.1rem, 1.8vw, 1.5rem);
  }
  .tier__name { font-size: clamp(1.5rem, 2.3vw, 2.05rem); }
  .tier__includes { font-size: clamp(.95rem, 1.05vw, 1.05rem); }
  .tier__price { padding: clamp(.65rem, .95vw, .85rem) clamp(.6rem, 1vw, .9rem); }
  .tier__price b { font-size: clamp(1.45rem, 1.9vw, 1.85rem); }
  /* The flag sits in the row gap below the card rather than over the next one. */
  .tier--top { margin-bottom: 0; }
  .tier__flag { bottom: -14px; }
}
