/* ===========================================================================
   SUPERIOR SHINE — DESIGN SYSTEM
   ---------------------------------------------------------------------------
   The brief: "modern metallic and black shiny style, replicate his logo".

   Every colour here was SAMPLED from his logo file, not guessed:

     ground      #000000   pure black, the logo sits on it
     chrome      #C2C2C2   mid-tone of the S and the SUPERIOR wordmark
     gold        #957042   mid-tone of the SHINE wordmark
     gold light  #CBB593   the four-point star

   ── CONTRAST, WHICH FOR ONCE IS EASY ──────────────────────────────────
   On black: chrome reads 13:1, gold 8.7:1, muted grey 6.6:1. Every one of
   those clears AA comfortably, so unlike a pale brand there is no tension
   here between looking right and being readable. The only real risk on a
   dark site is thin light text on a photograph, so any text over an image
   gets a scrim underneath it rather than relying on the photo staying dark.

   ── HOW "CHROME" IS ACTUALLY DONE ─────────────────────────────────────
   Not with an image, and not with a flat grey. Real chrome lettering is a
   vertical gradient with a hard tonal flip near the middle — light at the
   top, dropping fast to a dark band at the horizon line, then bouncing back
   up. That flip is what the eye reads as polished metal. It is one
   background-image plus background-clip: text, so it stays live text: it
   scales, it wraps, it is selectable, and a screen reader reads it normally.

   `color` is always set as well, so if background-clip: text is unsupported
   the headline is still legible chrome-grey rather than invisible.

   ── WHY IT LOOKS NOTHING LIKE DURHAM CLEAN ────────────────────────────
   Same author, same month, and the two owners are married — these will be
   seen side by side. Durham Clean is cream paper, a high-contrast serif,
   hairline rules and editorial restraint. This is its opposite on purpose:
   black ground, wide tracked-out sans caps, gradients, gloss, and
   photography running full width. Nothing is shared but the care.
   ======================================================================== */

