/* ==========================================================================
   ShowroomFX — design system
   Palette: yellow / black / white. Ultra clean, modern, high contrast.
   Rule: yellow is a fill, never small text on white. Text on yellow is black.
   ========================================================================== */

:root {
  --yellow:      #FFD100;
  --yellow-deep: #E8BE00;
  --yellow-soft: #FFF3BF;

  --black:       #0B0B0C;
  --black-soft:  #17181A;
  --black-line:  #2A2C2F;

  /* Header charcoal — lifted off --black so the bar reads as its own surface
     against both the white hero and the black sections further down. */
  --charcoal:      #141619;
  --charcoal-line: rgba(255, 255, 255, .12);

  --white:       #FFFFFF;
  --grey-50:     #F6F7F8;
  --grey-100:    #EEF0F2;
  --grey-200:    #E1E4E7;
  --grey-400:    #A8AEB4;
  --grey-600:    #6B7278;

  --ink:         #0B0B0C;
  --muted:       #5F666C;
  --rule:        #E4E7EA;

  --display: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --sans:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, sans-serif;

  --container: 1240px;
  --gutter: 24px;
  --header-h: 78px;
  --r: 3px;

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

  /* Carbon weave for white surfaces — two opposing 45-degree hatches, each a
     pale strand against a marginally darker one, which is what gives the twill
     its direction. Held around 2% so it reads as a texture on the paper rather
     than as a pattern. The dark equivalent lives on .services-page. */
  --carbon-light:
    repeating-linear-gradient(45deg,
      rgba(11, 11, 12, .026) 0 1px,
      rgba(255, 255, 255, .9) 1px 2px,
      transparent 2px 6px),
    repeating-linear-gradient(-45deg,
      rgba(11, 11, 12, .020) 0 1px,
      rgba(255, 255, 255, .9) 1px 2px,
      transparent 2px 6px);
}

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

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

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16.5px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 0 0 18px;
  text-wrap: balance;
}

h1 { font-size: clamp(2.75rem, 6.4vw, 5.1rem); }
h2 { font-size: clamp(2.05rem, 4.1vw, 3.35rem); }
h3 { font-size: 1.22rem; line-height: 1.28; letter-spacing: -0.02em; }
h4 { font-size: 1rem; letter-spacing: -0.01em; }

p { margin: 0 0 18px; }
p:last-child { margin-bottom: 0; }

::selection { background: var(--yellow); color: var(--black); }

:focus-visible {
  outline: 2px solid var(--yellow);
  outline-offset: 3px;
}

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--yellow);
  color: var(--black);
  padding: 12px 20px;
  font-weight: 600;
}
.skip-link:focus { left: 12px; top: 12px; }

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

/* --- Type utilities ------------------------------------------------------- */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--sans);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 20px;
}
.eyebrow::before {
  content: "";
  width: 22px;
  height: 2px;
  background: var(--yellow);
}
.eyebrow.on-dark { color: var(--grey-400); }

.lead {
  font-size: 1.13rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 62ch;
}
.lead.on-dark { color: var(--grey-400); }

.mark { color: var(--yellow); }

/* Yellow highlighter behind a word — the one place yellow sits under text */
.hl {
  background: linear-gradient(to top, var(--yellow) 0 38%, transparent 38%);
  padding: 0 2px;
  /* Each line of a wrapped phrase gets its own band rather than one stretched
     across the break. */
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* --- Buttons -------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 30px;
  font-family: var(--sans);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  border: 1.5px solid transparent;
  border-radius: var(--r);
  cursor: pointer;
  transition: background .25s var(--ease), color .25s var(--ease),
              border-color .25s var(--ease), transform .25s var(--ease),
              box-shadow .25s var(--ease);
}
.btn:active { transform: translateY(1px); }

/* The yellow button is the one the whole site points at, so it gets a little
   more: a lift, a yellow-tinted shadow, and a gloss that travels across it on
   hover — the same idea as the chrome flash on the intro curtain.
 *
 * The sheen is a background layer rather than a pseudo-element. A ::after wide
 * enough to sweep has to sit either above the label, washing it out, or behind
 * the button's own background, where it cannot be seen at all. A background
 * image paints behind the text by definition. */
.btn-yellow {
  background-color: var(--yellow);
  color: var(--black);
  background-image: linear-gradient(100deg,
    rgba(255, 255, 255, 0) 40%,
    rgba(255, 255, 255, .55) 50%,
    rgba(255, 255, 255, 0) 60%);
  background-repeat: no-repeat;
  /* With a background wider than the box, 0% parks the band just off the right
     edge and 100% just off the left — anything outside that range never enters
     the button at all. */
  background-size: 250% 100%;
  background-position: 100% 0;
  box-shadow: 0 1px 2px rgba(11, 11, 12, .18);
  transition: background-color .25s var(--ease), color .25s var(--ease),
              border-color .25s var(--ease), transform .25s var(--ease),
              box-shadow .25s var(--ease),
              /* linear, not var(--ease): that curve front-loads the movement and
                 the gloss is gone inside 150ms instead of travelling. */
              background-position .7s linear;
}
.btn-yellow:hover {
  background-color: var(--yellow);
  background-position: 0% 0;
  transform: translateY(-2px);
  box-shadow: 0 10px 22px -6px rgba(255, 209, 0, .55), 0 2px 4px rgba(11, 11, 12, .2);
}
/* Base .btn:active is declared earlier, so the hover lift would otherwise win
   and the button would never look pressed. */
.btn-yellow:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(11, 11, 12, .18); }

.btn-black   { background: var(--black); color: var(--white); }
.btn-black:hover { background: var(--yellow); color: var(--black); }

.btn-outline { border-color: var(--black); color: var(--black); }
.btn-outline:hover { background: var(--black); color: var(--white); }

.btn-ghost   { border-color: rgba(255,255,255,.35); color: var(--white); }
.btn-ghost:hover { background: var(--white); color: var(--black); border-color: var(--white); }

.btn-block { width: 100%; }

.btn .arw { transition: transform .25s var(--ease); }
.btn:hover .arw { transform: translateX(4px); }

/* Text link with a yellow underline sweep */
.tlink {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
  padding-bottom: 5px;
  background-image: linear-gradient(var(--yellow), var(--yellow));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 2px;
  transition: background-size .3s var(--ease);
}
.tlink:hover { background-size: 40% 2px; }
.tlink .arw { transition: transform .25s var(--ease); }
.tlink:hover .arw { transform: translateX(4px); }

/* --- Header --------------------------------------------------------------- */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 80;
  height: var(--header-h);
  background: var(--charcoal);
  border-bottom: 1px solid var(--charcoal-line);
  color: var(--white);
  transition: background .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease);
}

/* Transparent header option for interior dark heroes. */
.site-header.over-hero {
  background: transparent;
  border-bottom-color: transparent;
  color: var(--white);
}

.site-header .nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 100%;
}

/* Brand: the logo art is pre-trimmed to its own bounds (aspect ~2.09), so it is
   sized by height and left to keep its ratio. No cropping, no object-fit. */
.brand {
  display: flex;
  align-items: center;
  flex: none;
}
/* height:100% only works against the header's fixed height. In the footer the
   parent is auto-height, so the percentage went circular and the brand box grew
   to fill the column, leaving the paragraph beneath it overlapping. */
.site-header .brand { height: 100%; }
.brand-wordmark {
  height: clamp(38px, 4.6vw, 54px);
  width: auto;
  max-width: none;
}
.site-footer .brand-wordmark { height: clamp(52px, 13vw, 68px); }

.nav-links {
  display: flex;
  align-items: center;
  gap: 30px;
  margin-left: auto;
}
.nav-links > a {
  position: relative;
  font-size: .82rem;
  font-weight: 500;
  letter-spacing: .02em;
  padding: 6px 0;
}
.nav-links > a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--yellow);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .28s var(--ease);
}
.nav-links > a:not(.btn):hover::after,
.nav-links > a.active:not(.btn)::after { transform: scaleX(1); }
.nav-links > a:not(.btn):hover,
.nav-links > a.active:not(.btn) { color: var(--yellow); }

/* Longer than a stock button — it is the only CTA in the bar, so it reads
   better with room around the label than tight to it. */
.nav-cta {
  padding: 13px 34px;
  min-width: 176px;
  font-size: .72rem;
  letter-spacing: .13em;
}

/* The header CTA carries .btn-yellow directly now, rather than being an outline
   button repainted here — that way it picks up the gloss and lift along with
   every other yellow button. Only the border still needs saying. */
.site-header .nav-cta { border-color: var(--yellow); }
/* The old hover flipped this to white. .btn-yellow now owns the hover — the
   gloss and the lift — so anything here would just fight it. Over the hero the
   button is already yellow for the same reason. */

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 42px;
  height: 42px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  height: 2px;
  width: 22px;
  /* Yellow rather than currentColor — the header is charcoal in both its states,
     so it reads against either. */
  background: var(--yellow);
  transition: transform .3s var(--ease), opacity .2s var(--ease);
}
.nav-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* --- Hero ----------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100svh;
  background: var(--white);
  color: var(--black);
  overflow: hidden;
  padding-top: var(--header-h);
}

.hero-stage {
  position: absolute;
  inset: var(--header-h) 0 0;

  /* The 120vh term caps the car off viewport *height*, not just width. Without
     it a short window keeps the car at full width while the hero shrinks around
     it, and the roofline shoots up past the wordmark. */
  --car-w: min(84vw, 1320px, 120vh);
  --wordmark-top: clamp(1rem, 2.4vh, 2.25rem);
  --wordmark-h: calc(.78 * clamp(4.8rem, 14.1vw, 13.8rem));
  /* How far the roofline rides up over the base of the wordmark. */
  --car-overlap: 22px;
  --dude-w: calc(var(--car-w) * .28);

  /* Height the hero actually occupies — phones run it shorter (see the 560px
     block), and the car maths below has to follow that, not assume a full
     screen. */
  --hero-h: 100svh;
  --car-bottom-cap: 18rem;

  /* Solved rather than eyeballed. The car art's visible roofline sits
     0.711 x element-height above the element's bottom edge, and element-height
     is --car-w / 1.3333. Parking the car this far off the floor lands the
     roofline exactly --car-overlap into the base of the wordmark — and holds
     there at any viewport height. The crew hang off this too, so moving the
     car moves all three together. */
  --car-bottom: clamp(2rem, calc(
      var(--hero-h) - var(--header-h)
      - .5455 * var(--car-w)
      - var(--wordmark-top)
      - var(--wordmark-h)
      + var(--car-overlap)
    ), var(--car-bottom-cap));
}

.hero-wordmark {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: var(--wordmark-top);
  width: 100%;
  margin: 0;
  overflow: hidden;
  color: var(--black);
  font-size: clamp(4.8rem, 14.1vw, 13.8rem);
  font-weight: 700;
  letter-spacing: -.085em;
  line-height: .78;
  text-align: center;
  white-space: nowrap;
  transform: translateX(-50%);
}
.hero-wordmark-text {
  display: block;
  transform: translateY(105%);
  animation: heroWordmarkIn 1.05s .2s cubic-bezier(.16, 1, .3, 1) forwards;
  will-change: transform;
}
.hero-wordmark-fx { color: var(--yellow); }

/* Crisp white detailing glints across the wordmark. They share its layer, so
   the car naturally passes in front of the lower sparks as it enters. */
.hero-shines {
  position: absolute;
  left: 0;
  right: 0;
  top: var(--wordmark-top);
  height: var(--wordmark-h);
  z-index: 1;
  pointer-events: none;
}
.hero-shines span {
  --shine-size: 30px;
  position: absolute;
  width: var(--shine-size);
  height: var(--shine-size);
  color: var(--white);
  background: radial-gradient(circle, rgba(255,255,255,.95) 0 7%, rgba(11,11,12,.12) 8%, transparent 58%);
  border-radius: 50%;
  opacity: 0;
  transform: translate3d(0, 2px, 0) rotate(-6deg) scale(.92);
  animation: heroShine 14s var(--shine-delay, 0s) ease-in-out infinite;
  filter:
    drop-shadow(0 0 1px rgba(11,11,12,.82))
    drop-shadow(0 2px 3px rgba(11,11,12,.28))
    drop-shadow(0 0 7px rgba(255,255,255,1));
}
.hero-shines span::before,
.hero-shines span::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background: currentColor;
  border-radius: 100%;
  transform: translate(-50%, -50%);
}
.hero-shines span::before { width: 4px; height: 100%; }
.hero-shines span::after { width: 100%; height: 4px; }
.hero-shines span:nth-child(1) { left: 5%; top: 18%; --shine-size: 42px; --shine-delay: -.5s; }
.hero-shines span:nth-child(2) { left: 18%; top: 57%; --shine-size: 25px; --shine-delay: -2.6s; }
.hero-shines span:nth-child(3) { left: 29%; top: 2%; --shine-size: 31px; --shine-delay: -4.7s; }
.hero-shines span:nth-child(4) { left: 42%; top: 36%; --shine-size: 22px; --shine-delay: -6.8s; }
.hero-shines span:nth-child(5) { left: 54%; top: 61%; --shine-size: 37px; --shine-delay: -9.2s; }
.hero-shines span:nth-child(6) { left: 65%; top: 3%; --shine-size: 26px; --shine-delay: -11.5s; }
.hero-shines span:nth-child(7) { right: 19%; top: 43%; --shine-size: 34px; --shine-delay: -1.8s; }
.hero-shines span:nth-child(8) { right: 4%; top: 13%; --shine-size: 41px; --shine-delay: -5.7s; }
.hero-shines span:nth-child(9) { left: 11%; top: -6%; --shine-size: 21px; --shine-delay: -8s; }
.hero-shines span:nth-child(10) { right: 34%; top: 72%; --shine-size: 24px; --shine-delay: -12.8s; }

@keyframes heroShine {
  0%, 100% {
    opacity: .12;
    transform: translate3d(0, 2px, 0) rotate(-6deg) scale(.92);
  }
  18% {
    opacity: .68;
    transform: translate3d(-7px, -5px, 0) rotate(-3deg) scale(1.02);
  }
  36% {
    opacity: .3;
    transform: translate3d(4px, -9px, 0) rotate(0deg) scale(.95);
  }
  55% {
    opacity: .88;
    transform: translate3d(10px, -2px, 0) rotate(3deg) scale(1.04);
  }
  73% {
    opacity: .4;
    transform: translate3d(6px, 7px, 0) rotate(6deg) scale(.96);
  }
  88% {
    opacity: .7;
    transform: translate3d(-5px, 3px, 0) rotate(2deg) scale(1.01);
  }
}

.hero-car {
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: var(--car-bottom);
  width: var(--car-w);
  max-width: none;
  height: auto;
  transform: translateX(-50%) scale(.985);
  transform-origin: 50% 75%;
  opacity: 0;
  animation: heroCarIn .9s cubic-bezier(.16, 1, .3, 1) forwards;
  will-change: transform, opacity;
}

/* Contact shadow, sitting on the same ground line as the crew. It has to paint
   over the car rather than behind it — the cutout carries an opaque studio floor,
   so anything underneath is simply hidden — hence the multiply blend, which
   darkens that floor instead of covering it. */
.hero-car-shadow {
  --shadow-h: calc(var(--car-w) * .10);
  position: absolute;
  z-index: 2;
  left: 50%;
  /* Centre sits a little below the ground line, so the bulk of it falls under
     the car rather than up over the sills. */
  bottom: calc(var(--car-bottom) + .194 * var(--car-w) - .62 * var(--shadow-h));
  width: calc(var(--car-w) * .78);
  height: var(--shadow-h);
  transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%,
    rgba(11, 11, 12, .40) 0%,
    rgba(11, 11, 12, .22) 44%,
    rgba(11, 11, 12, 0) 74%);
  mix-blend-mode: multiply;
  pointer-events: none;
  opacity: 0;
  animation: heroShadowIn .9s .1s var(--ease) forwards;
}
@keyframes heroShadowIn {
  to { opacity: 1; }
}

/* Crew either side of the car. Same ground-line method as the bucket on phones:
   the car's tyres sit at 74.13% of that asset's canvas and the two figures at
   95.5% (spray) and 94.3% (dry) of their own square canvases, so the offsets
   below stand all three on one line and keep them there at any width.

   Both are drawn facing inward — dry works the rear quarter from the left, spray
   rinses the nose from the right — so neither needs mirroring and the lettering
   on their uniforms stays the right way round. */
.hero-dude {
  /* Square art, so --dude-h is the element's width and its height. */
  --dude-scale: 1;
  --dude-h: calc(var(--dude-w) * var(--dude-scale));
  position: absolute;
  z-index: 2;
  width: var(--dude-h);
  height: auto;
  opacity: 0;
  transform: translateY(12px);
  animation: heroDudeIn .8s .4s cubic-bezier(.16, 1, .3, 1) forwards;
}
.hero-dude-dry {
  left: calc(50% - .545 * var(--car-w));
  bottom: calc(var(--car-bottom) + .194 * var(--car-w) - .057 * var(--dude-h));
}
/* Standing, and nearest the camera at the front of the car, so he runs bigger
   than the crouching figure at the rear. */
.hero-dude-spray {
  --dude-scale: 1.16;
  right: calc(50% - .645 * var(--car-w));
  bottom: calc(var(--car-bottom) + .194 * var(--car-w) - .045 * var(--dude-h));
  animation-delay: .52s;
}

.hero-copy {
  position: absolute;
  inset: auto var(--gutter) clamp(2rem, 4vh, 3.5rem);
  z-index: 3;
  text-align: center;
  opacity: 0;
  transform: translateY(12px);
  animation: heroCopyIn .7s .85s var(--ease) forwards;
}
.hero-copy p { margin: 0; }
.hero-kicker {
  font-size: clamp(.68rem, .85vw, .78rem);
  font-weight: 600;
  letter-spacing: .18em;
  line-height: 1.3;
}
/* Hero CTA sits directly under the strapline, centred with it. The width:auto
   overrides the full-bleed .btn rule phones get, so it stays a pill here. */
.hero-copy .hero-cta {
  width: auto;
  margin-top: 18px;
  padding: 15px 34px;
}

.hero-support {
  margin: 10px auto 0 !important;
  max-width: 52ch;
  color: var(--muted);
  font-size: clamp(.94rem, 1.15vw, 1.06rem);
  line-height: 1.55;
}

.hero-trust {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 22px;
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
.hero-trust li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.hero-trust li::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--yellow);
}

/* --- Soap suds (phones only) ---------------------------------------------- */

/* Decorative bubbles drifting up behind the car, to fill the bare space either
   side of it on narrow screens. Bubbles are injected by script.js. */
.hero-suds {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  display: none;
}
.hero-suds span {
  position: absolute;
  bottom: -18%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgba(255,255,255,.95) 0 8%, rgba(255,255,255,.28) 26%, rgba(255,255,255,0) 42%),
    radial-gradient(circle at 50% 50%, rgba(255, 209, 0, .16) 0 58%, rgba(11,11,12,.05) 78%, rgba(255,255,255,0) 100%);
  border: 1px solid rgba(11, 11, 12, .06);
  box-shadow: inset -2px -4px 8px rgba(255,255,255,.55), 0 1px 6px rgba(11,11,12,.05);
  animation: sudsRise linear infinite;
  will-change: transform, opacity;
}
@keyframes sudsRise {
  0%   { transform: translateY(0) translateX(0) scale(.92); opacity: 0; }
  12%  { opacity: .85; }
  70%  { opacity: .7; }
  100% { transform: translateY(-118vh) translateX(var(--drift, 12px)) scale(1.06); opacity: 0; }
}