:root {
  /* --- Ground ------------------------------------------------------------
     Not one flat black. A near-black page with slightly lifted panels is
     what stops a dark site reading as a void — you need a little tonal
     separation or every section melts into the next. */
  --black: #000000;         /* the logo's own ground, used at the extremes */
  --pit: #050607;           /* page background */
  --panel: #0B0D0F;         /* raised sections */
  --panel-2: #121519;       /* cards, form fields */
  --hair: #1E2328;          /* borders */
  --hair-lit: #2C3238;      /* borders that need to be seen */

  /* --- Chrome ------------------------------------------------------------ */
  --chrome: #C2C2C2;        /* 13.0:1 on black — sampled from the S */
  --chrome-hi: #F4F6F8;
  --chrome-lo: #6E7378;
  --steel: #8A9199;         /*  6.6:1 — secondary text */
  --steel-dim: #6B7278;     /*  4.6:1 — smallest print only */

  /* --- Gold -------------------------------------------------------------- */
  --gold: #C9A227;          /*  8.7:1 — readable gold for text */
  --gold-hi: #E8CE7A;
  --gold-lo: #7A5C1E;
  --gold-logo: #957042;     /* the exact mid-tone off the wordmark */

  /* --- State ------------------------------------------------------------- */
  --good: #3FBF7F;
  --bad: #FF6B5A;

  /* --- Type ---------------------------------------------------------------
     Archivo is a wide grotesque with flat terminals — the closest thing on
     Google Fonts to the geometry of his wordmark. Inter carries the body.
     No serif anywhere: a serif is the one thing that would drag this back
     towards the other site. */
  --display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --body: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;

  --r: 2px;
  --r-field: 6px;

  --gutter: 1.25rem;
  --ease: cubic-bezier(.22, 1, .36, 1);
  /* Almost-linear, for the long slow moves — a hero that drifts on an
     ease-out visibly slows down and draws attention to itself. */
  --ease-drift: cubic-bezier(.33, .1, .5, .9);

  /* The gradient that does all the work. Light → hard dark band → light. */
  --chrome-grad: linear-gradient(
    180deg,
    #FFFFFF 0%, #DDE1E5 18%, #9DA4AA 42%,
    #43484D 50%, #6E7378 54%,
    #C9CFD4 74%, #FFFFFF 100%);
  --gold-grad: linear-gradient(
    180deg,
    #F6E6B4 0%, #E8CE7A 20%, #C9A227 44%,
    #6E4F14 51%, #A9821F 57%,
    #E3C15A 78%, #FBF1D2 100%);

  /* The moving highlight. Metal only looks like metal when the light on it
     moves — a static gradient is a picture of chrome, this is the thing that
     makes it read as chrome. Narrow and steep, like a strip light passing
     over a polished panel rather than a torch being waved at it. */
  --sheen-grad: linear-gradient(
    100deg,
    transparent 42%, rgba(255,255,255,.28) 47%,
    #FFFFFF 50%,
    rgba(255,255,255,.28) 53%, transparent 58%);
}
@media (width >= 48rem) { :root { --gutter: 2rem; } }
@media (width >= 90rem) { :root { --gutter: 3rem; } }

/* ==========================================================================
   BASE
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: 5rem;
  -webkit-text-size-adjust: 100%;
  background: var(--pit);
}

body {
  margin: 0;
  background: var(--pit);
  color: var(--steel);
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.7;
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--display);
  margin: 0;
  color: var(--chrome-hi);
  line-height: 1.02;
  font-weight: 600;
  letter-spacing: -.01em;
  text-wrap: balance;
}

/* Display sizes go large. Chrome only reads as chrome at scale — the tonal
   flip in the gradient needs enough height to be visible at all. Below about
   28px it just looks like flat grey, so small headings do not use it. */
h1 { font-size: clamp(2.6rem, 1.2rem + 5.6vw, 6rem); }
h2 { font-size: clamp(2rem, 1.2rem + 3.2vw, 3.6rem); }
h3 { font-size: clamp(1.15rem, 1rem + .6vw, 1.4rem); letter-spacing: 0; font-weight: 500; }

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

a { color: var(--chrome); text-underline-offset: .2em; }
a:hover { color: var(--gold-hi); }

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

:focus-visible {
  outline: 2px solid var(--gold-hi);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection { background: var(--gold); color: #000; }

[hidden] { display: none !important; }

/* ==========================================================================
   THE METAL
   ========================================================================== */

/* Chrome lettering. `color` first as the fallback, then the gradient clipped
   to the glyphs on top of it.

   The gradient goes in --metal rather than straight into background, so the
   sheen below can stack a second layer on top without either class having to
   know which metal it is made of. */
.chrome {
  color: var(--chrome);
  --metal: var(--chrome-grad);
  background-image: var(--metal);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  /* A hair of drop shadow gives the letters an edge against the black,
     the way a bevel catches light. Without it chrome text on black floats. */
  filter: drop-shadow(0 1px 0 rgba(255,255,255,.14))
          drop-shadow(0 -1px 1px rgba(0,0,0,.9));
}
.gold {
  color: var(--gold);
  --metal: var(--gold-grad);
  background-image: var(--metal);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 1px 0 rgba(255,235,180,.12))
          drop-shadow(0 -1px 1px rgba(0,0,0,.9));
}

/* ── THE SHEEN ──────────────────────────────────────────────────────────
   A highlight that travels across the lettering once, when the words first
   arrive on screen. Once — not on a loop. A headline that glints every four
   seconds forever stops being a headline and becomes a distraction, and it
   is exactly the thing that makes a site look cheap rather than expensive.

   It is a second background layer sliding across a stationary one, so it
   costs nothing but a background-position and it stays live, selectable
   text throughout. `is-lit` is added by the observer in site.js when the
   words scroll into view, so every chrome heading on the site catches the
   light as you reach it. */
/* The maths, because it reads backwards. A background-position percentage
   aligns that point of the IMAGE with the same point of the BOX, so the
   offset is X% × (box − image). The sheen layer is 2.6× the box wide, which
   makes that bracket negative and reverses the sign: 180% parks the streak
   off the LEFT edge and −80% parks it off the RIGHT. Hence from 180% to
   −80% for a highlight that travels left to right. */
.sheen {
  background-image: var(--sheen-grad), var(--metal);
  background-size: 260% 100%, 100% 100%;
  background-position: 180% 0, 0 0;   /* parked off the left, out of sight */
}
.sheen.is-lit { animation: sheen-pass 1.5s var(--ease-drift) both; }

@keyframes sheen-pass {
  from { background-position: 180% 0, 0 0; }
  to   { background-position: -80% 0, 0 0; }
}

/* A hairline that fades out at both ends — the rule under his strapline. */
.rule-fade {
  height: 1px; border: 0; margin: 0;
  background: linear-gradient(90deg, transparent, var(--hair-lit) 20%, var(--hair-lit) 80%, transparent);
}

/* The small tracked-out caps from the logo's strapline. Used for every
   eyebrow, label and button on the site — it is the brand's voice. */
.eyebrow {
  font-family: var(--body);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 1rem;
}

/* His four-point star, drawn rather than cropped so it stays sharp and can
   be recoloured. Two crossed diamonds, the vertical one longer. */
.star {
  display: inline-block;
  width: 1em; height: 1em;
  background: var(--gold-hi);
  -webkit-mask: radial-gradient(ellipse 14% 50% at 50% 50%, #000 99%, transparent) ,
                radial-gradient(ellipse 50% 14% at 50% 50%, #000 99%, transparent);
  -webkit-mask-composite: source-over;
  mask: radial-gradient(ellipse 14% 50% at 50% 50%, #000 99%, transparent),
        radial-gradient(ellipse 50% 14% at 50% 50%, #000 99%, transparent);
  vertical-align: middle;
}

/* ==========================================================================
   LAYOUT
   ========================================================================== */

.wrap { width: 100%; max-width: 80rem; margin-inline: auto; padding-inline: var(--gutter); }
.wrap-narrow { max-width: 48rem; }
.wrap-wide { max-width: 94rem; }

.section { padding-block: clamp(4rem, 2rem + 7vw, 8rem); position: relative; }
.section-panel { background: var(--panel); }
.section-tight { padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem); }

/* A soft pool of light behind a section, so the black has some depth to it
   instead of being a flat sheet. */
.section-glow::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(60% 50% at 50% 0%, rgba(201,162,39,.09), transparent 70%);
  pointer-events: none;
}

.centred { text-align: center; }

/* Section opener. Eyebrow, chrome headline, a line of body — left aligned. */
.opener { margin-bottom: clamp(2.5rem, 1.5rem + 3vw, 4rem); }
.opener h2 { max-width: 18ch; }
.opener .lede { max-width: 54ch; margin-top: 1.2rem; }
.opener-centred { text-align: center; }
.opener-centred h2, .opener-centred .lede { max-width: 30ch; margin-inline: auto; }

.lede { font-size: clamp(1.0625rem, 1rem + .4vw, 1.25rem); color: var(--steel); line-height: 1.65; }

/* ==========================================================================
   BUTTONS
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
  min-height: 3.5rem;
  padding: 1rem 2.2rem;
  border: 1px solid transparent;
  border-radius: var(--r);
  font-family: var(--body);
  font-size: .75rem; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .3s var(--ease), border-color .3s, color .3s, box-shadow .3s;
}

/* The primary action is gold — the only gold fill on the site, so it is
   unmistakably the thing to press. Black text on gold, never white. */
.btn-primary {
  background: linear-gradient(180deg, #E8CE7A, #C9A227 55%, #A6821D);
  color: #140F02;
  border-color: #E8CE7A;
  box-shadow: 0 1px 0 rgba(255,255,255,.35) inset, 0 8px 24px rgba(201,162,39,.18);
}
.btn-primary:hover {
  background: linear-gradient(180deg, #F6E6B4, #E0B93C 55%, #C09522);
  color: #140F02;
  box-shadow: 0 1px 0 rgba(255,255,255,.5) inset, 0 10px 30px rgba(201,162,39,.3);
}

.btn-ghost {
  background: rgba(255,255,255,.02);
  border-color: var(--hair-lit);
  color: var(--chrome);
}
.btn-ghost:hover { border-color: var(--chrome); color: var(--chrome-hi); background: rgba(255,255,255,.06); }

.btn-block { width: 100%; }

/* A link with a rule that fills on hover. Used instead of "Learn more →". */
.linkline {
  display: inline-block;
  font-size: .7rem; font-weight: 600; letter-spacing: .22em;
  text-transform: uppercase; text-decoration: none;
  color: var(--gold);
  padding-bottom: .4rem;
  border-bottom: 1px solid var(--gold-lo);
  transition: border-color .3s, color .3s;
}
.linkline:hover { color: var(--gold-hi); border-bottom-color: var(--gold-hi); }

/* ==========================================================================
   HEADER
   ========================================================================== */

.skip { position: absolute; left: -9999px; top: 0; z-index: 100; background: var(--gold); color: #000; padding: .8rem 1.2rem; }
.skip:focus { left: 0; top: 0; }

.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;
}

/* No backdrop-filter / transform / filter here: any of them would make the
   header the containing block for the fixed mobile drawer, and the menu
   would open inside the header strip. */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(5,6,7,.92);
  border-bottom: 1px solid var(--hair);
}
.header-inner { display: flex; align-items: center; gap: 1rem; padding-block: .7rem; }

.brand { display: flex; align-items: center; gap: .8rem; text-decoration: none; margin-right: auto; }
.brand-mark { width: 2.6rem; height: 2.6rem; flex: none; }
.brand-words { display: grid; }
.brand-name {
  font-family: var(--display); font-size: 1.05rem; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; line-height: 1.1;
}
.brand-sub {
  font-size: .5625rem; font-weight: 500; letter-spacing: .26em;
  text-transform: uppercase; color: var(--steel-dim); margin-top: .18rem;
}

.nav-toggle {
  display: grid; place-items: center;
  width: 2.9rem; height: 2.9rem;
  background: none; border: 1px solid var(--hair-lit); border-radius: var(--r);
  cursor: pointer;
}
.nav-bars { display: grid; gap: 4px; }
.nav-bars i { display: block; width: 18px; height: 1.5px; background: var(--chrome); transition: transform .3s, opacity .3s; }
.nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

#primary-nav ul { list-style: none; margin: 0; padding: 0; }
#primary-nav a {
  font-size: .6875rem; font-weight: 600; letter-spacing: .2em;
  text-transform: uppercase; color: var(--steel); text-decoration: none;
  padding-block: .4rem; border-bottom: 1px solid transparent;
  transition: color .25s, border-color .25s;
}
#primary-nav a:hover { color: var(--chrome-hi); border-bottom-color: var(--gold); }
#primary-nav a[aria-current="page"] { color: var(--chrome-hi); border-bottom-color: var(--gold); }

@media (width < 62rem) {
  #primary-nav {
    position: fixed; inset: 0 0 auto; top: 0;
    background: var(--panel);
    border-bottom: 1px solid var(--hair-lit);
    padding: 5.5rem var(--gutter) 2rem;
    transform: translateY(-100%);
    transition: transform .4s var(--ease);
    visibility: hidden;
  }
  #primary-nav.is-open { transform: none; visibility: visible; }
  #primary-nav ul { display: grid; gap: .1rem; }
  #primary-nav li { border-bottom: 1px solid var(--hair); }
  #primary-nav a { display: block; padding: 1.1rem 0; font-size: .875rem; }
}
@media (width >= 62rem) {
  .nav-toggle { display: none; }
  #primary-nav ul { display: flex; gap: 2rem; align-items: center; }
}

/* ==========================================================================
   HERO
   ==========================================================================
   Full-bleed photograph, faded into the page at the bottom so there is no
   seam — the van appears to emerge out of the black rather than sitting in
   a box on it. That fade is the single move that makes a dark site feel
   built rather than themed.

   ── THE SCRIM, RE-CUT FOR A WHITE VAN ─────────────────────────────────
   This was tuned for a dark blue car, where the photograph was already
   most of the way to black. A white van in sun is the opposite problem:
   chrome lettering over a white flank is chrome on white, which is close
   to invisible. So the wash is now angled — heavy across the left where
   the words are, opening up towards the right where the sign-writing is,
   because the whole reason for using this photograph is that you can read
   his van. Text side dark, brand side lit.

   ── AND WHY NARROW SCREENS GET A DIFFERENT LAYOUT ─────────────────────
   A full-bleed background only works while the frame is wider than the van
   is. The hero's height is set by the headline, so on a phone the frame is
   portrait and the photograph gets cropped to about a quarter of its width:
   a slab of white door with no way to tell what you are looking at. A
   portrait tablet is no better — 768px showed the middle of the van and cut
   the sign-writing off at both ends, which is the one thing this photograph
   is here to show.

   So under 62rem the photograph stops being a background and becomes a band
   across the top at the van's own 3:2 — whole van, sign-writing and all. It
   is also the sharpest this photo ever looks: 390 CSS px at 3× lands almost
   exactly on the 1200 file.
   ========================================================================== */

.hero { position: relative; overflow: hidden; }
.hero-media { position: absolute; inset: 0; z-index: 0; }

/* The parallax layer. Taller than the frame at both ends so it can be slid
   without ever showing a gap, and separate from the scrim above so the wash
   stays welded to the page while the photograph moves under it. */
.hero-shift { position: absolute; inset: -7% 0; will-change: transform; }
/* Weighted right and high: right, because a frame narrower than the van has
   to choose what to lose and the sign-written flank is the half worth
   keeping; high, because the words sit along the bottom and what is under
   them is grass. */
.hero-shift img { width: 100%; height: 100%; object-fit: cover; object-position: 62% 42%; }

.hero-media::after {
  content: '';
  position: absolute; inset: 0;
  background:
    linear-gradient(100deg,
      rgba(5,6,7,.95) 0%, rgba(5,6,7,.88) 22%, rgba(5,6,7,.55) 44%,
      rgba(5,6,7,.22) 62%, rgba(5,6,7,.12) 82%, rgba(5,6,7,.3) 100%),
    /* Lands on --panel, not --pit, and lands a few percent early. The hero is
       always followed by a .section-panel, so finishing on that exact colour
       with a little flat run to spare means there is no seam to see — fading
       to the page colour instead left a hairline of lighter grey where the
       next section started, and the photograph was still faintly visible
       right up to the join. */
    linear-gradient(to bottom,
      rgba(5,6,7,.6) 0%, rgba(5,6,7,.2) 28%, rgba(5,6,7,.35) 62%,
      rgba(5,6,7,.9) 86%, var(--panel) 96%, var(--panel) 100%);
}

.hero-inner {
  position: relative; z-index: 1;
  padding-block: clamp(5rem, 4rem + 12vw, 11rem);
  min-height: min(88vh, 46rem);
  display: flex; flex-direction: column; justify-content: flex-end;
}

@media (width < 62rem) {
  .hero { display: flex; flex-direction: column; }
  /* 4:3, not the photograph's own 3:2. Cover then trims about 13% off the
     width, which is spent almost entirely on the left at 85%: it takes away
     the neighbouring unit's signage, and it buys back a taller band and a
     van 13% bigger — which on a 390px screen is the difference between
     being able to read SUPERIOR SHINE off the side of it and not.
     What it costs is the front bumper, and that was half out of frame in
     the original anyway.

     overflow, so the drift — which scales the photograph slightly — cannot
     push it out over the copy below. */
  .hero-media { position: relative; inset: auto; aspect-ratio: 4 / 3; overflow: hidden; }
  .hero-shift { position: absolute; inset: 0; }
  .hero-shift img { object-position: 85% center; }
  /* Only the foot of the photograph is washed out now — into the page, so
     the band has no bottom edge, and a touch across the top so the sticky
     header has something to sit on. */
  .hero-media::after {
    background:
      linear-gradient(to bottom,
        rgba(5,6,7,.55) 0%, transparent 22%, transparent 58%,
        rgba(5,6,7,.75) 88%, var(--pit) 100%);
  }
  .hero-inner {
    min-height: 0;
    padding-block: 0 clamp(3rem, 2rem + 6vw, 4rem);
    margin-top: -2.5rem;   /* the copy starts inside the fade, not below it */
  }
}

.hero h1 { margin-bottom: 1.6rem; }
.hero h1 .line { display: block; }
.hero-lede { max-width: 44ch; font-size: clamp(1.0625rem, 1rem + .5vw, 1.35rem); }
.hero-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 2.4rem; }

/* The strip of facts along the foot of the hero. */
.hero-facts {
  list-style: none; margin: clamp(2.5rem, 2rem + 3vw, 4rem) 0 0; padding: 1.6rem 0 0;
  border-top: 1px solid var(--hair-lit);
  display: grid; gap: 1.4rem;
}
@media (width >= 48rem) { .hero-facts { grid-template-columns: repeat(3, 1fr); gap: 2.5rem; } }
.hero-facts b {
  display: block;
  font-size: .625rem; font-weight: 600; letter-spacing: .26em;
  text-transform: uppercase; color: var(--gold); margin-bottom: .4rem;
}
.hero-facts span { font-size: .9375rem; color: var(--steel); line-height: 1.5; }

/* ==========================================================================
   SERVICES
   ==========================================================================
   Full-width alternating bands: a big photograph one side, the words the
   other, flipping each row. On a dark site this beats a card grid — the
   photographs are the product, and cards would shrink them all to postage
   stamps.
   ========================================================================== */

.svc { display: grid; gap: 0; }
.svc-row { display: grid; align-items: center; gap: clamp(2rem, 1rem + 4vw, 4.5rem); padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem); border-bottom: 1px solid var(--hair); }
.svc-row:last-child { border-bottom: 0; }
@media (width >= 60rem) {
  .svc-row { grid-template-columns: 1fr 1fr; }
  .svc-row:nth-child(even) .svc-media { order: 2; }
}

.svc-media { position: relative; overflow: hidden; background: var(--panel-2); border: 1px solid var(--hair); }
.svc-media img { width: 100%; aspect-ratio: 4/3; object-fit: cover; transition: transform 1.2s var(--ease); }
.svc-row:hover .svc-media img { transform: scale(1.04); }

.svc-no {
  font-family: var(--display); font-size: .8125rem; font-weight: 600;
  letter-spacing: .2em; color: var(--gold); margin-bottom: 1rem;
  font-variant-numeric: tabular-nums;
}
.svc-body h3 { font-size: clamp(1.6rem, 1.1rem + 2vw, 2.6rem); font-weight: 600; letter-spacing: -.01em; margin-bottom: 1rem; }
.svc-body p { max-width: 52ch; }
.svc-detail { color: var(--steel-dim); font-size: .9375rem; border-left: 1px solid var(--gold-lo); padding-left: 1rem; margin-top: 1.4rem; }

/* ==========================================================================
   GALLERY
   ==========================================================================
   Uneven on purpose — a uniform grid of car photos reads as a contact sheet.
   ========================================================================== */

.gallery { display: grid; gap: clamp(.5rem, .3rem + .8vw, 1rem); grid-template-columns: repeat(2, 1fr); }
@media (width >= 48rem) { .gallery { grid-template-columns: repeat(3, 1fr); } }
@media (width >= 75rem) { .gallery { grid-template-columns: repeat(4, 1fr); } }

.shot { margin: 0; overflow: hidden; background: var(--panel-2); position: relative; }
.shot img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4/3; transition: transform 1s var(--ease), opacity .4s; opacity: .88; }
.shot:hover img { transform: scale(1.05); opacity: 1; }
/* Every fifth plate runs tall and wide, so the grid never settles. */
@media (width >= 48rem) {
  .shot:nth-child(6n + 1) { grid-column: span 2; grid-row: span 2; }
  .shot:nth-child(6n + 1) img { aspect-ratio: 1; }
}

/* ==========================================================================
   THE PROCESS / STEPS
   ========================================================================== */

.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; display: grid; gap: 0; }
.steps li {
  counter-increment: step;
  display: grid; grid-template-columns: 3rem 1fr; gap: .3rem 1.4rem;
  padding: clamp(1.4rem, 1rem + 1.5vw, 2.2rem) 0;
  border-bottom: 1px solid var(--hair);
}
.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--display); font-size: .8125rem; font-weight: 600;
  letter-spacing: .16em; color: var(--gold); padding-top: .45em;
  font-variant-numeric: tabular-nums;
}
.steps h3 { margin-bottom: .4rem; color: var(--chrome-hi); }
.steps p { grid-column: 2; margin: 0; max-width: 56ch; }