@media (max-width: 700px) {
  .hero-suds { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-suds { display: none; }
}

.hero-subtitle {
  margin-top: 8px !important;
  color: var(--ink);
  font-family: var(--display);
  font-size: clamp(1rem, 1.55vw, 1.35rem);
  font-weight: 500;
  letter-spacing: -.025em;
}

@keyframes heroWordmarkIn {
  to { transform: translateY(0); }
}
@keyframes heroCarIn {
  to { opacity: 1; transform: translateX(-50%) scale(1); }
}
@keyframes heroCopyIn {
  to { opacity: 1; transform: translateY(0); }
}
@keyframes heroDudeIn {
  to { opacity: 1; transform: none; }
}

/* --- Template-led home flow ---------------------------------------------- */

.home-heading {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(260px, .7fr);
  column-gap: clamp(36px, 8vw, 110px);
  align-items: end;
  margin-bottom: 44px;
}
.home-heading .eyebrow { grid-column: 1 / -1; }
.home-heading h2 {
  max-width: 17ch;
  margin: 0;
  font-size: clamp(2.35rem, 5vw, 4.5rem);
}
.home-heading > p {
  color: var(--muted);
  margin: 0 0 8px;
  max-width: 34ch;
}

.service-posters {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
.service-poster {
  position: relative;
  min-height: 390px;
  overflow: hidden;
  border-radius: 14px;
  padding: 22px;
  background: var(--black);
  color: var(--white);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  isolation: isolate;
  transition: transform .35s var(--ease);
}
/* Photo thumbnail behind each poster. The gradient is what makes the white
   copy legible over the image — without it the text sits on mid-tone paint. */
.service-poster-media {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: block;
  background: var(--yellow);
}
.service-poster-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s var(--ease);
}
.service-poster-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
      rgba(11, 11, 12, .34) 0%,
      rgba(11, 11, 12, .60) 46%,
      rgba(11, 11, 12, .86) 100%);
}
.service-poster:hover .service-poster-media img { transform: scale(1.05); }

/* Card 01 carries both photos. The 1% gap between the two clip paths lets the
   wrapper's yellow through as a diagonal seam. */
.service-poster-media.split img:first-child { clip-path: polygon(0 0, 62% 0, 38% 100%, 0 100%); }
.service-poster-media.split img:last-child  { clip-path: polygon(63% 0, 100% 0, 100% 100%, 39% 100%); }

.service-poster:hover { transform: translateY(-5px); }

/* The pick of the three. Same photo card as its neighbours, ringed in yellow
   with the glow thrown inward off the edges. The glow rides on the media's
   gradient layer, which already sits above the photo and below the copy — an
   inset shadow on the card itself would paint under the photo instead. */
.service-poster.featured { border: 2px solid var(--yellow); }
.service-poster.featured .service-poster-media::after {
  box-shadow: inset 0 0 42px rgba(255, 209, 0, .38);
}

/* --- Membership stripe ---------------------------------------------------- */

/* Yellow glow off the left edge, MEMBERSHIP across it, pricing in the middle,
   car in the right third of the artwork.
 *
 * The glow is capped at 50% yellow deliberately. Composited over the near-black
 * it lands around #907805, which holds ~4.4:1 against white — fine for the
 * large MEMBERSHIP wordmark (AA large text is 3:1) but not for body copy, which
 * is why nothing small sits on it. Push the yellow higher and white stops being
 * legible: at 70% it drops to ~2.6:1 and fails even as large text. The site's
 * usual rule still stands everywhere else — black on solid yellow. */
.member-stripe {
  display: block;
  margin-bottom: 26px;
  padding: 26px clamp(22px, 3vw, 34px);
  min-height: 172px;
  background-color: var(--black);
  background-image:
    linear-gradient(90deg, rgba(255,209,0,.50) 0%, rgba(255,209,0,.30) 14%, rgba(255,209,0,.08) 30%, rgba(255,209,0,0) 44%),
    linear-gradient(90deg, rgba(11,11,12,.94) 0%, rgba(11,11,12,.90) 42%, rgba(11,11,12,.35) 68%, rgba(11,11,12,0) 88%),
    url('assets/membership.webp');
  background-repeat: no-repeat;
  background-position: right center;
  background-size: cover;
  border-radius: var(--r);
  color: var(--white);
  text-decoration: none;
  transition: box-shadow .25s var(--ease);
}
.member-stripe:hover { box-shadow: 0 0 0 1px var(--yellow); }
.member-stripe:hover .arw { transform: translateX(4px); }
.member-stripe:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--yellow); }

.member-stripe-inner {
  display: flex;
  align-items: center;
  gap: clamp(20px, 3vw, 40px);
  /* Stop short of the car rather than running content across it. */
  max-width: 72%;
}

/* Matches the package card headings exactly — same clamp, tracking and leading
   as `.service-poster h3` plus the base h1-h4 rule it inherits from. Sits in
   the brightest part of the glow, which the size comfortably clears for AA. */
.member-stripe-label {
  flex: none;
  font-family: var(--display);
  font-size: clamp(1.6rem, 2.45vw, 2.35rem);
  font-weight: 700;
  line-height: .95;
  /* -0.02em, not the -0.03em on h1-h4 — the `h3` rule narrows it and that is
     what the card headings actually compute to. */
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--white);
}

.member-stripe-mid { min-width: 0; }
.member-stripe-mid strong {
  display: block;
  font-family: var(--display);
  font-size: clamp(1rem, 1.5vw, 1.2rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
}
.member-stripe-sub {
  display: block;
  margin-top: 5px;
  font-size: .86rem;
  color: var(--grey-400);
}

.member-stripe-figures {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.member-stripe-price { display: flex; align-items: baseline; gap: 10px; }
/* --grey-600 is the usual "dimmer than body" grey, but it only reaches ~3.3:1
   on the black here — under AA for text this size, and this is a real price. */
.member-stripe-price s { color: var(--grey-400); font-size: .9rem; }
.member-stripe-price b {
  font-family: var(--display);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.member-stripe-price i {
  font-style: normal;
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 500;
  color: var(--grey-400);
}
/* The saving is the point, so it gets the fill — black on yellow, per the one
   colour rule. It sits past the glow, where solid yellow still reads. */
.member-stripe-save {
  padding: 6px 11px;
  border-radius: 100px;
  background: var(--yellow);
  color: var(--black);
  font-size: .72rem;
  font-weight: 700;
  white-space: nowrap;
}
.member-stripe .arw { transition: transform .25s var(--ease); }

.service-poster-flag {
  position: absolute;
  z-index: 1;
  top: 20px;
  right: 20px;
  padding: 6px 11px;
  border-radius: 100px;
  background: var(--yellow);
  color: var(--black);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.service-poster-no,
.service-poster-link {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.service-poster-body { margin-top: auto; }
.service-poster-list {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
}
.service-poster-list li {
  position: relative;
  padding: 6px 0 6px 20px;
  font-size: .84rem;
  line-height: 1.4;
  color: var(--grey-200);
}
.service-poster-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 13px;
  width: 9px;
  height: 5px;
  border-left: 2px solid var(--yellow);
  border-bottom: 2px solid var(--yellow);
  transform: rotate(-45deg);
}
.service-poster-cta { padding: 12px 24px; font-size: .7rem; }

.services-note {
  margin-top: 30px;
  text-align: center;
  font-size: .84rem;
  color: var(--muted);
}

/* Bottom row of each card: price left, link right. */
.service-poster-price i {
  font-style: normal;
  font-family: var(--sans);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--grey-200);
}

.service-poster-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}
.service-poster-price {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  font-family: var(--display);
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -.025em;
  line-height: 1;
  color: var(--yellow);
}
.service-poster-price small {
  font-family: var(--sans);
  font-size: .6rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--grey-200);
}
.service-poster h3 {
  margin: 0 0 12px;
  font-size: clamp(1.6rem, 2.45vw, 2.35rem);
  line-height: .95;
  text-transform: uppercase;
}
.service-poster p {
  margin: 0;
  max-width: 20ch;
  color: var(--grey-200);
  font-size: .86rem;
  line-height: 1.45;
}

.instagram-showcase { padding-top: 0; }
.instagram-shell {
  overflow: hidden;
  border-radius: 18px;
  padding: clamp(38px, 5vw, 64px);
  background: var(--black);
  color: var(--white);
}
.instagram-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 36px;
  margin-bottom: 38px;
}
.instagram-head h2 {
  margin-bottom: 12px;
  color: var(--white);
  font-size: clamp(2.25rem, 4vw, 3.75rem);
}
.instagram-head p {
  max-width: 52ch;
  margin: 0;
  color: var(--grey-400);
}
.instagram-head .btn { flex: none; }
/* Two follow buttons side by side, wrapping before they squeeze the heading. */
.instagram-actions {
  display: flex;
  flex: none;
  flex-wrap: wrap;
  gap: 10px;
}
.instagram-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
.instagram-post {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: 12px;
  background: var(--black-soft);
}
.instagram-post::after {
  content: "";
  position: absolute;
  inset: 45% 0 0;
  background: linear-gradient(transparent, rgba(11,11,12,.78));
  pointer-events: none;
}
.instagram-post img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .55s var(--ease);
}
.instagram-post:hover img { transform: scale(1.045); }
.instagram-post > span {
  position: absolute;
  z-index: 2;
  inset: auto 18px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: var(--white);
}
.instagram-post strong {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.instagram-post i {
  font-style: normal;
  font-size: 1.1rem;
}
.instagram-post-light { background: var(--white); }
.instagram-post-light img { object-position: center; }
.instagram-post-light::after {
  background: linear-gradient(transparent, rgba(11,11,12,.66));
}
/* Add-ons: two ticked columns rather than the accordion this section used to
   be — every line is one short phrase, so there is nothing to expand into. */
.home-addons { padding-top: 0; }
.addon-group {
  margin: 0 0 6px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--black);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink);
}

.proof-section { padding: 0 var(--gutter); }
.proof-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  max-width: var(--container);
  padding: 0;
  overflow: hidden;
  border-radius: 16px;
  background: var(--grey-50);
}
.proof-grid div {
  padding: 42px 24px;
  text-align: center;
  border-right: 1px solid var(--rule);
}
.proof-grid div:last-child { border-right: 0; }
.proof-grid strong {
  display: block;
  margin-bottom: 8px;
  font-family: var(--display);
  font-size: clamp(2rem, 3.6vw, 3.2rem);
  line-height: 1;
  letter-spacing: -.05em;
}
.proof-grid span {
  color: var(--muted);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.home-packages { background: var(--white); }
.home-tiers .tier { border-radius: 16px; }
.home-tiers .tier.featured { transform: translateY(-10px); }
.home-reviews { padding-top: 0; }
.home-reviews .quote {
  min-height: 290px;
  border-radius: 16px;
}
.home-reviews .stars {
  font-size: .82rem;
  letter-spacing: .12em;
}
.home-cta .eyebrow { margin-bottom: 14px; color: var(--black); }
.home-cta .eyebrow::before { background: var(--black); }

/* --- Page hero (interior pages) ------------------------------------------- */

.page-hero {
  background: var(--black);
  color: var(--white);
  padding: calc(var(--header-h) + 96px) 0 84px;
}
.page-hero h1 { font-size: clamp(2.4rem, 5.2vw, 4.05rem); max-width: 18ch; }
.page-hero .lead { margin-top: 22px; }


@media (prefers-reduced-motion: reduce) {
  .btn-yellow { transition: background-color .25s linear; }
  .btn-yellow:hover { transform: none; background-position: 100% 0; }

  .hero-wordmark-text,
  .hero-car,
  .hero-car-shadow,
  .hero-dude,
  .hero-copy {
    animation: none;
    opacity: 1;
  }
  .hero-wordmark-text,
  .hero-dude { transform: none; }
  .hero-car { transform: translateX(-50%); }
  .hero-copy { transform: none; }
  .hero-shines span { animation: none; opacity: .8; transform: none; }
}

/* --- Hero reveal ----------------------------------------------------------
   The hero parks itself at the top of the viewport and everything after it
   rides up over the top of it — "Pick your detail" reads as a sheet pulled up
   over the car rather than the page scrolling past it.

   Two things make it work: the hero is sticky at z-index 0, and every sibling
   after it is positioned above with an opaque background of its own. Painting
   order in the root stacking context puts a positioned z-index:0 box above the
   backgrounds of *later* unpositioned ones, so the footer needs lifting too. */

.hero {
  position: sticky;
  top: 0;
  z-index: 0;
}

.hero ~ *,
.site-footer {
  position: relative;
  z-index: 1;
  /* Opaque by default — the hero stays pinned behind the whole page, so a
     see-through section would show the car through it. Sections that set
     their own fill (.grey, .dark, .cta-band) still win, being later or
     more specific, and the background shorthand in those rules clears the
     weave with it. */
  background: var(--white);
  background-image: var(--carbon-light);
}

/* The panel edge. Hero and section are both white, so without a rule and a
   soft cast shadow the join is invisible. */
.hero + .section {
  background: var(--white);
  background-image: var(--carbon-light);
  border-top: 1px solid var(--rule);
  box-shadow: 0 -26px 60px -22px rgba(11, 11, 12, .22);
}

/* Hero dims as it goes under, so it reads as sitting behind rather than
   being clipped. Scroll-driven, so it tracks the scrollbar exactly; browsers
   without scroll timelines just get the cover with no dim. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero::before {
      content: "";
      position: absolute;
      inset: 0;
      z-index: 4;
      background: var(--black);
      opacity: 0;
      pointer-events: none;
      animation: heroRecede linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 90svh;
    }
  }
}

@keyframes heroRecede {
  to { opacity: .12; }
}

/* --- Sections ------------------------------------------------------------- */

.section { padding: clamp(72px, 9vw, 118px) 0; }
.section.tight { padding: clamp(56px, 6vw, 80px) 0; }
.section.grey  { background: var(--grey-50); }
.section.dark  { background: var(--black); color: var(--white); }
.section.dark h1, .section.dark h2, .section.dark h3 { color: var(--white); }
.section.dark p { color: var(--grey-400); }

.section-head { max-width: 640px; margin-bottom: 54px; }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.section-head.center .eyebrow { justify-content: center; }
.section-head p { color: var(--muted); font-size: 1.05rem; }

/* Head with a link parked on the right */
.head-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 30px;
  margin-bottom: 48px;
}
.head-row .section-head { margin-bottom: 0; }

/* --- Split layout --------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: clamp(38px, 6vw, 88px);
  align-items: start;
}
.split.even { grid-template-columns: 1fr 1fr; }
.split.wide-left { grid-template-columns: 1.25fr 1fr; }
.split-sticky { position: sticky; top: calc(var(--header-h) + 40px); }

/* --- Grids and cards ------------------------------------------------------ */

.grid { display: grid; gap: 1px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

/* Hairline grid: cards butt together, separated by a single rule */
.grid.hairline {
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--r);
  overflow: hidden;
}
.section.dark .grid.hairline { background: var(--black-line); border-color: var(--black-line); }

.card {
  position: relative;
  background: var(--white);
  padding: 40px 34px 42px;
  transition: background .3s var(--ease);
}
.section.grey .card { background: var(--white); }
.section.dark .card { background: var(--black); }

/* Yellow rule that draws in across the top on hover */
.card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--yellow);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .35s var(--ease);
}
.card:hover::before { transform: scaleX(1); }
.card:hover { background: var(--grey-50); }
.section.dark .card:hover { background: var(--black-soft); }

.card .num {
  font-family: var(--display);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--grey-400);
  display: block;
  margin-bottom: 26px;
}
.card .icon {
  width: 42px;
  height: 42px;
  margin-bottom: 24px;
  color: var(--black);
}
.section.dark .card .icon { color: var(--yellow); }
.card .icon svg { width: 100%; height: 100%; fill: none; stroke: currentColor; }
.card h3 { margin-bottom: 12px; }
.card p { color: var(--muted); font-size: .95rem; margin-bottom: 0; }
.card .tlink { margin-top: 22px; }

/* --- Numbered process steps ----------------------------------------------- */

.steps { counter-reset: step; }
.step {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 40px;
  padding: 38px 0;
  border-top: 1px solid var(--rule);
  align-items: start;
}
.section.dark .step { border-color: var(--black-line); }
.step:last-child { border-bottom: 1px solid var(--rule); }
.section.dark .step:last-child { border-bottom-color: var(--black-line); }
.step-no {
  font-family: var(--display);
  font-size: 2.6rem;
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--grey-200);
  transition: color .3s var(--ease);
}
.section.dark .step-no { color: var(--black-line); }
.step:hover .step-no { color: var(--yellow); }
.step h3 { margin-bottom: 10px; }
.step p { color: var(--muted); max-width: 68ch; margin-bottom: 0; }

/* --- Pricing -------------------------------------------------------------- */

/* Tiers stretch to a common height so the CTA buttons line up, regardless of
   how many features each list carries (.tier-list takes the slack via flex:1). */
.tiers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
}
.tier {
  border: 1px solid var(--rule);
  border-radius: var(--r);
  padding: 38px 32px 34px;
  background: var(--white);
  display: flex;
  flex-direction: column;
  height: 100%;
  transition: border-color .3s var(--ease), transform .3s var(--ease);
}
.tier:hover { border-color: var(--black); }

/* The pick of the three: ringed in yellow, with the glow thrown inward off
   the edges. */
.tier.featured {
  background: var(--black);
  border: 2px solid var(--yellow);
  color: var(--white);
  box-shadow: inset 0 0 60px rgba(255, 209, 0, .22);
}
.tier.featured h3 { color: var(--white); }
.tier.featured .tier-price { color: var(--yellow); }
.tier.featured .tier-list li { color: var(--grey-400); border-color: var(--black-line); }

.tier-flag {
  display: inline-block;
  align-self: flex-start;
  background: var(--yellow);
  color: var(--black);
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 6px 11px;
  border-radius: 2px;
  margin-bottom: 18px;
}
.tier h3 { font-size: 1.4rem; margin-bottom: 8px; }
.tier-note { font-size: .85rem; color: var(--muted); margin-bottom: 24px; }
.tier.featured .tier-note { color: var(--grey-400); }
.tier-price {
  font-family: var(--display);
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  margin-bottom: 4px;
}
.tier-price small {
  display: block;
  font-family: var(--sans);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
.tier.featured .tier-price small { color: var(--grey-400); }
.tier-dur {
  font-size: .8rem;
  color: var(--muted);
  padding-bottom: 26px;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 24px;
}
.tier.featured .tier-dur { color: var(--grey-400); border-color: var(--black-line); }

.tier-list { list-style: none; margin: 0 0 30px; padding: 0; flex: 1; }
.tier-list li {
  position: relative;
  padding: 11px 0 11px 28px;
  font-size: .92rem;
  color: var(--muted);
  border-bottom: 1px solid var(--rule);
}
.tier-list li:last-child { border-bottom: 0; }
.tier-list li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 19px;
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--black);
  border-bottom: 2px solid var(--black);
  transform: rotate(-45deg);
}
.tier.featured .tier-list li::before { border-color: var(--yellow); }

/* Add-on table */
.addons {
  width: 100%;
  border-collapse: collapse;
  margin-top: 12px;
}
.addons th, .addons td {
  text-align: left;
  padding: 17px 16px;
  border-bottom: 1px solid var(--rule);
  font-size: .95rem;
}
.addons th {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}
.addons td:last-child, .addons th:last-child { text-align: right; white-space: nowrap; }
.addons td:first-child { font-weight: 500; color: var(--ink); }
.addons td { color: var(--muted); }
.addons tbody tr { transition: background .2s var(--ease); }
.addons tbody tr:hover { background: var(--grey-50); }
.addons .price { font-family: var(--display); font-weight: 700; color: var(--ink); letter-spacing: -0.02em; }

/* Variant where the second column explains the add-on instead of pricing it —
   it has to wrap and sit left, unlike the right-aligned price column. */
.addons.notes td:last-child,
.addons.notes th:last-child { text-align: left; white-space: normal; }
.addons.notes td:first-child { width: 40%; }
.addons.notes td:last-child { font-size: .9rem; line-height: 1.5; }


/* --- Services page dark theme ------------------------------------------- */

.services-page {
  background: var(--charcoal);
  color: var(--grey-400);
}
.services-page main {
  background: var(--charcoal);
}
.services-page .page-hero { background: var(--charcoal); }
/* Carbon weave over the charcoal. Two 45-degree hatches running opposite ways,
   each a bright strand against a dark one, which is what gives the twill its
   direction. Held at 2-3% so it reads as a texture on the surface rather than
   as a pattern — anything stronger and it fights the artwork sitting on it. */
.services-page .section,
.services-page .section.grey,
.services-page .section.dark {
  background-color: var(--charcoal);
  background-image:
    repeating-linear-gradient(45deg,
      rgba(255, 255, 255, .028) 0 1px,
      rgba(0, 0, 0, .22) 1px 2px,
      transparent 2px 6px),
    repeating-linear-gradient(-45deg,
      rgba(255, 255, 255, .022) 0 1px,
      rgba(0, 0, 0, .18) 1px 2px,
      transparent 2px 6px);
  color: var(--grey-400);
}
.services-page main > .section + .section {
  border-top: 1px solid var(--black-line);
}

/* Light variant — a white sheet at the top of an otherwise dark page. Has to
   sit after the .services-page block above, which paints every hero charcoal at
   the same specificity and would otherwise win on order. */