/* ==========================================================================
   FORMS
   ========================================================================== */

.enquiry { background: var(--panel); border: 1px solid var(--hair); padding: clamp(1.4rem, 1rem + 2vw, 2.6rem); }

.field { margin-bottom: 1.4rem; }
.field > label, .field > legend, .field fieldset > legend {
  display: block; margin-bottom: .55rem; padding: 0;
  font-size: .625rem; font-weight: 600; letter-spacing: .24em;
  text-transform: uppercase; color: var(--gold);
}
.field .hint { display: block; margin-top: .4rem; font-size: .8125rem; letter-spacing: 0; text-transform: none; color: var(--steel-dim); }
.hint-inline { font-size: .6875rem; color: var(--steel-dim); text-transform: none; letter-spacing: 0; }
.field input, .field select, .field textarea {
  width: 100%; padding: .95em 1em;
  font-family: var(--body); font-size: 1rem; color: var(--chrome-hi);
  background: var(--panel-2); border: 1px solid var(--hair-lit); border-radius: var(--r-field);
  transition: border-color .2s, box-shadow .2s;
}
.field input::placeholder, .field textarea::placeholder { color: var(--steel-dim); }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--gold); box-shadow: 0 0 0 3px rgba(201,162,39,.18); outline: none;
}
.field fieldset { border: 0; margin: 0; padding: 0; }
.req { color: var(--gold); }
.two-up { display: grid; gap: 0 1.1rem; }
@media (width >= 40rem) { .two-up { grid-template-columns: 1fr 1fr; } }