.page-hero.light {
  background: var(--white);
  color: var(--ink);
  padding-bottom: 64px;
  border-bottom: 1px solid var(--rule);
}
.page-hero.light h1 { color: var(--ink); }
.page-hero.light .lead { color: var(--muted); }

.page-hero-grid {
  display: grid;
  grid-template-columns: 1.35fr .65fr;
  align-items: end;
  gap: clamp(30px, 5vw, 70px);
}

/* Three facts down the right, on hairlines — the detail that stops a white
   band being a blank one. */
.page-hero-facts {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule);
}
.page-hero-facts li {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 15px 0;
  border-bottom: 1px solid var(--rule);
}
.page-hero-facts strong {
  flex: none;
  min-width: 4.2ch;
  font-family: var(--display);
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.page-hero-facts span { font-size: .84rem; color: var(--muted); line-height: 1.4; }
.services-page .section h1,
.services-page .section h2,
.services-page .section h3 {
  color: var(--white);
}
.services-page .section p,
.services-page .lead,
.services-page .eyebrow {
  color: var(--grey-400);
}
.services-page .services-packages {
  padding-top: clamp(34px, 5vw, 64px);
}
.services-page .ticks li {
  color: var(--grey-400);
  border-color: var(--black-line);
}
.services-page .ticks li strong { color: var(--white); }
.services-page .addons th,
.services-page .addons td {
  border-color: var(--black-line);
}
.services-page .addons th,
.services-page .addons td { color: var(--grey-400); }
.services-page .addons td:first-child,
.services-page .addons .price { color: var(--white); }
.services-page .addons tbody tr:hover { background: var(--black-soft); }
.svc-disclaimer {
  margin-top: 30px;
  text-align: center;
  font-size: .86rem;
  color: var(--grey-400);
}


/* --- Services accordion --------------------------------------------------- */

/* Four rows, one per package. Closed by default; script.js measures the panel
   and animates its height so it glides rather than snapping. Everything here
   assumes the panel may be mid-transition, so nothing depends on a fixed size. */
.svc-accordion { margin-top: 8px; }
/* No rules between rows — the hover fill and the open panel do the separating. */
.svc-row + .svc-row { margin-top: 8px; }

.svc-row-head { margin: 0; font-size: inherit; letter-spacing: normal; }

.svc-toggle {
  display: grid;
  grid-template-columns: auto 1.1fr 1.6fr auto auto;
  align-items: center;
  gap: clamp(14px, 2.4vw, 32px);
  width: 100%;
  padding: clamp(20px, 2.4vw, 30px) 4px;
  border: 0;
  text-align: left;
  cursor: pointer;
  font-family: var(--sans);
  color: var(--white);
  border-radius: var(--r);
  /* A shallow crop of the same image used by the open panel previews each
     package while it is closed. The overlay keeps copy legible and adds only a
     restrained brand tint at the far-right edge. */
  background-color: var(--black);
  background-image:
    linear-gradient(90deg,
      rgba(11,11,12,.94) 0%,
      rgba(11,11,12,.86) 42%,
      rgba(11,11,12,.52) 70%,
      rgba(11,11,12,.16) 86%,
      rgba(255,209,0,.28) 100%),
    var(--svc-preview);
  background-size: 100% 100%, cover;
  background-position: center, center var(--svc-preview-y, 50%);
  background-repeat: no-repeat;
  transition: filter .25s var(--ease), padding-inline .25s var(--ease);
}
.svc-toggle:hover,
.svc-row.is-open .svc-toggle { filter: brightness(1.18); padding-inline: 16px; }
.svc-toggle:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--yellow-soft);
}

.svc-no {
  font-family: var(--sans);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .16em;
  color: var(--grey-600);
}
/* Block caps, white, big — the row's whole job is this word. */
.svc-name {
  font-family: var(--display);
  font-size: clamp(1.5rem, 2.9vw, 2.6rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--white);
}
.svc-flag {
  display: inline-block;
  margin-left: 8px;
  padding: 4px 9px;
  border-radius: 100px;
  background: var(--yellow);
  color: var(--black);
  font-family: var(--sans);
  font-size: .56rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  vertical-align: middle;
}
.svc-note { color: var(--grey-400); font-size: .92rem; max-width: 38ch; }
.svc-price {
  font-family: var(--display);
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.svc-price {
  color: var(--white);
  text-shadow: 0 1px 8px rgba(11,11,12,.72);
}
.svc-price i {
  font-style: normal;
  font-family: var(--sans);
  font-size: .72rem;
  font-weight: 500;
  color: rgba(255,255,255,.72);
}

/* Chevron. Rotates a half turn on open, in step with the panel. */
.svc-chev {
  position: relative;
  width: 34px;
  height: 34px;
  border: 1px solid rgba(255,255,255,.58);
  border-radius: 50%;
  background: rgba(11,11,12,.28);
  transition: transform .4s var(--ease);
}
.svc-chev::before,
.svc-chev::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 9px;
  height: 2px;
  background: var(--white);
  border-radius: 2px;
}
.svc-chev::before { left: 8px; transform: translateY(-50%) rotate(45deg); }
.svc-chev::after  { right: 8px; transform: translateY(-50%) rotate(-45deg); }
.svc-toggle[aria-expanded="true"] .svc-chev { transform: rotate(180deg); }

/* Height is driven from script.js; overflow is what makes the glide read. */
.svc-panel {
  height: 0;
  overflow: hidden;
  transition: height .45s var(--ease);
}
/* The photo is the card. Content sits on top of it, so the panel is a single
   positioned box and the figure fills it rather than sitting beside the copy. */
.svc-panel-inner {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: clamp(340px, 33vw, 480px);
  margin: 6px 0 10px;
  padding: clamp(26px, 3.2vw, 46px);
  border-radius: 10px;
  overflow: hidden;
  background: var(--black);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .3s var(--ease) .06s, transform .35s var(--ease) .06s;
}
.svc-row.is-open .svc-panel-inner { opacity: 1; transform: none; }

/* Name of the row repeated across the top of its open panel, in the same
   wordmark as the membership stripe, with a line of copy under it. The panel is
   a flex box that bottom-aligns its copy, so the pair is taken out of flow
   rather than fighting that. */
.svc-panel-head {
  position: absolute;
  z-index: 2;
  top: clamp(26px, 3.2vw, 46px);
  left: clamp(26px, 3.2vw, 46px);
  right: clamp(26px, 3.2vw, 46px);
}
.svc-panel-note {
  margin: 10px 0 0;
  max-width: 46ch;
  font-size: .95rem;
  line-height: 1.5;
  color: var(--white);
  text-shadow: 0 1px 10px rgba(11, 11, 12, .8);
}
.svc-panel-title {
  display: block;
  font-family: var(--display);
  font-size: clamp(1.6rem, 2.45vw, 2.35rem);
  font-weight: 700;
  line-height: .95;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--white);
}

/* Price in the opposite corner to the title, on the same inset as the padding
   so it lines up with the copy stack. Yellow rather than the row's white — this
   is the closing line of the panel, not a repeat of the header. */
.svc-panel-price {
  position: absolute;
  z-index: 2;
  right: clamp(26px, 3.2vw, 46px);
  bottom: clamp(26px, 3.2vw, 46px);
  font-family: var(--display);
  font-size: clamp(1.6rem, 2.45vw, 2.35rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
  white-space: nowrap;
  color: var(--yellow);
  text-shadow: 0 1px 10px rgba(11, 11, 12, .8);
}
.svc-panel-price i {
  font-style: normal;
  font-family: var(--sans);
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: 0;
  color: rgba(255, 255, 255, .72);
}

.svc-media {
  position: absolute;
  inset: 0;
  margin: 0;
  background: var(--black);
}
/* Pulls the exposure down so white copy holds over the paint. Weighted to the
   left, where the text is, and lighter on the right so the cars still read. */
.svc-media::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    /* Bottom-left is where the copy sits, so the weight goes there and the
       upper right stays open enough for the cars to actually read. */
    linear-gradient(100deg, rgba(11,11,12,.92) 0%, rgba(11,11,12,.68) 46%, rgba(11,11,12,.18) 100%),
    linear-gradient(0deg, rgba(11,11,12,.92) 0%, rgba(11,11,12,.50) 36%, rgba(11,11,12,0) 70%);
}
.svc-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Until a file lands, show the same hatched placeholder the gallery uses
   rather than a broken image icon. script.js adds .is-missing. */
.svc-media.is-missing img { display: none; }
.svc-media.is-missing::after {
  content: attr(data-label);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 20px;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--grey-600);
  background:
    repeating-linear-gradient(-45deg, var(--grey-100) 0 12px, var(--grey-50) 12px 24px);
}

.svc-panel-copy {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  color: var(--white);
}

.svc-list {
  list-style: none;
  margin: 0 0 22px;
  padding: 0;
}
.svc-list {
  columns: 2;
  column-gap: clamp(24px, 4vw, 60px);
}
.svc-list li {
  position: relative;
  padding: 7px 0 7px 24px;
  font-size: .93rem;
  color: rgba(255, 255, 255, .88);
  break-inside: avoid;
}
.svc-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 15px;
  width: 9px;
  height: 5px;
  border-left: 2px solid var(--yellow);
  border-bottom: 2px solid var(--yellow);
  transform: rotate(-45deg);
}
.svc-cta { flex: none; margin-top: auto; }

/* --- Gallery -------------------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 34px;
}
.filter {
  background: none;
  border: 1px solid var(--rule);
  border-radius: 100px;
  padding: 10px 20px;
  font-family: var(--sans);
  font-size: .76rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  cursor: pointer;
  transition: all .25s var(--ease);
}
.filter:hover { border-color: var(--black); color: var(--black); }
.filter.active { background: var(--black); border-color: var(--black); color: var(--white); }

.tiles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
.tile {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--grey-100);
}
.tile.wide { grid-column: span 2; aspect-ratio: 8 / 3; }
.tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s var(--ease);
}
.tile:hover img { transform: scale(1.045); }

.tile figcaption {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  padding: 20px;
  background: linear-gradient(transparent, rgba(11,11,12,.85));
  color: var(--white);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.tile:hover figcaption { opacity: 1; transform: none; }

/* Placeholder shown until real photography is dropped into assets/gallery/.
   script.js adds .is-missing to the figure when the image fails to load. */
.tile.is-missing img { display: none; }
.tile.is-missing::after {
  content: attr(data-label);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 20px;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--grey-600);
  background:
    repeating-linear-gradient(-45deg, var(--grey-100) 0 12px, var(--grey-50) 12px 24px);
}
.tile.is-missing figcaption { display: none; }
.tile.is-hidden { display: none; }

/* --- Before / after comparison -------------------------------------------- */

.compare {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--grey-100);
  touch-action: pan-y;
  cursor: ew-resize;
  user-select: none;
}
.compare img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The "after" layer is anchored to the RIGHT edge and clipped, so the handle
   reads as a wipe: before to its left, after to its right. Its width is the
   inverse of the handle position. The image inside is pinned right and sized to
   the full widget (--w, set in script.js) so it stays registered with the
   "before" layer underneath. */
.compare .after-wrap {
  position: absolute;
  inset: 0 0 0 auto;
  width: 50%;
  overflow: hidden;
  will-change: width;
}
.compare .after-wrap img {
  position: absolute;
  top: 0; right: 0;
  width: var(--w, 100%);
  height: 100%;
  max-width: none;
}

.compare-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  background: var(--yellow);
  transform: translateX(-1px);
  z-index: 3;
  will-change: left;
}
.compare-handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 46px;
  height: 46px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--yellow);
  box-shadow: 0 4px 20px rgba(0,0,0,.3);
}
.compare-handle i {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  font-style: normal;
  font-size: .9rem;
  font-weight: 700;
  color: var(--black);
  letter-spacing: 1px;
  white-space: nowrap;
}

.compare-tag {
  position: absolute;
  top: 16px;
  z-index: 2;
  background: rgba(11,11,12,.72);
  color: var(--white);
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 7px 12px;
  border-radius: 2px;
}
.compare-tag.l { left: 16px; }
.compare-tag.r { right: 16px; }

/* Placeholder halves when no photography is present yet */
.compare.is-missing img { display: none; }
/* The .compare-tag chips already label the two halves, so the placeholder is
   hatch only — a centred caption would sit under the drag knob. */
.compare.is-missing::before,
.compare.is-missing .after-wrap::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(-45deg, var(--grey-200) 0 12px, var(--grey-100) 12px 24px);
}
/* Dirty half dark, clean half light */
.compare.is-missing::before {
  background: repeating-linear-gradient(-45deg, #2A2C2F 0 12px, #17181A 12px 24px);
}
.compare.is-missing .after-wrap::before {
  inset: 0 0 0 auto;
  width: var(--w, 100%);
}

/* --- Testimonials --------------------------------------------------------- */

.quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.quote {
  border: 1px solid var(--black-line);
  border-radius: var(--r);
  padding: 34px 30px;
  display: flex;
  flex-direction: column;
}
.section:not(.dark) .quote { border-color: var(--rule); }
.stars { display: flex; gap: 3px; color: var(--yellow); margin-bottom: 20px; }
.stars svg { width: 15px; height: 15px; fill: currentColor; stroke: none; }
.quote blockquote {
  margin: 0 0 26px;
  font-size: 1.02rem;
  line-height: 1.6;
  flex: 1;
}
.section.dark .quote blockquote { color: var(--white); }
.quote cite {
  font-style: normal;
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .06em;
}
.quote cite span {
  display: block;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-size: .68rem;
  color: var(--muted);
  margin-top: 5px;
}
.section.dark .quote cite span { color: var(--grey-600); }

/* --- FAQ ------------------------------------------------------------------ */

.faq { border-top: 1px solid var(--rule); }
.faq details {
  border-bottom: 1px solid var(--rule);
}
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 26px 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: 1.12rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  transition: color .25s var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--muted); }
.faq summary::after {
  content: "";
  flex: none;
  width: 13px;
  height: 13px;
  border-right: 2px solid var(--yellow);
  border-bottom: 2px solid var(--yellow);
  transform: rotate(45deg) translateY(-3px);
  transition: transform .3s var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg) translateY(-3px); }
.faq .answer { padding: 0 60px 28px 0; color: var(--muted); max-width: 78ch; }

/* --- Feature list (ticks) ------------------------------------------------- */

.ticks { list-style: none; margin: 0; padding: 0; }
.ticks li {
  position: relative;
  padding: 13px 0 13px 34px;
  border-bottom: 1px solid var(--rule);
  color: var(--muted);
  font-size: .96rem;
}
.section.dark .ticks li { border-color: var(--black-line); }
.ticks li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 21px;
  width: 12px;
  height: 7px;
  border-left: 2px solid var(--yellow);
  border-bottom: 2px solid var(--yellow);
  transform: rotate(-45deg);
}
.ticks li strong { color: var(--ink); font-weight: 600; }
.section.dark .ticks li strong { color: var(--white); }

/* --- Suburb chips --------------------------------------------------------- */

.chips { display: flex; flex-wrap: wrap; gap: 9px; }
.chips span {
  border: 1px solid var(--rule);
  border-radius: 100px;
  padding: 8px 17px;
  font-size: .8rem;
  color: var(--muted);
}
.section.dark .chips span { border-color: var(--black-line); color: var(--grey-400); }

/* --- CTA band ------------------------------------------------------------- */

.cta-band {
  background: var(--yellow);
  color: var(--black);
  padding: clamp(58px, 7vw, 88px) 0;
}
.cta-band .inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  flex-wrap: wrap;
}
.cta-band h2 { margin-bottom: 10px; max-width: 20ch; }
.cta-band p { margin: 0; font-weight: 500; max-width: 46ch; }
.cta-band .btn-black:hover { background: var(--white); color: var(--black); }

/* --- Forms ---------------------------------------------------------------- */

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}
.field { display: flex; flex-direction: column; }
.field.full { grid-column: 1 / -1; }
.field label {
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 9px;
}
.field input,
.field select,
.field textarea {
  font-family: var(--sans);
  font-size: .97rem;
  color: var(--ink);
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: var(--r);
  padding: 15px 16px;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
  width: 100%;
}
.field textarea { resize: vertical; min-height: 132px; }

/* Add-ons: two ticked columns inside one field. .field label is built for a
   stacked text input, so the option labels undo most of it. */
.field-heading {
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 9px;
}
/* The frame lives on the <details> so it wraps the summary row too. */
.addon-details {
  border: 1px solid var(--rule);
  border-radius: var(--r);
}
.addon-details summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 15px 18px;
  list-style: none;
  cursor: pointer;
}
.addon-details summary::-webkit-details-marker { display: none; }
.addon-details summary .field-heading { margin-bottom: 0; }
.addon-details summary em {
  font-style: normal;
  letter-spacing: .1em;
  color: var(--grey-400);
}
.addon-details[open] summary { border-bottom: 1px solid var(--rule); }
.addon-count {
  font-size: .84rem;
  color: var(--muted);
}
/* Rotates a quarter turn on open, like the accordions elsewhere. */
.addon-count::after {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: 11px;
  vertical-align: 1px;
  border-right: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  transform: rotate(45deg);
  transition: transform .25s var(--ease);
}
.addon-details[open] .addon-count::after { transform: rotate(-135deg); }

.addon-picker {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px 30px;
  padding: 20px 22px;
}
.addon-col-head {
  display: block;
  margin-bottom: 10px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--rule);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink);
}
.field .addon-opt {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 11px;
  margin: 0 0 9px;
  font-size: .9rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.45;
  text-transform: none;
  color: var(--muted);
  cursor: pointer;
}
.field .addon-opt:last-child { margin-bottom: 0; }
.field .addon-opt input[type="checkbox"] {
  width: 17px;
  height: 17px;
  margin-top: 1px;
  padding: 0;
  border: 0;
  background: none;
  accent-color: var(--black);
  cursor: pointer;
}

/* Day-of requirements, ticked before the calendar will load. Both the label and
   the input rules above are built for a stacked text field, so most of this is
   undoing them for a checkbox sitting inline with its copy. */
.field label.agree {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 14px;
  margin-bottom: 0;
  padding: 20px 22px;
  background: var(--grey-50);
  border-left: 3px solid var(--yellow);
  border-radius: var(--r);
  cursor: pointer;
  font-size: .92rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.6;
  text-transform: none;
  color: var(--muted);
}
.field .agree input[type="checkbox"] {
  width: 20px;
  height: 20px;
  margin-top: 2px;
  padding: 0;
  border: 0;
  background: none;
  /* Black box, white tick — white on yellow would not hold up. */
  accent-color: var(--black);
  cursor: pointer;
}
.field .agree strong {
  display: block;
  margin-bottom: 5px;
  font-family: var(--display);
  font-size: 1rem;
  letter-spacing: -.01em;
  color: var(--ink);
}
.field select { appearance: none; cursor: pointer; background-image: none; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--black);
  box-shadow: 0 0 0 3px var(--yellow-soft);
}
.field .hint { font-size: .78rem; color: var(--grey-600); margin-top: 8px; }

/* Stop the submit button stretching to the column width */
.field > .btn { align-self: flex-start; }

.form-note { font-size: .82rem; color: var(--grey-600); margin-top: 18px; }

.form-success {
  display: none;
  background: var(--yellow-soft);
  border-left: 3px solid var(--yellow);
  border-radius: var(--r);
  padding: 20px 22px;
  margin-bottom: 26px;
  font-size: .95rem;
}

/* --- Booking calendar ----------------------------------------------------- */

/* Calendly renders into here. It sets its own height once resize:true kicks in;
   the min-height stops the page collapsing while widget.js is still loading. */
.booking-embed {
  min-width: 320px;
  /* Calendly centres a fixed-width widget inside whatever it's given, so an
     unconstrained frame leaves a wide white margin either side of it. */
  max-width: 820px;
  margin-inline: auto;
  /* Compact while it's just the prompt; the calendar claims the height it needs
     once mounted, and .is-live stops the frame collapsing mid-load. */
  min-height: 220px;
  border: 1px solid var(--rule);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--white);
  display: grid;
  place-items: center;
}
/* Calendly draws its own bordered card, so ours would double up — the frame is
   only there to hold the shape while the placeholder prompt is showing. */
.booking-embed.is-live {
  min-height: 680px;
  border-color: transparent;
  background: transparent;
}
/* The widget wants the full width; the hint sits centred in the empty frame. */
.booking-embed > div { width: 100%; }
.booking-embed-hint {
  margin: 0;
  padding: 0 32px;
  max-width: 44ch;
  text-align: center;
  color: var(--muted);
  font-size: .95rem;
}