.choices { display: grid; gap: .5rem; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); }
.choices label {
  position: relative; display: block; padding: .9rem 1rem;
  background: var(--panel-2); border: 1px solid var(--hair-lit); border-radius: var(--r-field);
  font-size: .9375rem; color: var(--steel); cursor: pointer;
  transition: border-color .2s, background-color .2s, color .2s;
}
.choices input { position: absolute; opacity: 0; pointer-events: none; }
.choices label:has(input:checked) { border-color: var(--gold); background: rgba(201,162,39,.1); color: var(--chrome-hi); }
.choices label:hover { border-color: var(--chrome-lo); }
.choices input:focus-visible + span { outline: 2px solid var(--gold-hi); outline-offset: 4px; }

.form-status { padding: 1rem 1.2rem; font-size: .9375rem; border: 1px solid; margin-bottom: 1rem; }
.form-status.is-good { background: rgba(63,191,127,.1); border-color: var(--good); color: #9BE9C2; }
.form-status.is-bad { background: rgba(255,107,90,.1); border-color: var(--bad); color: #FFB3A9; }
.form-status.is-working { background: var(--panel-2); border-color: var(--hair-lit); color: var(--steel); }
.form-small { font-size: .8125rem; color: var(--steel-dim); margin-top: .9rem; text-align: center; }

.notice {
  border: 1px solid var(--hair-lit); border-left: 2px solid var(--gold);
  background: var(--panel-2); padding: 1.1rem 1.3rem;
  font-size: .9375rem; color: var(--steel);
}
.notice strong { color: var(--chrome-hi); }

/* Honeypot: off-screen rather than display:none, which some bots skip. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ==========================================================================
   CONTACT STRIP / FOOTER
   ========================================================================== */

.contact-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.contact-list a { font-family: var(--display); font-size: clamp(1.2rem, 1rem + 1vw, 1.7rem); font-weight: 600; text-decoration: none; letter-spacing: .02em; }

.site-footer { background: var(--black); border-top: 1px solid var(--hair); padding-block: 4rem 2rem; }

/* The call bar is position:fixed, so it floats over whatever the page ends
   with — here, the footer's last line. 2rem of bottom padding is less than
   the bar is tall, so that line sat underneath it. Nothing in the layout can
   know a fixed element is there; it has to be compensated for explicitly. */
@media (width < 62rem) {
  .site-footer {
    padding-bottom: calc(2rem + var(--callbar-h) + env(safe-area-inset-bottom));
  }
}
.footer-inner { display: grid; gap: 2.5rem; }
.footer-top { display: grid; gap: 2.5rem; }
@media (width >= 48rem) { .footer-top { grid-template-columns: 1.3fr 1fr 1fr; gap: 3rem; } }
.footer-logo { width: min(15rem, 70%); margin-bottom: 1.2rem; }
.footer-blurb { font-size: .9rem; color: var(--steel-dim); max-width: 34ch; }
.footer-h { font-size: .625rem; font-weight: 600; letter-spacing: .26em; text-transform: uppercase; color: var(--gold); margin: 0 0 1.1rem; }
.footer-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.footer-list a { color: var(--steel); text-decoration: none; font-size: .9375rem; }
.footer-list a:hover { color: var(--chrome-hi); }
.footer-base {
  border-top: 1px solid var(--hair); padding-top: 1.6rem;
  display: flex; flex-wrap: wrap; gap: .6rem 1.4rem; justify-content: space-between;
  font-size: .75rem; color: var(--steel-dim);
}
.footer-base a { color: var(--steel-dim); }

/* ==========================================================================
   MOBILE CALL BAR
   ==========================================================================
   A detailer's business runs on the phone. Past the first screen there is
   nothing to tap, so this puts calling and WhatsApp one thumb away.
   ========================================================================== */

/* Height of the bar, declared beside the thing it measures so the footer's
   clearance cannot drift out of step with it.
   1.1rem padding top + bottom, plus roughly 1.1rem of line box. */
:root { --callbar-h: 3.3rem; }

.callbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  display: grid; grid-template-columns: 1fr 1fr;
  background: rgba(5,6,7,.97);
  border-top: 1px solid var(--hair-lit);
  transform: translateY(110%);
  transition: transform .4s var(--ease);
  padding-bottom: env(safe-area-inset-bottom);
}
.callbar.is-up { transform: none; }
.callbar a {
  display: flex; align-items: center; justify-content: center; gap: .5rem;
  padding: 1.1rem .5rem;
  font-size: .6875rem; font-weight: 600; letter-spacing: .2em;
  text-transform: uppercase; text-decoration: none;
}
.callbar-call { color: var(--chrome); }
.callbar-quote { background: linear-gradient(180deg, #E8CE7A, #C9A227); color: #140F02; }
@media (width >= 62rem) { .callbar { display: none; } }

/* ==========================================================================
   MOTION
   ==========================================================================
   The rule everything here obeys: motion is either an ARRIVAL or a
   RESPONSE. Something arrives on screen once, or it answers a pointer.
   Nothing loops, nothing pulses, nothing moves while you are trying to
   read it. On a detailer's site the animation has the same job as the
   finish he sells — you should feel that it is expensive without being
   able to point at the thing that did it.
   ========================================================================== */

@keyframes rise {
  from { opacity: 0; transform: translate3d(0, 26px, 0); }
  to   { opacity: 1; transform: none; }
}

/* ── The hero arriving ──────────────────────────────────────────────────
   Pure CSS, no observer and no class from JavaScript. This is the first
   thing anybody sees, and it must not be able to fail: if the script
   never runs the words still animate in rather than sitting invisible.
   The order is the order you would read it in, roughly a frame apart. */
.hero-inner > .eyebrow,
.hero-inner > .hero-lede,
.hero-inner > .hero-actions,
.hero-inner > .hero-facts,
.hero h1 .line { animation: rise .95s var(--ease) both; }

.hero-inner > .eyebrow      { animation-delay: .10s; }
.hero h1 .line:nth-child(1) { animation-delay: .24s; }
.hero h1 .line:nth-child(2) { animation-delay: .38s; }
.hero-inner > .hero-lede    { animation-delay: .56s; }
.hero-inner > .hero-actions { animation-delay: .70s; }
.hero-inner > .hero-facts   { animation-delay: .84s; }

/* ── The photograph, moving ─────────────────────────────────────────────
   A very slow push across the van — 28 seconds to travel 4%, which is
   under a pixel a second. You cannot catch it moving; you only notice
   that the picture is not a flat still. Paired with the parallax in
   site.js it gives the hero depth without a single sudden movement.
   Sits on the img so the parallax can own the wrapper's transform. */
@keyframes drift {
  from { transform: scale(1.005) translate3d(0, 0, 0); }
  to   { transform: scale(1.045) translate3d(-1.4%, 0, 0); }
}
.hero-shift img { animation: drift 28s var(--ease-drift) both; }

/* ── Buttons: a gloss passing over ──────────────────────────────────────
   The gold button is the one solid metal surface in the layout, so it is
   the one that should catch the light when you reach for it. */
.btn-primary { position: relative; overflow: hidden; isolation: isolate; }
.btn-primary::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(105deg,
    transparent 38%, rgba(255,255,255,.55) 50%, transparent 62%);
  transform: translateX(-130%);
  transition: transform .8s var(--ease);
  pointer-events: none;
}
.btn-primary:hover::after,
.btn-primary:focus-visible::after { transform: translateX(130%); }

/* ── Underlines that draw rather than appear ────────────────────────────
   Same gesture in three places: the nav, the "all services" links and the
   gallery plates. One idea used consistently reads as a design; three
   different hover effects read as decoration. */
#primary-nav a, .linkline, .shot { position: relative; }

#primary-nav a::after,
.linkline::after,
.shot::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--gold-hi);
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s var(--ease);
  pointer-events: none;
}
.shot::after { height: 2px; bottom: 0; background: linear-gradient(90deg, var(--gold-hi), var(--gold-lo)); }