/* A button that reads as a link, for the quote escape hatch inside a sentence. */
.link-inline {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--yellow);
  text-decoration-thickness: 2px;
}
.link-inline:hover { text-decoration-color: var(--black); }
.link-inline:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--yellow-soft);
  border-radius: 2px;
}

/* Contact detail rows */
.contact-list { list-style: none; margin: 0; padding: 0; }
.contact-list li {
  padding: 22px 0;
  border-bottom: 1px solid var(--rule);
}
.contact-list li:first-child { border-top: 1px solid var(--rule); }
.contact-list strong {
  display: block;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 7px;
}
.contact-list a,
.contact-list li > span { font-size: 1.06rem; font-weight: 500; line-height: 1.45; }
.contact-list a { transition: color .25s var(--ease); }
.contact-list a:hover { color: var(--muted); }

/* --- Footer --------------------------------------------------------------- */

.site-footer {
  background: var(--black);
  color: var(--grey-400);
  padding: 78px 0 34px;
  font-size: .9rem;
}
.footer-top {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr;
  gap: 44px;
  padding-bottom: 54px;
  border-bottom: 1px solid var(--black-line);
}
.site-footer .brand { color: var(--white); margin-bottom: 18px; }
.site-footer h4 {
  color: var(--white);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  margin-bottom: 18px;
  font-family: var(--sans);
}
.footer-links { list-style: none; margin: 0; padding: 0; }
.footer-links li { margin-bottom: 11px; }
.footer-links a { transition: color .25s var(--ease); }
.footer-links a:hover { color: var(--yellow); }

.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  padding-top: 28px;
  font-size: .8rem;
  color: var(--grey-600);
}
.footer-bottom a:hover { color: var(--yellow); }

/* --- Sticky booking bar --------------------------------------------------- */

/* Only shown at <=900px. Above that the header CTA is always on screen, so a
   second permanent CTA is just clutter. Hidden until the visitor scrolls, so it
   never sits on top of the hero copy. */
.book-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 70;
  display: none;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 17px var(--gutter);
  padding-bottom: calc(17px + env(safe-area-inset-bottom, 0px));
  background: var(--yellow);
  color: var(--black);
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  box-shadow: 0 -6px 22px rgba(11, 11, 12, .16);
  transform: translateY(100%);
  visibility: hidden;
  transition: transform .32s var(--ease), visibility .32s var(--ease);
}
.book-bar.show { transform: none; visibility: visible; }
.book-bar .arw { transition: transform .25s var(--ease); }
.book-bar:active .arw { transform: translateX(4px); }

@media (max-width: 900px) {
  .book-bar { display: flex; }
  /* Keep the last of the footer clear of the bar */
  .site-footer { padding-bottom: 104px; }
}

@media (prefers-reduced-motion: reduce) {
  .book-bar { transition: none; }
}

/* --- Reveal on scroll ----------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}

/* --- Responsive ----------------------------------------------------------- */

@media (max-width: 1080px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .service-posters { grid-template-columns: repeat(2, 1fr); }
  .service-poster { min-height: 330px; }
  .footer-top { grid-template-columns: 1fr 1fr; gap: 34px; }
}

/* Phones: the three cards become a swipeable carousel of full vertical cards.
   They bleed to the viewport edges and sit at 78% width so the next one peeks,
   which is the affordance that says "swipe" without needing arrows. */
@media (max-width: 700px) {
  .service-posters {
    display: flex;
    grid-template-columns: none;
    gap: 12px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-left: var(--gutter);
    /* Break out of .container so cards can run to the screen edge */
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    padding-block-end: 4px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .service-posters::-webkit-scrollbar { display: none; }

  .service-poster {
    flex: 0 0 78%;
    scroll-snap-align: start;
    min-height: 430px;
    padding: 20px;
  }
  /* Cards 2 and 3 start off-screen to the right, so the scroll reveal would
     never fire for them and they would swipe in blank. */
  .service-poster.reveal { opacity: 1; transform: none; transition: none; }
  .service-poster h3,
  .member-stripe-label { font-size: 1.45rem; }
  .service-poster-body p { font-size: .82rem; }
  .service-poster-list li { font-size: .8rem; padding: 5px 0 5px 18px; }
  .service-poster-list li::before { top: 12px; }
  .services-note { margin-top: 22px; font-size: .78rem; }
}

@media (max-width: 900px) {
  :root { --header-h: 68px; }

  .nav-links {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--charcoal);
    border-bottom: 1px solid var(--charcoal-line);
    padding: 10px var(--gutter) 26px;
    color: var(--white);
    display: none;
  }
  .nav-links.open { display: flex; }
  .nav-links > a {
    padding: 15px 0;
    border-bottom: 1px solid var(--charcoal-line);
    font-size: 1rem;
  }
  .nav-links > a:not(.btn)::after { display: none; }
  .nav-cta,
  .site-header.over-hero .nav-cta {
    margin-top: 20px;
    border: 0;
    background: var(--yellow);
    color: var(--black);
    padding: 16px 22px;
    font-size: .78rem;
  }
  .nav-toggle { display: flex; }
  .site-header .brand { width: 158px; height: 52px; }

  .home-heading { grid-template-columns: 1fr; row-gap: 18px; }
  .home-heading > p { max-width: 52ch; }
  .instagram-head { align-items: flex-start; flex-direction: column; }
  .proof-grid { grid-template-columns: repeat(2, 1fr); }
  .proof-grid div:nth-child(2) { border-right: 0; }
  .proof-grid div:nth-child(-n+2) { border-bottom: 1px solid var(--rule); }
  .home-tiers .tier.featured { transform: none; }

  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .split, .split.even, .split.wide-left { grid-template-columns: 1fr; }
  .split-sticky { position: static; }
  .tiers { grid-template-columns: 1fr; }
  .quotes { grid-template-columns: 1fr; }
  .tiles { grid-template-columns: repeat(2, 1fr); }
  .tile.wide { grid-column: span 2; aspect-ratio: 16 / 9; }
  .head-row { flex-direction: column; align-items: flex-start; }
  .step { grid-template-columns: 1fr; gap: 14px; }
  .form-grid { grid-template-columns: 1fr; }
  .addon-picker { grid-template-columns: 1fr; gap: 20px; }
  .page-hero-grid { grid-template-columns: 1fr; gap: 30px; }
  .page-hero.light { padding-bottom: 44px; }
  /* The row collapses to name + price, with the note tucked under the name. */
  .svc-toggle {
    grid-template-columns: 1fr auto auto;
    gap: 12px 14px;
    padding-block: 20px;
  }
  .svc-no { display: none; }
  .svc-note { grid-column: 1 / 2; font-size: .84rem; max-width: none; }
  /* On smaller rows the image remains visible, with an even dark wash because
     the price returns to white and the chevron carries the yellow on its own. */
  .svc-toggle {
    background-image:
      linear-gradient(90deg, rgba(11,11,12,.9) 0%, rgba(11,11,12,.76) 58%, rgba(11,11,12,.58) 100%),
      var(--svc-preview);
  }
  .svc-price { color: var(--white); }
  .svc-price i { color: var(--grey-400); }
  .svc-chev { background: var(--yellow); border-color: var(--yellow); }
  .svc-chev::before,
  .svc-chev::after { background: var(--black); }
  /* The title, note and price are pinned to the panel's corners on desktop,
     where the photo is wide enough to hold copy in one corner and a price in
     another. On a phone the list stacks into one column and fills the box, so
     pinned corners land straight on top of it — the title printing over the
     first two list items. They come back into flow here and the panel reads as
     a plain stack: name, line of copy, price, what's included, then the button.
     Relative rather than static so the z-index still lifts them off the photo. */
  .svc-panel-inner { min-height: 0; padding: 22px; display: block; }
  .svc-panel-head {
    position: relative;
    top: auto;
    left: auto;
    right: auto;
    margin-bottom: 14px;
  }
  .svc-panel-price {
    position: relative;
    right: auto;
    bottom: auto;
    display: block;
    margin: 0 0 18px;
  }
  .svc-list { columns: 1; }
  .svc-cta { width: 100%; text-align: center; }
  .booking-embed.is-live { min-height: 1000px; }
  .faq .answer { padding-right: 0; }
}

@media (max-width: 560px) {
  body { font-size: 16px; }
  .tiles { grid-template-columns: 1fr; }
  .tile.wide { grid-column: span 1; }
  /* Hero stops short of the full screen so the services panel is already peeking
     when the page loads — it is the thing that rides up over the hero, so it has
     to advertise itself. The rest of the height goes to the car, which runs as
     big as the wordmark above it and the copy below it allow; the trust row goes
     and the support line tightens to buy it that room. */
  /* Capped as well as proportional: past ~37rem the extra height only opens a
     gap between the car and the copy, since the car is pinned to the wordmark
     and the copy to the floor. */
  .hero { min-height: min(78svh, 37rem); padding-top: var(--header-h); }
  .hero-wordmark { font-size: clamp(3.2rem, 15.5vw, 4.4rem); }
  /* Same composition as the desktop hero, scaled to the phone: the wordmark, the
     centred car below it, and the crew either side. Only the numbers change —
     the car runs wider against the viewport, the crew a touch bigger against the
     car, and every offset re-solves off --hero-h.

     The overlap goes negative down here. At this size the wordmark is small
     enough that a roofline tucked into its base covers the letters rather than
     grazing them, so the car drops clear of it into the space below. */
  .hero-stage {
    --hero-h: min(78svh, 37rem);
    --car-w: min(92vw, 400px);
    --car-overlap: -26px;
    --wordmark-top: clamp(1.5rem, 5vh, 3rem);
    --wordmark-h: calc(.78 * clamp(3.2rem, 15.5vw, 4.4rem));
    --dude-w: calc(var(--car-w) * .3);
    --car-bottom-cap: 26rem;
  }
  /* Pulled in from the desktop anchors so both stay inside a narrow viewport. */
  .hero-dude-dry { left: calc(50% - .5 * var(--car-w)); }
  .hero-dude-spray { right: calc(50% - .58 * var(--car-w)); }
  .hero-shines span { --shine-size: 19px; }
  .hero-shines span::before { width: 3px; }
  .hero-shines span::after { height: 3px; }
  .hero-shines span:nth-child(1) { left: 2%; top: 20%; --shine-size: 29px; }
  .hero-shines span:nth-child(2) { left: 21%; top: 58%; --shine-size: 18px; }
  .hero-shines span:nth-child(3) { left: 35%; top: -4%; --shine-size: 23px; }
  .hero-shines span:nth-child(4) { left: auto; right: 42%; top: 42%; --shine-size: 18px; }
  .hero-shines span:nth-child(5) { left: auto; right: 23%; top: 62%; --shine-size: 25px; }
  .hero-shines span:nth-child(6) { left: auto; right: 4%; top: 13%; --shine-size: 28px; }
  .hero-shines span:nth-child(7) { right: 12%; top: -5%; --shine-size: 17px; }
  .hero-shines span:nth-child(n+8) { display: none; }
  .hero-copy { inset: auto var(--gutter) clamp(1.1rem, 2.6vh, 1.8rem); }
  .hero-subtitle { font-size: 1.16rem !important; margin-top: 0 !important; }
  .hero-support {
    font-size: .88rem;
    line-height: 1.5;
    max-width: 40ch;
    margin-top: 7px !important;
  }
  .hero-trust { display: none; }
  .hero-copy .hero-cta { margin-top: 12px; padding: 13px 28px; }

  /* Lower third: heading pared back so the cards themselves get the space. */
  /* Same artwork and glow as desktop. The stack is inherited rather than
     restated; only the crop is steered, so the car keeps its place on the right
     instead of the frame filling with bodywork at this width. */
  .member-stripe {
    padding: 22px 20px;
    background-size: auto 132%;
    background-position: right 62%;
    /* Same artwork and glow, but the copy runs the full width here rather than
       stopping at 56%, so the dark layer has to carry across the whole frame
       instead of clearing by two thirds. */
    background-image:
      /* Stacked layout puts the small grey copy where the glow falls, and the
         glow is the top layer so darkening under it changes nothing. Held to
         the top third, behind the wordmark, which is large enough to carry it. */
      linear-gradient(180deg, rgba(255,209,0,.44) 0%, rgba(255,209,0,.12) 17%, rgba(255,209,0,0) 32%),
      linear-gradient(90deg, rgba(11,11,12,.97) 0%, rgba(11,11,12,.93) 46%, rgba(11,11,12,.82) 100%),
      url('assets/membership.webp');
  }
  .member-stripe-inner {
    max-width: none;
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }
  .member-stripe .arw { display: none; }

  .home-services { padding-top: 26px; }
  .home-services .section-head { margin-bottom: 18px; }
  .home-services .section-head p { display: none; }
  .home-services .section-head h2 { font-size: 1.85rem; margin-bottom: 0; }
  .home-services .eyebrow { margin-bottom: 12px; }
  .service-poster h3,
  .member-stripe-label { font-size: 1.3rem; }
  .instagram-shell { padding: 34px 20px 22px; }
  .instagram-head { margin-bottom: 24px; }
  .instagram-head .btn { width: 100%; }
  .instagram-actions { width: 100%; }
  .instagram-grid {
    display: flex;
    overflow-x: auto;
    gap: 10px;
    margin-right: -20px;
    padding-right: 20px;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  .instagram-grid::-webkit-scrollbar { display: none; }
  .instagram-post { flex: 0 0 78vw; scroll-snap-align: start; }
  .proof-section { padding: 0 12px; }
  .proof-grid div { padding: 30px 12px; }
  .btn { width: 100%; }
  .footer-top { grid-template-columns: 1fr; }
  .addons th:first-child, .addons td:first-child { width: 60%; }
}

/* Small phones. The hero is a fixed budget — wordmark, car, copy — and down here
   the subtitle wraps to two lines and eats the car's clearance, so the headline
   comes down a notch to hold one line and the car gives back a little width. */
@media (max-width: 380px) {
  .hero-stage { --car-w: min(88vw, 320px); }
  .hero-subtitle { font-size: 1.04rem !important; }
  .hero-support { font-size: .84rem; }
}

/* ==========================================================================
   INTRO CURTAIN — home page only
   Charcoal screen, the logo sitting on it dull, then a sponge sweeps across
   and wipes it clean. Curtain fades and the hero plays behind it.

   The head script in index.html decides whether it runs (skipped under
   reduced-motion and after the first load of a session) by putting
   .is-preloading on <html> before first paint; script.js starts the sequence
   with .is-preload-run once the artwork has decoded, and clears both at the
   end. With JS off, .preloader never leaves display:none.
   ========================================================================== */

.preloader { display: none; }

html.is-preloading,
html.is-preloading body { overflow: hidden; }

/* Hero entrance animations hold their first frame until the curtain lifts,
   so the wordmark and car play into a visible page rather than behind it. */
html.is-preloading .hero-wordmark-text,
html.is-preloading .hero-car,
html.is-preloading .hero-car-shadow,
html.is-preloading .hero-dude,
html.is-preloading .hero-copy,
html.is-preloading .hero-shines span { animation-play-state: paused; }

html.is-preloading .preloader {
  display: grid;
  position: fixed;
  inset: 0;
  z-index: 999;
  place-items: center;
  background: radial-gradient(118% 88% at 50% 46%, #1A1D21 0%, var(--charcoal) 64%);
  animation: preOut .45s 1.95s var(--ease) forwards;
}

/* Nothing moves until the sponge and the logo are decoded — otherwise the
   sweep can play against an empty screen on a cold cache. */
html.is-preloading:not(.is-preload-run) .preloader,
html.is-preloading:not(.is-preload-run) .preloader * { animation-play-state: paused; }

.pre-stage {
  --logo-w: min(74vw, 560px);
  position: relative;
  width: var(--logo-w);
  animation: preStageOut .45s 1.95s var(--ease) forwards;
}

.pre-logo {
  position: relative;
  width: 100%;
  opacity: 0;
  transform: scale(.985);
  animation: preLogoIn .45s .1s var(--ease) forwards;
}

/* Dull layer — the logo before the sponge gets to it. */
.pre-logo-dull {
  width: 100%;
  height: auto;
  opacity: .3;
  filter: grayscale(1) brightness(.62) blur(.6px);
}

/* Clean layer, revealed left to right in step with the sponge. Same keyframe
   stops as preSponge at the same duration, so the wipe edge tracks the middle
   of the sponge the whole way across. */
.pre-logo-clean {
  position: absolute;
  inset: 0;
  background: url("assets/showroomfx-logo.webp") center / 100% 100% no-repeat;
  clip-path: inset(0 100% 0 0);
  animation: preWipe 1s .5s linear forwards;
}

/* Wet trail. Anchored to the right edge of the clean layer, so the wipe edge
   clips it by construction — no timing of its own beyond fading out as the
   sweep finishes and there is nothing left to clip it. */
.pre-wet {
  position: absolute;
  top: 6%;
  right: -3%;
  bottom: 6%;
  width: 24%;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, .08) 40%,
    rgba(255, 209, 0, .20) 74%,
    rgba(255, 255, 255, .26) 92%,
    rgba(255, 255, 255, 0) 100%);
  filter: blur(8px);
  mix-blend-mode: screen;
  animation: preWet 1s .5s linear forwards;
}

/* Chrome flash across the finished logo, masked to its own artwork. */
.pre-gleam {
  position: absolute;
  inset: 0;
  opacity: 0;
  background: linear-gradient(104deg,
    rgba(255, 255, 255, 0) 42%,
    rgba(255, 255, 255, .8) 50%,
    rgba(255, 255, 255, 0) 58%) 140% 0 / 260% 100% no-repeat;
  -webkit-mask: url("assets/showroomfx-logo.webp") center / 100% 100% no-repeat;
  mask: url("assets/showroomfx-logo.webp") center / 100% 100% no-repeat;
  animation: preGleam .6s 1.45s ease-out forwards;
}

.pre-sponge {
  position: absolute;
  top: 50%;
  left: 0;
  width: calc(var(--logo-w) * .42);
  height: auto;
  /* Half the sponge width, so translateX positions its centre. */
  margin-left: calc(var(--logo-w) * -.21);
  transform: translate3d(calc(var(--logo-w) * -.22), -50%, 0);
  filter: drop-shadow(0 18px 26px rgba(0, 0, 0, .55));
  animation: preSponge 1s .5s linear forwards;
  will-change: transform;
}

@keyframes preLogoIn {
  to { opacity: 1; transform: none; }
}

/* Centre of the sponge, in multiples of the logo width. Past 85% it is clear of
   the artwork, so the last stop is a flick off screen rather than a sync point. */
@keyframes preSponge {
  0%   { opacity: 1; transform: translate3d(calc(var(--logo-w) * -.22), -46%, 0) rotate(-13deg) scale(1); }
  15%  { transform: translate3d(calc(var(--logo-w) * -.05), -54%, 0) rotate(-7deg) scale(1.03); }
  35%  { transform: translate3d(calc(var(--logo-w) *  .26), -44%, 0) rotate(2deg) scale(.99); }
  55%  { transform: translate3d(calc(var(--logo-w) *  .58), -55%, 0) rotate(8deg) scale(1.03); }
  75%  { transform: translate3d(calc(var(--logo-w) *  .86), -45%, 0) rotate(3deg) scale(1); }
  85%  { opacity: 1; transform: translate3d(calc(var(--logo-w) * 1.02), -52%, 0) rotate(9deg) scale(1.01); }
  100% { opacity: 0; transform: translate3d(calc(var(--logo-w) * 1.62), -44%, 0) rotate(18deg) scale(.97); }
}

/* The inverse of the line above: right inset = 100% - sponge centre. */
@keyframes preWipe {
  0%   { clip-path: inset(0 100% 0 0); }
  15%  { clip-path: inset(0 100% 0 0); }
  35%  { clip-path: inset(0 74% 0 0); }
  55%  { clip-path: inset(0 42% 0 0); }
  75%  { clip-path: inset(0 14% 0 0); }
  85%  { clip-path: inset(0 0 0 0); }
  100% { clip-path: inset(0 0 0 0); }
}

/* Gone by the time the wipe edge stops clipping it. */
@keyframes preWet {
  0%, 62% { opacity: 1; }
  86%, 100% { opacity: 0; }
}

@keyframes preGleam {
  0%   { opacity: 0;  background-position: 140% 0; }
  35%  { opacity: .95; }
  100% { opacity: 0;  background-position: 0% 0; }
}

@keyframes preStageOut {
  to { opacity: 0; transform: scale(1.045); }
}

@keyframes preOut {
  to { opacity: 0; visibility: hidden; }
}

@media (max-width: 560px) {
  .pre-stage { --logo-w: min(82vw, 420px); }
}