#primary-nav a:hover::after,
#primary-nav a[aria-current="page"]::after,
.linkline:hover::after,
.shot:hover::after { transform: scaleX(1); }

/* The drawn line replaces the border that used to jump into existence. */
#primary-nav a:hover, #primary-nav a[aria-current="page"] { border-bottom-color: transparent; }
.linkline:hover { border-bottom-color: transparent; }

/* ── The header, once you have left the top ─────────────────────────────
   No backdrop-filter, for the reason given up in the header section. */
.site-header {
  transition: background-color .35s var(--ease), border-color .35s var(--ease);
}
.site-header.is-stuck {
  background: rgba(3,4,5,.97);
  border-bottom-color: var(--hair-lit);
}

/* How far down the page you are, as a hairline of gold along the foot of
   the header. It is the only thing on the site that moves continuously,
   which is allowed because it is not asking to be read. */
.scroll-line {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, var(--gold-lo), var(--gold-hi));
  transform: scaleX(var(--p, 0)); transform-origin: left;
  pointer-events: none;
}

/* ==========================================================================
   REVEAL
   ==========================================================================
   Everything below the fold arrives on the same 18px rise. --i staggers a
   group so a row of eight photographs cascades instead of flicking on all
   at once; it is set in site.js and defaults to 0, so anything that never
   gets one simply arrives immediately.
   ========================================================================== */

.reveal { opacity: 0; transform: translateY(18px); }
.reveal-in {
  opacity: 1; transform: none;
  transition: opacity .9s var(--ease), transform .9s var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms);
}

/* The service photographs wipe in from whichever side they sit on, so the
   picture opens towards its own words. Scoped to .reveal so the About
   page's ungoverned .svc-media — which nothing will ever reveal — is not
   left permanently clipped to nothing. */
.svc-row.reveal .svc-media {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 1.1s var(--ease) .08s;
}
@media (width >= 60rem) {
  /* :where() so this contributes NO specificity. It only chooses a
     direction; without it, `.svc-row.reveal:nth-child(even) .svc-media`
     outweighs the open rule below and every second photograph stays clipped
     to nothing forever. Which is exactly what it did. */
  .svc-row.reveal:where(:nth-child(even)) .svc-media { clip-path: inset(0 0 0 100%); }
}
/* Must stay after the direction rule — same weight, later wins. */
.svc-row.reveal-in .svc-media { clip-path: inset(0 0 0 0); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  /* Held open, not wiped open. */
  .svc-row.reveal .svc-media { clip-path: none; }
  /* The drift's end state is a 4% crop off the side of the photograph.
     With the animation stopped there is no reason to pay it. */
  .hero-shift img { animation: none; }
  .scroll-line { display: none; }
}

/* ==========================================================================
   PRINT
   ========================================================================== */

@media print {
  .site-header, .site-footer, .callbar, .hero-media, .btn { display: none !important; }
  body { background: #fff; color: #000; }
  .chrome, .gold { -webkit-text-fill-color: #000; color: #000; background: none; filter: none; }
  .section { padding-block: 1rem; }
}
