/* ==========================================================================
   Attention to Detail — Interior Auto Detailing
   Standard tier mockup · stylesheet

   Direction: warm cream ground, near-black bands, and one colour — the cyan
   off Ava's business card. Plus Jakarta Sans throughout. Read at arm's length
   on a phone, so everything is sized for that first:

     · rounded geometry — 18px radii, 12 for small parts, 26 for large
     · white cards lifted off the tinted ground on one soft shadow
     · hairlines divide columns; they do not lift anything
     · calm headline weights, sentence case, no uppercase in user-facing text
       beyond the small wide-tracked step labels
     · photography given room, before and after shown as a pair
     · slow, restrained transitions, all on var(--ease)

   The cyan is spent about six times a page, which is what makes it read as
   her colour rather than a default link colour. The rule that does it:

       on the cream ground   the cyan is a FILL, with ink type on it
       on the ink bands      the cyan is the TYPE

   Every text/ground pairing here is checked at 4.5:1 or better, and the
   ratios are recorded in the token comments so a later change can be checked
   against them rather than guessed.

   Sections are numbered below and each one opens with the reasoning behind
   it — read that before editing the section. Section 20 is the phone layout
   and it comes last on purpose: it is walled off at 40em so nothing in it can
   reach the desktop or tablet view.

   This replaced an earlier marque direction — 2px radii, no shadows, hairline
   columns, Archivo. The current design is the opposite of it on every one of
   those points. Nothing here is a leftover from it.
   ========================================================================== */

/* --- 1. Tokens ----------------------------------------------------------- */
/* Warm near-white ground, white surfaces lifted on soft shadow, rounded
   geometry, and the card cyan kept for the few places it can carry. Elevation
   comes from shadow and radius rather than hairlines, which is much friendlier
   to read at arm's length. */
:root {
  --paper:         #F2EDE4;  /* ground */
  --paper-alt:     #E6DFD2;  /* the warm band that alternates against it */
  --paper-alt-end: #E6DFD2;
  /* Near-black rather than a soft charcoal. It keeps a trace of the cyan's hue
     at 5% lightness so it reads as deliberate rather than as a flat #000, which
     halates against the cream and looks cheap at this size — but it is close
     enough to black that the bands land as black. */
  --ink:           #0A0D0E;  /* header, banner, mid-band, footer, CTA card */
  --ink-soft:      #0F1314;  /* the mid-page band, a hair off the bookends */
  --on-ink:        #FFFFFF;

  --bg:            var(--paper);
  --surface:       #FFFFFF;
  --surface-2:     #F2EDE4;
  --surface-sunk:  #EEE8DC;

  --line:          rgba(18, 25, 26, 0.12);
  --line-soft:     rgba(18, 25, 26, 0.08);
  --line-strong:   rgba(18, 25, 26, 0.22);

  --text:          #18201F;
  /* Secondary copy is a warm slate rather than black — at this type size the
     page needs the tonal step. Darkened from #4E5958: nearly everything wearing
     this token is small (hints, notes, captions, the rail labels), and at 6.22:1
     on the cream that was clearing AA on a technicality rather than being
     comfortable. 8.6:1 on the cream, 7.57:1 on the alt band, 10.03:1 on a white
     field. Not darker than this on purpose — --text stays 1.65x above it, and
     past roughly #363E3D that gap closes far enough that secondary copy stops
     reading as secondary.

     Only the light grounds are affected: the ink bands and the header rebind
     all three of these tokens to translucent whites further down. */
  --muted:         #3B4443;
  --muted-dim:     #3B4443;
  /* The one thing here that must NOT go as dark as the rest — a placeholder
     that reads as solid as a real value is a placeholder people try to submit.
     Lifted a step for legibility while staying far below --text on white
     (6.68:1 against 16.6:1) so it still reads as a prompt, not an entry. */
  --placeholder:   #555E5D;

  /* Brand cyan off the business card — #85E5E8, taken from the card itself
     rather than eyeballed. It is the only colour on the site.

     There used to be a second, deepened cyan here for type on light grounds,
     because #85E5E8 sits at 1.25:1 on the cream and cannot be read as words.
     That one is gone, so the accent can no longer be a text colour on
     anything light, and the rule the page now runs on is:

         on the cream ground   the cyan is a FILL, with ink type on it
         on the ink bands      the cyan is the TYPE

     --accent is what the stylesheet reaches for ~45 times below, for words,
     icons, dots, hairlines and focus rings. Pointing it at ink is what takes
     all of those monochrome on light in one move; the ink-band rule in
     section 3b flips it back to the card colour inside the dark bands. The
     cyan then gets spent about six times a page instead of forty, which is
     what makes it read as her colour rather than a default link colour. */
  --accent-bright:      #85E5E8;
  --accent-bright-deep: #A6EEF0;
  --accent:             #0A0D0E;
  --accent-deep:        #2B3334;
  /* The pill and avatar wash is the card colour itself at 30%, not a separate
     pale blue. Mixed on the cream it lands near #D1EAE5 and holds ink at 14:1. */
  --accent-tint:        rgba(133, 229, 232, 0.30);
  --accent-ink:         #0A0D0E;

  --danger:             #9C2B16;

  --font-display:  'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-body:     var(--font-display);

  --radius:        18px;
  --radius-sm:     12px;
  --radius-lg:     26px;
  /* Deeper and longer than a default card shadow — on a tinted ground a faint
     shadow disappears, and lifting the white cards off the cream is most of
     the reason the ground is tinted at all. */
  --shadow:        0 1px 2px rgba(18, 25, 26, 0.06), 0 16px 36px -18px rgba(18, 25, 26, 0.30);
  /* The same shadow one step further off the ground, for the cards that
     respond to a cursor. Cast longer and a little darker rather than just
     bigger — a card that rises should also throw further. */
  --shadow-lift:   0 2px 4px rgba(18, 25, 26, 0.07), 0 28px 52px -20px rgba(18, 25, 26, 0.42);
  --shell:         1160px;
  --shell-narrow:  820px;

  --pad-section:   clamp(4.5rem, 9vw, 8rem);
  --ease:          cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* --- 2. Reset ------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
/* The UA's [hidden] rule is a bare attribute selector, so any class that sets
   display beats it — .btn and .form-foot both do. The stepped form toggles
   real elements with the hidden property, so this has to win outright. */
[hidden] { display: none !important; }
/* Root bumped off the 16px default so every rem-based size and gap scales
   together. A lot of her customers are reading this at arm's length. */
html {
  /* Percentage, not px: an author px value here overrides the reader's own
     default font size, so anyone who has set their browser to 20 or 24px --
     which is what someone with declining close vision does once and then
     forgets about -- would get no change at all, since every size below is a
     rem off this root. 106.25% of the usual 16px default is the same 17px,
     so nothing moves for a default reader, and the whole page scales for the
     ones who need it to. */
  font-size: 106.25%;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  color-scheme: light;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 1.09rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; }
ul { margin: 0; padding: 0; list-style: none; }

/* Heavy and tightly tracked. The weight is what carries hierarchy here, so
   there are only two of them on the page — 800 for headings, 400 for copy. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1.06;
  letter-spacing: -0.03em;
  margin: 0;
}
h1 { font-size: clamp(2.6rem, 5.6vw, 4.2rem); text-wrap: balance; }
h2 { font-size: clamp(1.9rem, 3.6vw, 2.9rem); text-wrap: balance; }
h3 { font-size: clamp(1.1rem, 1.5vw, 1.25rem); letter-spacing: -0.01em; line-height: 1.3; }
p  { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

/* --- 3. Layout helpers -------------------------------------------------- */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
}
.shell--narrow { max-width: var(--shell-narrow); }
.section { padding-block: var(--pad-section); }

.section--alt {
  background: var(--paper-alt);
}

/* --- 3b. Ink bands ------------------------------------------------------ */
/* Three things on every page are ink: the banner the interior pages open on,
   one band through the middle, and the footer. With the sticky header already
   black and the closing CTA card already black, the page reads as dark at the
   top, light and open through the middle where the reading happens, and dark
   again at the close — rather than one continuous sheet of cream.

   Everything below is driven off these six custom properties. The base
   stylesheet never hard-codes a text or hairline colour, so re-pointing the
   tokens inverts the entire subtree — eyebrow pills, ledes, hairlines, card
   grounds, city lists, spec rows, the footer link colour — without any of
   those rules knowing they are on a dark ground.

   --accent is the important one. On the cream it is ink; in here it goes back
   to the card cyan, which is the mechanism behind the whole palette: the one
   colour is a fill on light and type on dark, and never the other way round. */
.section--ink,
.page-banner,
.site-footer {
  --bg:            var(--ink);
  --surface:       rgba(255, 255, 255, 0.05);
  --surface-2:     rgba(255, 255, 255, 0.08);
  --surface-sunk:  rgba(255, 255, 255, 0.05);
  --line:          rgba(255, 255, 255, 0.15);
  --line-soft:     rgba(255, 255, 255, 0.09);
  --line-strong:   rgba(255, 255, 255, 0.32);
  --text:          #FFFFFF;
  --muted:         rgba(255, 255, 255, 0.74);
  --muted-dim:     rgba(255, 255, 255, 0.62);
  --placeholder:   rgba(255, 255, 255, 0.55);
  --accent:        var(--accent-bright);
  --accent-deep:   var(--accent-bright-deep);
  --accent-tint:   rgba(133, 229, 232, 0.15);
  /* Shadow is a light-ground device. On ink it only shows up as a smudge. */
  --shadow:        none;
  --shadow-lift:   none;
  background: var(--bg);
  color: var(--text);
}
/* The mid-page band sits a hair off the bookends so a page that happens to
   end with the band butted against the footer still shows the seam. */
.section--ink { --bg: var(--ink-soft); }

/* Two cream bands in a row would read as one very long slab and lose the
   alternation, so consecutive light bands get a hairline between them. An ink
   band needs no such help — the tonal step is the divider. */
.section--alt + .section--alt { border-top: 1px solid var(--line); }

.section--tight { padding-block: clamp(3.5rem, 6vw, 5.5rem); }
.hr { height: 1px; background: var(--line); border: 0; margin: 0; }

/* Soft teal pill. Replaces the wide-tracked hairline label — same job, but it
   reads as a tag rather than a spec-sheet heading. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  border-radius: 999px;
  background: var(--accent-tint);
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent);
  margin: 0 0 1.4rem;
}
.lede { font-size: clamp(1.1rem, 1.35vw, 1.18rem); color: var(--muted); max-width: 56ch; }
.section-head { max-width: 60ch; margin-bottom: clamp(2.75rem, 5vw, 4rem); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head--center .lede { margin-inline: auto; }
.section-head--center .eyebrow { justify-content: center; }

/* --- 4. Buttons --------------------------------------------------------- */
/* Pills, sentence case, sized so they're easy to hit. Every variant clears
   48px tall; the defaults are 54. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 54px;
  padding: 0 1.7rem;
  border: 1.5px solid transparent;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  text-align: center;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease),
              color 0.18s var(--ease), transform 0.18s var(--ease);
}
/* The one loud thing on the page. Cyan fill, ink type, 12.2:1 — and identical
   on the cream sections, in the header and on the closing card, so the thing
   you are meant to press looks the same everywhere. No shadow: it is already
   the highest-contrast object in view and does not need lifting too. */
.btn--primary {
  background: var(--accent-bright);
  border-color: var(--accent-bright);
  color: var(--accent-ink);
  box-shadow: none;
}
.btn--primary:hover { background: var(--accent-bright-deep); border-color: var(--accent-bright-deep); transform: translateY(-1px); }
.btn--ghost { border-color: var(--line); color: var(--text); background: var(--surface); }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn--sm { min-height: 48px; padding: 0 1.3rem; font-size: 0.94rem; }
.btn--block { width: 100%; }
.btn-row { display: flex; flex-wrap: wrap; gap: 0.8rem; }

.textlink {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0;
  color: var(--accent);
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  border-bottom: 0;
  transition: gap 0.18s var(--ease);
}
.textlink:hover { gap: 0.85rem; text-decoration: underline; text-underline-offset: 4px; }

/* --- 5. Header / nav ---------------------------------------------------- */
/* Espresso bar — always darker than whatever sits beneath it, on every page.
   Same token flip as .section--ink, so the whole subtree inverts. */
.site-header {
  --line:          rgba(255, 255, 255, 0.16);
  --line-soft:     rgba(255, 255, 255, 0.10);
  --line-strong:   rgba(255, 255, 255, 0.30);
  --text:          #FFFFFF;
  --muted:         rgba(255, 255, 255, 0.76);
  --muted-dim:     rgba(255, 255, 255, 0.60);
  --accent:        var(--accent-bright);
  position: sticky;
  top: 0;
  z-index: 60;
  color: var(--text);
  /* Flat ink. The bar used to carry a specular sheen along its top edge, two
     cyan washes thrown from off the corners, and a hairline that picked the
     cyan up at the lit end — depth, on the argument that a flat fill reads as
     a sticker laid on the cream rather than a surface. Reverted on request:
     the bar is one solid black now, and the only cyan up there is her mark.
     The hairline stays, plain white at 12%, because the bar still has to
     separate from the cream when the page scrolls under it. */
  background-color: var(--ink);
  background-image: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.site-header__inner {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  min-height: 78px;
}

.brand { display: flex; align-items: center; gap: 0.75rem; margin-right: auto; min-width: 0; }
.brand__mark { width: 42px; height: 23px; flex: none; color: var(--accent); }
.brand__text { display: flex; flex-direction: column; line-height: 1.15; }
.brand__name {
  font-family: var(--font-display);
  font-size: 1.02rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  text-transform: none;
  white-space: nowrap;
  color: var(--text);
}
/* Header lockup: the business name with its strapline under it. */
.site-header .brand__text {
  flex-direction: column;
  align-items: flex-start;
  gap: 0.05rem;
}

.brand__tag {
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-dim);
  margin-top: 0.25rem;
}

.nav { display: flex; align-items: center; gap: 1.6rem; }
/* :not(.btn) throughout — the drawer's quote button is an <a> inside .nav, and
   a bare `.nav a` out-specifies `.btn--primary`, so without this the button
   picks up the nav's link colour and its ink type turns into white-on-cyan the
   moment the drawer opens. Scoping the link rules is the fix; patching the
   button afterwards would just start the specificity race again. */
.nav a:not(.btn) {
  position: relative;
  padding: 0.5rem 0;
  font-family: var(--font-display);
  font-size: 0.96rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  color: var(--muted);
  transition: color 0.18s var(--ease);
}
.nav a:not(.btn)::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.18s var(--ease);
}
.nav a:not(.btn):hover { color: var(--text); }
.nav a:not(.btn):hover::after { transform: scaleX(1); }
.nav a:not(.btn)[aria-current="page"] { color: var(--text); }
.nav a:not(.btn)[aria-current="page"]::after { transform: scaleX(1); }
/* The nav's quote button is for the mobile drawer only. */
.nav .btn { display: none; }

.header__cta { display: flex; align-items: center; gap: 1.25rem; flex: none; }
/* The bar is a single nowrap row; if it ever runs short the CTA must not
   collapse into a stack of words. The drawer breakpoint below is set to hand
   off before that can happen. */
.header__cta .btn { white-space: nowrap; }
/* Calling beats the form for a lot of her customers, so the number is real
   text in the bar at full size, not a small caption next to the button. */
.header__phone {
  font-family: var(--font-display);
  font-size: 1.06rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  padding: 0.6rem 0;
  color: var(--text);
  white-space: nowrap;
  transition: color 0.18s var(--ease);
}
.header__phone:hover { color: var(--accent); }

.nav-toggle {
  display: none;
  flex: none;
  width: 48px; height: 48px;
  align-items: center; justify-content: center;
  background: none;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: var(--text);
}
.nav-toggle svg { width: 20px; height: 20px; }

/* Brand + 5 links + phone + CTA need ~1100px of nowrap content plus the
   shell's 112px of padding. Below that the row has nowhere to go, so the
   drawer takes over here rather than at a width the bar can't actually hold.
   Keep this number in sync with the resize handler in js/nav.js. */
@media (max-width: 1259px) {
  .nav-toggle { display: inline-flex; }
  /* The bar keeps the phone number once the links collapse — the quote button
     is already in the drawer, and calling is the action most of her customers
     actually want. No new markup: this is the CTA block that was hidden
     wholesale before, with only its button dropped. */
  .header__cta { display: flex; gap: 0.9rem; order: 2; }
  .header__cta .btn { display: none; }
  /* The toggle sits before the CTA block in the markup; on the collapsed bar
     the number should come first and the toggle sit at the far right. */
  .nav-toggle { order: 3; }
  .nav {
    position: absolute;
    inset: 78px 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.5rem clamp(1.25rem, 5vw, 3.5rem) 2rem;
    /* The drawer reads as the bar continuing downwards, so it carries the same
       wash -- turned to come down the left edge, so the light stays on the
       same side as the bar's. A flat slab under a lit bar looks like two
       different blacks. */
    /* Matched to the bar. It was washed the same way the bar was, so that it
       read as the bar continuing downwards; with the bar flat, a lit drawer
       under it would read as two different blacks. */
    background-color: var(--ink);
    background-image: none;
    border-bottom: 1px solid var(--line);
    display: none;
  }
  .nav[data-open="true"] { display: flex; }
  .nav a:not(.btn) { padding: 1.15rem 0; font-size: 1.06rem; border-bottom: 1px solid var(--line-soft); }
  .nav a:not(.btn)::after { display: none; }
  .nav .btn { display: inline-flex; margin-top: 1.5rem; }
}

/* Phone-width bar: brand, number and toggle all have to fit on one row, so
   the strapline under the wordmark drops out. */
@media (max-width: 560px) {
  .site-header .brand__tag { display: none; }
  .site-header .brand__mark { width: 34px; height: 19px; }
  .site-header .brand__name { font-size: 0.94rem; }
  .header__phone { font-size: 0.98rem; }
  .site-header__inner { gap: 0.8rem; }
}

/* Below ~440px the wordmark, the number and the toggle stop fitting on one
   row -- and 320px is where a reader sits at 400% zoom, so this is the case
   that has to work rather than an edge one. The wordmark text gives way: the
   mark stays as the home link and keeps its aria-label, and the phone number
   keeps full size, because calling is the action most of her customers
   actually want. */
@media (max-width: 27.5em) {
  .site-header .brand__name { display: none; }
  .site-header .brand { gap: 0; }
}

/* --- 6. Hero ------------------------------------------------------------ */
.hero { position: relative; overflow: hidden; background: var(--bg); }

/* The concentric arc belonged to the technical treatment. This ground is
   plain — the photo card is the only thing that should be drawing the eye. */
.hero__arc { display: none; }

.hero__grid {
  position: relative;
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
  align-items: center;
  padding-block: clamp(3rem, 6vw, 5rem) clamp(3.5rem, 7vw, 6rem);
}
@media (min-width: 1000px) { .hero__grid { grid-template-columns: 1.05fr 0.95fr; } }

.hero__badge {
  display: inline-flex; align-items: center; gap: 0.55rem;
  margin-bottom: 1.4rem;
  padding: 0.5rem 1rem;
  border-radius: 999px;
  background: var(--accent-tint);
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent);
}
.hero__badge i {
  width: 6px; height: 6px; flex: none;
  border-radius: 50%;
  background: currentColor;
}

/* Sized to the column it actually sits in — the hero copy shares the row with
   the photo pair, so it never gets the full shell width to wrap into. */
.hero h1 {
  font-size: clamp(2.5rem, 4.4vw, 3.5rem);
  line-height: 1.06;
  letter-spacing: -0.03em;
  margin-bottom: 1.4rem;
  text-wrap: balance;
}
/* The second half of the headline used to be teal. With --accent at ink the
   whole line would go one tone, so the accent comes back underneath the words
   instead — the card colour at the largest scale anywhere on the site, with
   the type still ink and fully legible above it. A text-decoration rather than
   a background gradient because the em wraps onto two lines at most widths,
   and a gradient paints once across the whole inline box; this draws per line,
   and skip-ink lifts it around the descenders on its own. Home page only —
   every other page opens on the ink banner, where `em` is already cyan type. */
.hero h1 em {
  font-style: normal;
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--accent-bright);
  text-decoration-thickness: 0.1em;
  text-underline-offset: 0.1em;
  text-decoration-skip-ink: auto;
}
.hero__sub {
  font-size: clamp(1.1rem, 1.35vw, 1.18rem);
  line-height: 1.65;
  color: var(--muted);
  max-width: 34rem;
  /* Was 2.2rem, the gap before the buttons. The gallery link now sits between
     the two and reads as the tail of this sentence, so the paragraph closes
     tight and the link carries the gap instead. */
  margin-bottom: 0.5rem;
}
.hero__link { margin-bottom: 1.9rem; }
.hero .btn-row { margin-bottom: 2.4rem; }

/* Was a hairline-divided spec strip. Now three plain lines under the buttons —
   no rules, no boxes, just the three things people need to know. */
.hero__facts {
  display: grid;
  gap: 0.9rem;
  background: none;
  border: 0;
}
/* Stacked, not three-up. These sit in the narrow hero column, and splitting
   them into thirds put every description on three wrapped lines. */
.hero__fact {
  display: flex; align-items: flex-start; gap: 0.65rem;
  padding: 0;
  background: none;
  font-size: 1rem;
  color: var(--muted);
}
.hero__fact svg { width: 20px; height: 20px; flex: none; margin-top: 0.2rem; color: var(--accent); }
.hero__fact strong {
  display: block;
  font-family: var(--font-display);
  font-size: 1.02rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  margin-bottom: 0.15rem;
}
.hero__fact em {
  display: block;
  font-style: normal;
  font-size: 0.96rem;
  line-height: 1.5;
  color: var(--muted);
}

/* --- showcase: a real before/after pair, above the fold ------------------ */
/* Two white cards on soft shadow instead of overlapping hairline frames, and
   the price is a floating white pill rather than a black slab. */
.hero__showcase { position: relative; }
.showcase-card {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--surface);
  border: 0;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.showcase-card img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }
.showcase-card figcaption {
  position: absolute; top: 0.85rem; left: 0.85rem;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  background: rgba(255, 255, 255, 0.94);
  color: var(--text);
}
/* Was deep teal behind white type. Same job, inverted: the card colour as the
   fill, ink on top of it. */
.showcase-card--after figcaption { background: var(--accent-bright); color: var(--accent-ink); }

.showcase-chip {
  display: inline-flex; align-items: baseline; gap: 0.5rem;
  padding: 0.85rem 1.4rem;
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}
.showcase-chip b { font-size: 1.25rem; font-weight: 800; letter-spacing: -0.03em; }

@media (min-width: 1000px) {
  .hero__showcase { aspect-ratio: 1 / 1.02; }
  .showcase-card { position: absolute; }
  .showcase-card--before { width: 54%; top: 0; left: 0; z-index: 1; }
  .showcase-card--after { width: 63%; right: 0; bottom: 0; z-index: 2; }
  .showcase-chip { position: absolute; z-index: 3; left: 0; bottom: 15%; }
}
@media (max-width: 999px) {
  .hero__showcase { display: grid; grid-template-columns: 1fr 1fr; gap: 0.9rem; background: none; }
  .showcase-chip { display: none; }
}

/* --- 7. Marquee --------------------------------------------------------- */
/* The stuff she actually pulls out of cars — her voice, set as a quiet spec
   strip rather than a joke ticker. */
.marquee {
  overflow: hidden;
  padding-block: 1.5rem;
  background: var(--paper-alt);
  color: var(--text);
  border-block: 1px solid var(--line);
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 64s linear infinite;
}
.marquee__group { display: flex; align-items: center; gap: 3.5rem; padding-right: 3.5rem; }
.marquee__group li {
  display: flex;
  align-items: center;
  gap: 3.5rem;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
.marquee__group li::after {
  content: "";
  width: 5px; height: 5px; flex: none;
  border-radius: 50%;
  background: var(--accent);
}
@keyframes marquee-scroll { to { transform: translateX(-50%); } }

/* --- 8. Before / after -------------------------------------------------- */
.ba-grid { display: grid; gap: 1.25rem; background: none; }
@media (min-width: 900px) { .ba-grid { grid-template-columns: 1fr 1fr; } }
.ba-card {
  background: var(--surface);
  overflow: hidden;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.ba-card img { width: 100%; }
.ba-card__foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: 1.4rem 1.6rem 1.5rem;
}
/* Was 1.1rem, landing exactly on the lede size, so the caption for each
   before/after pair carried no more weight than the copy around it. */
.ba-card__foot h3 { font-size: 1.25rem; }
.ba-card__foot span {
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-dim);
  white-space: nowrap;
}

/* --- 8b. What's included ------------------------------------------------ */
/* One photograph carries the band and the six items list out on hairlines
   beside it. Per-item photography is the Premium treatment; here the list
   does the work and a single image supplies the proof. */
.band-grid { display: grid; gap: clamp(2.5rem, 5vw, 4.5rem); align-items: center; }
@media (min-width: 900px) { .band-grid { grid-template-columns: 1fr 1fr; } }
.band-media { overflow: hidden; }
.band-media img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}
.band-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.band-list li {
  display: grid; grid-template-columns: 2.1rem 1fr; gap: 0.25rem 1rem;
  padding-block: 1.35rem;
  border-bottom: 1px solid var(--line);
}
/* The index sits at the size of the title it labels, not shrunk to a caption. */
.band-list b {
  font-family: var(--font-display);
  font-size: 0.92rem; font-weight: 600; letter-spacing: 0.04em;
  line-height: 1.4;
  color: var(--accent);
}
/* Title in the display face at full strength — otherwise it inherits the muted
   colour off the wrapper and name and description read as one grey block. */
.band-list strong {
  display: block;
  font-family: var(--font-display);
  font-size: 1.06rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.35;
  color: var(--text);
  margin-bottom: 0.3rem;
}
.band-list span { color: var(--muted); font-size: 0.88rem; line-height: 1.55; }
/* On the espresso bands the same list flips to cream. */
.section--ink .band-list strong { color: var(--on-ink); }

.proof-row {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  padding-block: clamp(2.25rem, 4vw, 3.25rem);
  border-bottom: 1px solid var(--line);
  align-items: center;
}
.proof-row:first-of-type { border-top: 1px solid var(--line); }
@media (min-width: 800px) {
  .proof-row { grid-template-columns: 0.85fr 1.15fr; }
  /* Photo leads on alternate rows. Set per row with a modifier rather than
     nth-child, which counts the section head and flips the whole rhythm.
     The track widths swap too — reordering alone would drop the photo into
     the narrow column and make every other image smaller. */
  .proof-row--flip { grid-template-columns: 1.15fr 0.85fr; }
  .proof-row--flip .proof-row__media { order: -1; }
}

/* The copy side is only three lines, so at this row height it was floating in
   dead space. An oversized index number gives each row an anchor and turns the
   run of six into a visible sequence. */
.proof-row__text { max-width: 34ch; }
.proof-row__index {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 5vw, 3.6rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--accent);
  margin-bottom: 0.4rem;
}
.proof-row__num {
  display: flex; align-items: center; gap: 0.85rem;
  margin-bottom: 1.1rem;
  font-family: var(--font-display);
  font-size: 0.64rem; font-weight: 600;
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--muted-dim);
}
.proof-row__num::before {
  content: "";
  width: 28px; height: 1px; flex: none;
  background: var(--accent);
}
.proof-row h3 {
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
  letter-spacing: -0.025em;
  line-height: 1.15;
  margin-bottom: 0.8rem;
}
.proof-row p { color: var(--muted); margin: 0; }

/* Photo gets a caption chip naming the vehicle — the same espresso tag the
   hero and gallery use, and one more small proof that these are real cars.
   margin:0 because the photo rows are <figure> and the placeholder rows are
   <div>; the UA's 40px figure margin made every real photo narrower than the
   two empty slots. */
.proof-row__media { position: relative; overflow: hidden; margin: 0; }
.proof-row__media img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.proof-row__chip {
  position: absolute; left: 0; bottom: 0;
  margin: 0;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--on-ink);
  font-family: var(--font-display);
  font-size: 0.6rem; font-weight: 600;
  letter-spacing: 0.22em; text-transform: uppercase;
}

/* Awaiting a photo. Same dashed convention as the portrait and map slots, so
   it's obvious at a glance what still needs shooting before launch. */
.photo-placeholder {
  aspect-ratio: 3 / 2;
  display: grid; place-items: center;
  text-align: center;
  padding: 1.5rem;
  border: 1px dashed var(--line-strong);
}
.photo-placeholder svg { width: 28px; height: 28px; color: var(--muted-dim); margin-bottom: 0.9rem; }
.photo-placeholder p { font-size: 0.86rem; color: var(--muted-dim); max-width: 26ch; margin: 0; }

/* --- 9. Split ------------------------------------------------------------ */
.split { display: grid; gap: clamp(2.5rem, 6vw, 5rem); align-items: start; }
@media (min-width: 900px) { .split { grid-template-columns: 0.95fr 1.05fr; } }
.split--reverse > :first-child { order: 2; }
@media (max-width: 899px) { .split--reverse > :first-child { order: 0; } }
/* For splits where the copy is much shorter than the photo beside it —
   without this the text pins to the top and leaves a large dead gap. */
.split--center { align-items: center; }

/* Copy / photo / stat row as three siblings instead of the stats being the last
   thing inside the copy column. Nested, nothing could reorder them: `order`
   only sorts within one container, so on a phone the photo was stuck below the
   stats no matter what. As siblings the phone can put the photo between them.

   Desktop keeps the old picture -- copy and stats stacked in column one, photo
   filling column two -- via explicit placement rather than source order. The
   two halves are pinned to the boundary between their rows (copy to the end of
   row 1, stats to the start of row 2) so that when the photo is the taller of
   the columns the slack falls outside the pair instead of opening a gap down
   the middle of it. */
@media (max-width: 899px) {
  .split--stats > .frame        { order: 2; }
  .split--stats > .split__links { order: 3; }
}
@media (min-width: 900px) {
  .split--stats { row-gap: 2.5rem; }
  .split--stats > .split__copy  { grid-column: 1; grid-row: 1; align-self: end; }
  .split--stats > .split__links { grid-column: 1; grid-row: 2; align-self: start; }
  .split--stats > .frame        { grid-column: 2; grid-row: 1 / span 2; }
}

/* Both columns finish on the same line: the photo takes its height from the
   copy beside it rather than running past it. Only above the breakpoint —
   once the split stacks there is no second column to match. */
@media (min-width: 900px) {
  .split--level { align-items: stretch; }
  /* The photo is taken out of flow so it contributes no intrinsic height of
     its own. That leaves the copy column as the only thing setting the row
     height, and the image then fills exactly that — so the two columns start
     and finish on the same line instead of the photo's aspect ratio pushing
     the row taller than the text. */
  .split--level .frame { position: relative; height: 100%; min-height: 0; }
  .split--level .frame--tall img {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    aspect-ratio: auto;
    object-fit: cover;
  }
}

.frame { overflow: hidden; border-radius: var(--radius); box-shadow: var(--shadow); }
.frame img { width: 100%; }
.frame--tall img { aspect-ratio: 4 / 5; object-fit: cover; }

/* --- 10. Pricing -------------------------------------------------------- */
/* A spec sheet, not a set of cards: hairline columns, oversized figures. */
/* Separate rounded cards rather than one hairline-divided slab. */
.price-grid { display: grid; gap: 1.25rem; background: none; border: 0; }
@media (min-width: 860px) { .price-grid { grid-template-columns: repeat(3, 1fr); } }
.price-card {
  position: relative;
  display: flex; flex-direction: column;
  padding: clamp(2rem, 3vw, 2.4rem) clamp(1.6rem, 2.5vw, 2rem);
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: transform 0.24s var(--ease), box-shadow 0.24s var(--ease);
}
/* The middle tier used to carry a hairline of --accent as well, which on the
   cream ground is ink — a black rectangle drawn around one of three white
   cards, and by some distance the heaviest thing in the section. The filled
   button already in its markup was making the same point in the one colour
   this ground allows, so the emphasis is left to that. The 1.5px transparent
   border that reserved the space for it went with it. */

/* These are the cards you act on, and the whole card is the target rather
   than just the button at the bottom of it, so the whole card answers. It
   rises and the shadow lengthens underneath it — elevation on this site is
   shadow and radius, so a hover raises those rather than drawing an edge,
   which is what the removed border was doing permanently. */
.price-card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-lift);
}
/* And the vehicle pulls forward. Four pixels, on the one element in the
   section that can move without anything else having to move with it. */
.price-card:hover .price-card__icon { transform: translateX(4px); }
.price-card__tag {
  position: absolute; top: clamp(2rem, 3vw, 2.4rem); right: clamp(1.6rem, 2.5vw, 2rem);
  font-family: var(--font-display);
  font-size: 0.85rem; font-weight: 600;
  letter-spacing: 0; text-transform: none;
  color: var(--accent);
}
.price-card__icon {
  width: 52px; height: 30px;
  color: var(--accent);
  margin-bottom: 1.4rem;
  transition: transform 0.24s var(--ease);
}
.price-card h3 {
  /* Was 1.15rem -- a hair under the lede beside it, so the tier name read as
     body copy. It is the thing the reader is choosing between; it leads. */
  font-size: 1.4rem;
  letter-spacing: -0.01em;
  text-transform: none;
  margin-bottom: 0.4rem;
}
.price-card__fits { font-size: 0.98rem; color: var(--muted); margin-bottom: 1.2rem; min-height: 2.9em; }
.price-card__price { display: flex; align-items: baseline; gap: 0.6rem; margin-bottom: 1.6rem; }
.price-card__price b {
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 4.4vw, 3.2rem);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1;
}
.price-card__price span {
  font-family: var(--font-display);
  font-size: 0.98rem; letter-spacing: 0; text-transform: none;
  color: var(--muted);
}
.price-card .btn { margin-top: auto; }

/* Add-ons. Cards rather than pills: each one has to carry the reason someone
   would want it, and a pill can only hold a name and a number. Equal-height
   columns so the three prices line up instead of floating at three depths. */
.addons {
  display: grid;
  gap: 1.25rem;
  margin-top: 2.25rem;
  padding: 0;
  list-style: none;
  background: none;
  border: 0;
}
@media (min-width: 820px) { .addons { grid-template-columns: repeat(3, 1fr); } }
.addon {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.8rem;
  padding: 1.8rem 1.7rem;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: var(--text);
  font-size: 1rem;
}
.addon__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
}
.addon__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.15rem; font-weight: 800; letter-spacing: -0.02em;
  color: var(--text);
}
.addon__price {
  flex: none;
  font-family: var(--font-display);
  font-size: 1.3rem; font-weight: 800; letter-spacing: -0.03em;
  color: var(--accent);
}
.addon p { margin: 0; color: var(--muted); line-height: 1.6; }
/* The add-on cards get the shadow and not the lift. There is nothing in one
   to press — a card that rises under the cursor is promising a target it does
   not have — but they are priced items sitting in a row, and the shadow is
   enough to say which one you are reading. On the ink bands --shadow-lift is
   none along with --shadow, so this quietly does nothing there. */
.addon { transition: box-shadow 0.24s var(--ease); }
.addon:hover { box-shadow: var(--shadow-lift); }

/* An add-on card on an ink band inherits --surface at 5% white, which is a
   dark box on a dark ground: the name and the price hold up, but the line of
   copy under them — the part that says what the add-on is for — sits at 74%
   white on near-black and reads as an afterthought. These are the three things
   on that page someone might actually add to the job, so they go cream and
   carry ink type at full strength, the same as they have on phones.

   The band works by re-pointing tokens on the subtree, so the honest way to
   undo it for one component is to re-point them back rather than override
   .addon__name, .addon__price and .addon p one at a time. The literals are the
   :root values from section 1 — keep them in step if those change. On this
   ground --text is 14.2:1 and --muted is 8.6:1. */
.section--ink .addon {
  --surface: #FFFFFF;
  --text:    #18201F;
  --muted:   #3B4443;
  --accent:  #0A0D0E;
  --line:    rgba(18, 25, 26, 0.12);
  background: var(--paper);
  color: var(--text);
}

/* Stacked — for the add-on list sitting in one half of a split, beside a
   photo, where three across would be far too narrow. Doubled class so it
   beats the three-column rule in the media query above regardless of order.
   Compressed, because the whole copy column has to finish level with the
   photograph next to it. */
.addons.addons--stack { grid-template-columns: 1fr; gap: 0.7rem; margin-top: 1.75rem; }
.addons--stack .addon { padding: 1rem 1.35rem; gap: 0.2rem; }
/* Was 1.02rem, i.e. smaller than the paragraph under it. */
.addons--stack .addon__name { font-size: 1.2rem; }
.addons--stack .addon__price { font-size: 1.12rem; }
.addons--stack .addon p { font-size: 0.98rem; line-height: 1.5; }

/* Compact — the home page carries the name and the price only, so the roomier
   card used on Services leaves it looking hollow. */
.addons.addons--compact { gap: 1rem; }
.addons--compact .addon { padding: 1.15rem 1.35rem; gap: 0; }
/* Same inversion as the stack variant: the name sat under both the lede and
   its own price, so the thing being named lost to the number beside it. */
.addons--compact .addon__name { font-size: 1.2rem; }
.addons--compact .addon__price { font-size: 1.15rem; }

.price-note { margin-top: 1.5rem; font-size: 1rem; color: var(--muted); }

/* --- 11. Gallery -------------------------------------------------------- */
/* Separate rounded photos with real gaps, not a hairline wall. */
.gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; background: none; }
@media (min-width: 760px) { .gallery { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1060px) { .gallery { grid-template-columns: repeat(4, 1fr); } }
.gallery figure {
  margin: 0; position: relative; overflow: hidden;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.gallery img { width: 100%; aspect-ratio: 1; object-fit: cover; transition: transform 0.5s var(--ease); }
.gallery figure:hover img { transform: scale(1.04); }
.gallery figcaption {
  position: absolute; inset: auto 0 0 0;
  padding: 2.5rem 1.2rem 1.1rem;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: #FFFFFF;
  background: linear-gradient(180deg, transparent, rgba(10, 13, 14, 0.9));
}
.gallery--tall img { aspect-ratio: 3 / 4; }

@media (min-width: 760px) {
  .gallery--feature > figure:first-child { grid-column: span 2; grid-row: span 2; aspect-ratio: 1; }
  .gallery--feature > figure:first-child img { aspect-ratio: auto; height: 100%; }
  .gallery--feature > figure:first-child figcaption { font-size: 1.05rem; padding: 3rem 1.5rem 1.35rem; }
}

/* 12 was Reviews — review cards, a star row and a Google score bar, all built
   and never used by a page. Ava does not want reviews on the site, so it was
   58 lines styling a section that is not coming. The numbers after it are left
   alone deliberately: CLAUDE.md and a good few comments in here refer to
   sections by number, and renumbering to close a gap would cost more than the
   gap does. */

/* --- 13. Service area --------------------------------------------------- */
.area-grid { display: grid; gap: clamp(2.5rem, 5vw, 4.5rem); align-items: center; }
@media (min-width: 900px) { .area-grid { grid-template-columns: 1fr 1fr; } }
/* Cities read as pills rather than a hairline table. */
.city-list { display: flex; flex-wrap: wrap; gap: 0.7rem; margin: 2rem 0; border: 0; }
.city-list li {
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.7rem 1.2rem;
  border: 0;
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow);
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}
.city-list svg { width: 17px; height: 17px; color: var(--accent); }

.map-placeholder {
  position: relative;
  aspect-ratio: 4 / 3;
  display: grid; place-items: center;
  text-align: center;
  padding: 2rem;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.map-placeholder svg { width: 30px; height: 30px; color: var(--accent); margin-bottom: 1rem; }
.map-placeholder p { font-size: 1rem; color: var(--muted); max-width: 26ch; margin: 0; }

/* --- 14. CTA band ------------------------------------------------------- */
/* The one black block on the page below the header — an inset rounded card
   sitting on the ground, rather than a full-bleed band. */
.cta-band {
  --line: rgba(255, 255, 255, 0.2);
  --accent: var(--accent-bright);
  background: var(--bg);
  color: var(--on-ink);
  text-align: center;
  padding-block: var(--pad-section);
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
}
/* Backed with a finished interior. The band is the last thing on every page, so
   it closes on the work rather than on a flat black card — but the card is the
   one place the page relies on white type, so the photograph sits under an ink
   scrim at 80–92%. That floor is what holds the lede (white at 72%) past 4.5:1
   even across the sunlit part of the frame, and it lets the ghost button's
   border stay a legible edge rather than a suggestion. The focal point sits low
   so the wheel and console hold the centre when the card goes tall and narrow on
   a phone. Static by construction: no attachment: fixed, nothing to animate. */
.cta-band .shell {
  background-color: var(--ink);
  /* A CSS background cannot use <picture>, so the WebP is offered through
     image-set() and the plain url() line above it is the fallback: a browser
     that does not understand image-set() ignores the second declaration
     entirely and keeps the JPEG. */
  background-image:
    linear-gradient(180deg,
      rgba(10, 13, 14, 0.92) 0%,
      rgba(10, 13, 14, 0.80) 52%,
      rgba(10, 13, 14, 0.90) 100%),
    url("../assets/audi-after-dash.jpg");
  background-image:
    linear-gradient(180deg,
      rgba(10, 13, 14, 0.92) 0%,
      rgba(10, 13, 14, 0.80) 52%,
      rgba(10, 13, 14, 0.90) 100%),
    image-set(url("../assets/audi-after-dash.webp") type("image/webp"),
              url("../assets/audi-after-dash.jpg")  type("image/jpeg"));
  background-position: 50% 62%;
  background-size: cover;
  background-repeat: no-repeat;
  border-radius: var(--radius-lg);
  padding: clamp(2.8rem, 6vw, 4.5rem) clamp(1.5rem, 4vw, 3rem);
}
.cta-band h2 { margin-bottom: 1.3rem; }
.cta-band .lede { color: rgba(255, 255, 255, 0.72); margin-inline: auto; margin-bottom: 2.4rem; }
.cta-band .btn-row { justify-content: center; }
/* Bumped from 0.3 — over the photograph that edge fell to ~2.2:1 and the button
   read as floating text. At 0.5 it clears 3:1 against the lightest composite. */
/* This was the site's one true ghost button -- transparent, sitting on a
   photograph, at the last conversion moment on every page, and on the home page
   it is the "call me" action that a good share of her customers would rather
   take than fill in a form. An outline on a photo does not read as a control.
   It gets a real surface now.

   A solid white fill would have been the obvious fix and the wrong one: white
   outshouts the cyan primary beside it, and two equally loud buttons is not
   better than one quiet one. A tonal fill reads unmistakably as a button while
   staying subordinate -- white type holds 9.5-12.4:1 on it whatever the
   photograph underneath is doing. */
.cta-band .btn--ghost {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.68);
  color: var(--on-ink);
}
.cta-band .btn--ghost:hover {
  background: rgba(255, 255, 255, 0.26);
  border-color: #FFFFFF;
  color: #FFFFFF;
}

/* --- 15. Forms ---------------------------------------------------------- */
.form-layout { display: grid; gap: clamp(2.5rem, 5vw, 4.5rem); align-items: start; }
/* Grid children default to min-width:auto, which lets min-content push a track
   wider than its container -- at a large reader font size that turned the form
   into a sideways scroll. Zero lets the track shrink and the content wrap. */
.form-layout > * { min-width: 0; }
@media (min-width: 62.5em) { .form-layout { grid-template-columns: 1.4fr 0.6fr; } }

.form-card { padding: 0; background: transparent; }
.field-grid { display: grid; gap: 2.25rem; }
.field-grid > * { min-width: 0; }
@media (min-width: 40em) { .field-grid--2 { grid-template-columns: 1fr 1fr; } }

.field { display: flex; flex-direction: column; gap: 0.55rem; min-width: 0; }
/* These are the words you have to read to fill the form in, so they are the
   one place the wide-tracked uppercase label treatment used elsewhere does not
   earn its keep: caps strip the ascender/descender word shapes that older
   readers lean on, and 0.2em tracking pulls words apart into letters. Sentence
   case at a readable size, weight kept so they still read as labels. */
.field > label, .fieldset__legend {
  font-family: var(--font-display);
  font-size: 0.94rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text);
}
.req { color: var(--accent); }

/* Filled fields — a bare underline is a weak "type here" signal, so each field
   is a filled block on the sand ground. No outer panel: the layout stays open
   and editorial, the inputs just stop being invisible. Square corners and a
   hairline base keep it inside the house style. */
.input, .select, .textarea {
  width: 100%;
  /* width:100% alone does not stop an input from reporting a min-content width
     of roughly its default 20-character size. That intrinsic width propagates
     up through the flex/grid parents and, at a large reader font size, pushed
     the whole form wider than the screen. */
  min-width: 0;
  padding: 0.9rem 0.95rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid transparent;
  border-bottom-color: var(--line);
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: 1rem;
  transition: border-color 0.45s var(--ease), background 0.45s var(--ease);
}
.textarea { min-height: 110px; resize: vertical; line-height: 1.6; }
.input::placeholder, .textarea::placeholder { color: var(--placeholder); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface-2);
}
/* The outline:none above outranks the global :focus-visible ring, which left
   these three signalling keyboard focus by border colour alone. Put the ring
   back for keyboard users; pointer focus keeps the quieter treatment. */
.input:focus-visible, .select:focus-visible, .textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* appearance:none strips the native arrow, and a filled select with no arrow is
   indistinguishable from a text input — so draw one back on. */
.select {
  appearance: none;
  padding-right: 2.6rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%230A0D0E' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m1 1.5 5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.95rem center;
  background-size: 12px 8px;
}

fieldset { margin: 0; padding: 0; border: 0; }
.fieldset__legend { display: block; margin-bottom: 1.1rem; }

/* Three-across boxes. The 1px grid gap shows the background through as the
   internal dividers, and the border closes the block on all four sides so it
   reads as one framed unit rather than a floating table. */
/* Separated cards, not a hairline table. These are the one thing on the form
   you tap rather than type, and as edge-to-edge cells filled with the page
   ground they were the odd unit out on a site where every other repeated
   thing is a white surface on a soft shadow. */
.option-grid {
  display: grid;
  gap: 0.6rem;
}
.option-grid > * { min-width: 0; }
@media (min-width: 35em) { .option-grid--3 { grid-template-columns: repeat(3, 1fr); } }
.option {
  display: flex; align-items: flex-start; gap: 0.9rem;
  padding: 1.15rem 1.15rem;
  background: var(--surface);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  cursor: pointer;
  transition: box-shadow 0.24s var(--ease);
}
.option:hover { box-shadow: var(--shadow-lift); }
.option input {
  align-self: flex-start;
  margin: 0.25rem 0 0;
  accent-color: var(--accent);
  width: 18px; height: 18px; flex: none;
}
/* Label to the top, price to the bottom — so the prices stay on one line
   across all three boxes even when a longer label wraps. */
.option__body {
  flex: 1;
  display: flex; flex-direction: column; justify-content: space-between;
  gap: 0.5rem;
}
.option__label { font-size: 1.05rem; line-height: 1.4; }
/* The figure as a chip in the card colour rather than as bold text. On this
   ground the cyan can only be a fill, and a price is the one number on the
   form worth spending it on. Ink on #85E5E8 is 13.3:1. */
.option__price {
  align-self: flex-start;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--accent-bright);
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-size: 0.82rem; font-weight: 800; letter-spacing: -0.01em;
}
/* The card is already a white surface, so a checked one cannot answer with a
   background. The native box is doing that; this just firms up the label. */
.option:has(input:checked) .option__label { font-weight: 600; }

/* Photo upload — the real input sits inside the label, so the whole panel is
   the click target. Wired to storage at build; inert in the mockup. */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.5rem;
  padding: clamp(2rem, 4vw, 2.75rem) 1.25rem;
  border: 1px dashed var(--line-strong);
  cursor: pointer;
  transition: border-color 0.45s var(--ease), background 0.45s var(--ease);
}
.dropzone:hover { border-color: var(--accent); background: var(--surface); }
.dropzone:focus-within { border-color: var(--accent); }
.dropzone input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.dropzone__icon { color: var(--accent); margin-bottom: 0.75rem; }
.dropzone__icon svg { width: 26px; height: 26px; }
.dropzone__title {
  font-family: var(--font-display);
  font-size: 0.74rem; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.dropzone__title u { color: var(--accent); text-decoration: none; border-bottom: 1px solid currentColor; }
.dropzone__meta { font-size: 0.83rem; color: var(--muted-dim); }

.form-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem;
  margin-top: 3rem;
  padding-top: 2.25rem;
  border-top: 1px solid var(--line);
}


/* Confirmation block on thanks.html, where the form posts to. It used to
   replace the form in place; a real POST leaves the page, so the reassurance
   moved to the page that catches it rather than being deleted. */
.form-sent { padding: clamp(2rem, 4vw, 3rem) 0; }
.form-sent__label {
  font-family: var(--font-display);
  font-size: 0.84rem; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1rem;
}
.form-sent h2 { margin-bottom: 1rem; }
.form-sent p { color: var(--muted); max-width: 52ch; }

/* Error state. The palette had no failure colour — this is the one addition,
   a deep brick that holds 4.5:1 on both the sand ground and white fields. */
.field--invalid .input,
.field--invalid .select,
.field--invalid .textarea { border-color: var(--danger); }
.field--invalid .option-grid { border-color: var(--danger); }
.field__error {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.83rem;
  font-weight: 500;
  color: var(--danger);
}

/* Contact side rail */
.rail { display: grid; gap: 3rem; }
.rail-card { padding: 0; }
.rail-card h3 {
  font-size: 0.84rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted);
  padding-bottom: 1.1rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--line);
}
.contact-list { display: grid; gap: 1.5rem; }
.contact-list li { display: flex; gap: 0.9rem; align-items: flex-start; }
.contact-list svg { width: 17px; height: 17px; flex: none; margin-top: 0.3rem; color: var(--accent); }
.contact-list span {
  display: block;
  font-family: var(--font-display);
  font-size: 0.8rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted-dim);
  margin-bottom: 0.35rem;
}
.contact-list p { font-size: 1rem; margin: 0; }
/* Calling is often the real conversion for an older customer, and these two
   sat 21px tall -- half the 44px minimum -- directly under "Reach me
   directly". Inline-flex with a min-height pads the hit area without moving
   the text or boxing the link. */
.contact-list a {
  display: inline-flex; align-items: center;
  min-height: 44px;
  font-size: 1rem;
  margin: -0.5rem 0;
}
.contact-list a:hover { color: var(--accent); }

.hours { display: grid; gap: 0; }
.hours li {
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: 0.92rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--line);
}
/* The rule divides one row from the next, and the card ends after the last
   row, so it has nothing left to divide. */
.hours li:last-child { border-bottom: 0; }
.hours span { color: var(--muted); }

/* --- 16. About ---------------------------------------------------------- */
.about-hero { display: grid; gap: clamp(2.5rem, 6vw, 5rem); align-items: center; }
@media (min-width: 900px) { .about-hero { grid-template-columns: 0.85fr 1.15fr; } }
.portrait-placeholder {
  aspect-ratio: 4 / 5;
  display: grid; place-items: center;
  text-align: center;
  padding: 2rem;
  border: 1px dashed var(--line-strong);
}
.portrait-placeholder svg { width: 34px; height: 34px; color: var(--muted-dim); margin-bottom: 1rem; }
.portrait-placeholder p { font-size: 0.89rem; color: var(--muted-dim); max-width: 24ch; margin: 0; }

/* What she will be held to, under her story. This replaced a row of three
   figures in tiles, and the shape is the point: big numerals in boxes are how
   a page performs credibility when it has none to show, and on a one-person
   mobile round the numbers available are either unverifiable or already said
   somewhere else. Three sentences on hairlines make a claim you can check
   against the rest of the site instead, and they sit in the copy column as
   part of the reading rather than as a panel bolted under it.

   No card, no shadow: this is the tail of a paragraph, not a peer unit. */
.promises {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  border-top: 1px solid var(--line);
}
.promises li {
  padding-block: 1.05rem;
  border-bottom: 1px solid var(--line);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--muted);
}
.promises b {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}

/* --- 17. Footer --------------------------------------------------------- */
/* Ink footer — the ground and the token flip both come from the shared
   ink-band rule in section 3b, so there is nothing to set here. No top
   hairline: the tonal step against the section above already is the edge. */
.site-footer { border-top: 0; }
.footer-grid {
  display: grid; gap: clamp(2.5rem, 4vw, 3.5rem);
  padding-block: clamp(3rem, 5vw, 4rem);
}
@media (min-width: 860px) { .footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1.2fr; } }
.footer-col h4 {
  font-family: var(--font-display);
  font-size: 0.92rem; letter-spacing: -0.01em; text-transform: none;
  color: var(--text); font-weight: 700; margin-bottom: 0.9rem;
}
/* These rows are real tap targets — the phone number and email down here get
   used, and at 22px tall they were a coin toss on a phone. */
.footer-col ul { display: grid; gap: 0.15rem; }
.footer-col a, .footer-col p { font-size: 1rem; color: var(--muted); }
/* Scoped to the link lists — the brand lockup is also an <a> in here, and
   making it inline-block broke the mark and wordmark onto separate lines. */
.footer-col ul a { display: inline-block; padding: 0.65rem 0; }
.footer-col li > p { padding: 0.65rem 0; margin: 0; }
.footer-col a { transition: color 0.18s var(--ease); }
.footer-col a:hover { color: var(--accent); }
.site-footer .brand__name { color: var(--text); }
.site-footer .brand__tag { color: var(--muted); }
.site-footer .brand__mark { color: var(--accent); }
.footer-brand p { margin-top: 1.2rem; max-width: 32ch; font-size: 1rem; }
.footer-bottom {
  display: flex; flex-wrap: wrap; gap: 0.75rem 1.5rem; align-items: center;
  padding-block: 1.6rem;
  border-top: 1px solid var(--line);
  font-family: var(--font-display);
  font-size: 0.92rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
.footer-bottom p { margin: 0; }
.footer-bottom .spacer { margin-left: auto; }

/* --- 18. Page banner (interior pages) ---------------------------------- */
/* Pill eyebrow, heavy two-tone headline, and whatever that page is actually
   about carried in a card beside it. The concentric arc and the accent tick
   belonged to the technical treatment and are gone.

   Everything below is still shared, because section 18b builds the photo
   banner on top of it — but contact is the only page that gets this as it
   stands. Anything added here lands on the photo pages too. */
/* Ground and token flip come from the shared ink-band rule in section 3b. */
.page-banner {
  position: relative;
  overflow: hidden;
  border-bottom: 0;
  /* The band was flat ink, which under a lit header read as the bar being the
     only thing designed and the rest being a hole. This carries the header's
     light on down: same cyan, same direction, spread over a much larger area
     so it reads as atmosphere rather than as a second glow.

     Only background-image is set here -- the ink-band rule in section 3b
     already supplies background-color via --bg, and this rule comes after it,
     so the shorthand there is not fighting these layers.

     Peak lands at ~#2A4547. That ceiling is set by the eyebrow pill, not the
     headline: the pill is a 15% cyan wash with cyan type on it, so it lightens
     along with the band and its type is the first thing to fall below 4.5:1. */
  background-image:
    /* the header's light spilling down into the band */
    radial-gradient(78% 125% at 2% -12%, rgba(133, 229, 232, 0.26), rgba(133, 229, 232, 0) 62%),
    /* a wider, softer counter-glow so the diagonal does not go dead */
    radial-gradient(68% 115% at 97% 112%, rgba(133, 229, 232, 0.15), rgba(133, 229, 232, 0) 66%),
    /* faint sheen off the top edge, so band and bar meet as one surface */
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 42%);
}
.page-banner__arc { display: none; }
.page-banner .shell {
  position: relative;
  padding-block: clamp(3rem, 6vw, 5rem);
}
.page-banner__grid { display: grid; gap: clamp(2.25rem, 5vw, 4.5rem); }
@media (min-width: 900px) {
  .page-banner__grid {
    grid-template-columns: minmax(0, 1.4fr) minmax(14rem, 0.6fr);
    align-items: end;
  }
}
.page-banner h1 {
  font-size: clamp(2.2rem, 4vw, 3.2rem);
  margin-bottom: 1.2rem;
  text-wrap: balance;
}
.page-banner h1 em { font-style: normal; color: var(--accent); }

/* Contact is the only page still opening on this banner — services, the
   gallery and about open on a photograph instead, section 18b — so the spec
   card, the contact sheet and the business card that used to fill the second
   column here are gone with them.

   What is left is contact's: what happens after the form. Answering that above
   the fold is what gets it filled in. Arrows rather than 01/02/03, because the
   form below numbers its own groups and two numbered sequences on one screen
   read as one. */
.page-banner__next-label {
  display: inline-flex; align-items: center;
  margin: 0 0 0.9rem;
  padding: 0.5rem 1rem;
  border-radius: 999px;
  background: var(--accent-tint);
  font-family: var(--font-display);
  font-size: 0.85rem; font-weight: 600; letter-spacing: 0; text-transform: none;
  color: var(--accent);
}
.page-banner__steps {
  list-style: none; margin: 0;
  padding: 0.4rem 1.6rem;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.page-banner__steps li {
  display: flex; align-items: baseline; gap: 0.9rem;
  padding-block: 1.1rem;
  border-top: 1px solid var(--line);
}
.page-banner__steps li:first-child { border-top: 0; }
.page-banner__steps li:last-child { border-bottom: 0; }
.page-banner__steps b {
  flex: none;
  font-size: 1rem; font-weight: 700;
  color: var(--accent);
}
.page-banner__steps p {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.06rem; font-weight: 600; letter-spacing: -0.01em;
  color: var(--text);
}

/* Only the 404 puts links inside this card. On every other page the steps
   describe what happens next and nothing in them is clickable, so there is no
   link affordance here to inherit — and on this white ground the cyan is a
   fill rather than a type colour, which rules out the usual move of colouring
   them. That leaves an underline, which is the honest one anyway: these three
   are the whole point of that page. */
.page-banner__steps p a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
  text-decoration-color: var(--line-strong);
  transition: text-decoration-color 0.18s var(--ease);
}
.page-banner__steps p a:hover,
.page-banner__steps p a:focus-visible { text-decoration-color: currentColor; }


/* --- 18b. Photo banner (services, gallery, about) ----------------------- */
/* Three of the four interior pages open on a photograph instead of on the
   gradient. The gradient was the same on all four, so the only thing telling
   you which page you had landed on was the words — and a lit black field with
   a soft glow in the corner is the one part of this site that could have come
   from anywhere. A different car on each page fixes both at once, and it puts
   the actual work above the fold on pages that were opening with type.

   Contact keeps the plain ink band on purpose: it is the one interior page
   where the fold has a job other than persuading, and a photograph in front of
   a form is decoration in the way of the thing you came to do.

   The ground and the token flip still come from the ink-band rule in section
   3b, so `em` is already cyan and the ledes are already the translucent white.
   All this variant does is put a picture behind that and take the gradient
   off. Everything stacks explicitly: picture 0, scrim 1, copy 2 — the scrim is
   a pseudo-element, which generates after .shell and would otherwise paint
   over the headline. */
.page-banner--photo {
  background-image: none;
  /* The photographs are 900px wide phone snaps. Full-bleed on a desktop they
     upscale about 1.4x, which the scrim mostly hides; if the originals turn up
     at full resolution they should be dropped in over these. */
}
.page-banner--photo .page-banner__shot { position: absolute; inset: 0; z-index: 0; }
.page-banner--photo .page-banner__shot img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  /* On a phone the frame is taller than it is wide and the whole photograph
     fits, so this does nothing. On a desktop the band is a ~19% horizontal
     slice of a portrait phone photo, and where that slice falls decides
     whether you are looking at a truck or at a texture. Each page sets
     --shot-y in its own markup, next to the photograph it picked. */
  object-position: center var(--shot-y, 50%);
}
/* A vertical ramp to solid ink rather than an even wash. The type never sits
   on the picture — it sits on ink that the picture fades into, which is the
   same white-on-#0A0D0E the ink bands already run at, ~19:1. Reaching solid at
   74% is deliberate: every line has to clear 4.5:1 against the brightest frame
   in the set, not against the one that happens to be dark. The second layer
   pulls the left edge down so the copy column holds up on wide screens, where
   the vertical ramp alone is doing less work. */
.page-banner--photo::after {
  content: "";
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(180deg, rgba(10, 13, 14, 0.30) 0%, rgba(10, 13, 14, 0.86) 38%, #0A0D0E 74%),
    linear-gradient(90deg, rgba(10, 13, 14, 0.60), rgba(10, 13, 14, 0) 72%);
}
/* Tall, with the copy sitting at the bottom of the frame. The picture needs
   room above the type or it reads as a texture rather than as a car. */
.page-banner--photo .shell {
  z-index: 2;
  padding-block: clamp(7rem, 16vw, 11rem) clamp(2rem, 4vw, 3rem);
}
/* The photograph replaces the second column, so there is no grid left to run —
   the copy is the whole banner and the picture is behind it. */
.page-banner--photo .page-banner__grid { display: block; }
.page-banner--photo .page-banner__arc { display: none; }
.page-banner--photo h1 { max-width: 20ch; }
.page-banner--photo .lede { max-width: 46ch; }
/* On the photograph the pill loses its edges — a 15% white wash over a picture
   is a smudge. The page name goes back to plain cyan type with a dot, which is
   also the one place the eyebrow can be type rather than a tag without costing
   anything, because the ground under it here is solid ink. */
.page-banner--photo .eyebrow {
  background: none;
  padding: 0;
  color: var(--accent);
  gap: 0.55rem;
}
.page-banner--photo .eyebrow::before {
  content: "";
  width: 6px; height: 6px; flex: none;
  border-radius: 50%;
  background: currentColor;
}

/* Services — the three figures the white card used to carry, as one line on a
   hairline. The card cannot come along: a cream slab in front of a photograph
   covers the half of the picture worth looking at. */
.page-banner__facts {
  display: flex; flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin: 1.5rem 0 0;
  padding: 1.1rem 0 0;
  list-style: none;
  border-top: 1px solid var(--line);
  /* The rule is a divider, not a margin — run it the full width of the shell
     and it sits a foot wider than the lede it is dividing from. This is the
     width the three facts actually take. */
  max-width: 36rem;
}
.page-banner__facts li { font-size: 1rem; color: var(--muted); }
.page-banner__facts b { color: var(--text); font-weight: 700; }


/* --- 19. Misc ----------------------------------------------------------- */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 0.75rem 1.25rem; background: var(--accent-bright); color: var(--accent-ink);
  font-weight: 600;
}
.skip-link:focus { left: 0; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

@media (max-width: 480px) {
  /* The header brand is handled in the 560px block above; this only needs to
     catch the footer lockup, which is still sentence case now. */
  .site-footer .brand__mark { width: 34px; height: 19px; }
  .site-footer .brand__name { font-size: 0.95rem; }
  .site-footer .brand__tag  { font-size: 0.8rem; }
  .hero .btn-row .btn,
  .cta-band .btn-row .btn { width: 100%; }
}

/* The link under a split's copy used to carry margin-top:1.4rem as an inline
   style on the markup, which no stylesheet rule could outrank — so the phone
   block could not tighten it. It lives here now, at the value the inline style
   set, and section 20 overrides it for phones. */
.split__copy .textlink,
.split > div > .textlink { margin-top: 1.4rem; }


/* --- 19b. FAQ ------------------------------------------------------------
   Eight <details> on the services page. Nothing here is required for the
   content to be readable: with CSS off they are still eight questions with
   eight answers, and with JavaScript off they still open, because <details>
   was already the accordion and nobody needed to build one.

   The cards are the same surface/radius/shadow as the pricing and add-on cards
   rather than a bordered list, so the section reads as a sibling of the two
   above it. Elevation is shadow, hairlines divide — the one hairline in here
   sits between a question and its answer, which is dividing.

   The chevron is a rotated corner rather than an SVG so it inherits colour and
   costs no request. It uses --accent, which is ink on this cream ground: the
   cyan is a fill here, never type, and a cyan chevron would break that. */
.faq { display: grid; gap: 0.85rem; }
.faq__item {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;      /* keeps the open body inside the rounded corner */
}
.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1.35rem clamp(1.4rem, 3vw, 1.8rem);
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 1.06rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--text);
  /* Both are needed: the pseudo-element is Safari's, list-style is everyone
     else's, and leaving either in gives the row two markers. */
  list-style: none;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after {
  content: '';
  flex: none;
  width: 9px; height: 9px;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: translateY(-3px) rotate(45deg);
  transition: transform 0.2s var(--ease);
}
.faq__item[open] summary::after { transform: translateY(2px) rotate(-135deg); }
.faq__item summary:hover { background: var(--surface-sunk); }
.faq__body {
  padding: 0 clamp(1.4rem, 3vw, 1.8rem) 1.45rem;
  border-top: 1px solid var(--line-soft);
  padding-top: 1.25rem;
}
.faq__body p { margin: 0; color: var(--muted); }
.faq__foot { margin-top: 1.6rem; text-align: center; color: var(--muted); }
/* The link is inline in a sentence here, so it needs the padding off or the
   line it sits in grows taller than the ones around it. */
.faq__foot .textlink { padding-block: 0; }

/* --- 20b. Stepped quote form -------------------------------------------
   The steps are hidden with the hidden attribute from JS, so none of this
   applies until the script runs.
   ------------------------------------------------------------------------ */
.form-progress {
  margin: 0 0 1.4rem;
  font-family: var(--font-display);
  font-size: 0.76rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted);
}
.form-progress [data-progress-name] { color: var(--text); }
.form-nav { display: grid; gap: 0.6rem; margin-top: 1.6rem; }
.form-nav .btn { width: 100%; }

/* Two routes out of the who-I-am section, set as rows with a rule between
   them rather than two bare arrows stacked up — at a glance they were reading
   as one link that had wrapped. */
.split__links {
  display: grid;
  justify-items: stretch;
  gap: 0;
  margin-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.split__links .textlink {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0;
  min-height: 52px;
  border-bottom: 1px solid var(--line);
}

/* --- 21. Scroll reveals -------------------------------------------------
   .has-reveal is set by js/reveal.js, so none of this applies unless the
   script has run and the reader has not asked for reduced motion. Opacity
   and a 14px rise only — nothing here can move layout, so a reveal firing
   cannot shift something the reader is already looking at.
   ------------------------------------------------------------------------ */
.has-reveal [data-reveal] {
  opacity: 0;
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
  /* The browser gets told what is about to change, and then told to forget:
     leaving will-change on a long page keeps a layer alive for every
     revealed block. */
  will-change: opacity, transform;
}
/* Everything rises. */
.has-reveal [data-reveal="up"] { transform: translateY(14px); }
/* Except the deep-clean checklist, which is dealt out from alternating sides.
   The distance is deliberately short: a long slide reads as the layout being
   unstable, and anything further is visibly still moving when you start
   reading the line. */
.has-reveal [data-reveal="left"]  { transform: translateX(-26px); }
.has-reveal [data-reveal="right"] { transform: translateX(26px); }
.has-reveal [data-reveal].is-shown {
  opacity: 1;
  transform: none;
  will-change: auto;
}
/* transform does not change layout but it does extend the scrollable area, so
   a block waiting 26px off to the right would give the page a sideways scroll
   until it arrived. clip, not hidden: hidden would make this a scroll
   container and break the sticky header. */
.has-reveal body { overflow-x: clip; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .has-reveal [data-reveal] { opacity: 1; transform: none; }
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* --- 20. Phone ----------------------------------------------------------
   Everything above this point was sized for a desktop column and then left to
   reflow. On a 375px screen that meant a 42px headline eating three lines
   before anything else appeared, a page 8,840px tall — about eleven screens
   to reach the footer — a wordmark that vanished under 440px, and no way to
   call or quote once you had scrolled past the hero.

   This block is the phone layout, and it is deliberately walled off at 40em
   so nothing here can reach the desktop or tablet view, which were fine. Two
   pieces of markup exist only for it and are display:none above this width:
   the hero drag-to-compare and the segmented pricing control.
   ------------------------------------------------------------------------ */

/* Both phone-only blocks are hidden by default and switched on inside the
   query below, so no desktop browser ever lays them out. */
.ba, .ba__hint, .hero__acts, .hero__intro, .hero__trust,
.price-tabs, .action-rail, .u-phone-only { display: none; }

@media (max-width: 40em) {

  /* --- scale ------------------------------------------------------------ */
  /* The single biggest fix. Everything else follows from the type coming
     down to something read at arm's length rather than across a desk. */
  .hero h1                       { font-size: 2.05rem; margin-bottom: 1rem; }
  .section h2, .cta-band h2      { font-size: 1.58rem; }
  /* The interior pages open on this, and it was taking the same 1.58rem as a
     mid-page section heading — which is most of why those four pages read as
     flat next to the home page. It is a page title; it gets the home
     headline's size. */
  .page-banner h1                { font-size: 1.95rem; margin-bottom: 0.9rem; }
  .hero__sub                     { font-size: 1rem; margin-bottom: 1.5rem; }
  .lede                          { font-size: 0.97rem; }
  .section                       { padding-block: 2.6rem; }
  .cta-band                      { padding-block: 2.8rem; }
  .shell                         { width: calc(100% - 2.5rem); }
  .u-phone-hide                  { display: none; }
  .u-phone-only                  { display: revert; }

  /* --- header ----------------------------------------------------------- */
  /* I tried restoring the wordmark under 440px here and took it back out: the
     name, the number and the toggle need ~352px of a 333px bar, and the only
     way to fit all three is 13-14px type in a header the rest of the site
     deliberately sets at 17px for readers holding the phone at arm's length.
     The original trade — mark stays as the home link, name goes, number keeps
     full size because calling is the action most of her customers want — is
     the right one at this width. Getting the name back needs the number to
     become a call icon, which is a markup change on all five pages.
     What is left here is just breathing room and a 44px toggle. */
  .site-header__inner { gap: 0.6rem; }
  .nav-toggle         { width: 44px; height: 44px; }
  .nav                { inset-block-start: 70px; }

  /* The rail holds Call at the bottom of every screen on every page now, so no
     bar has to carry the number — which is what was crowding the wordmark out
     below 440px. Name and mark go back in, the same on all five pages. */
  .has-rail .header__cta    { display: none; }
  .has-rail .brand__name    { display: inline; font-size: 0.92rem; }
  .has-rail .brand          { gap: 0.55rem; }
  /* The stacked pair is only as wide as the name, so the row costs mark, name,
     tyre and her name across a bar with 224px going spare beside a 44px
     toggle. At full size that came to 244px and ran under the toggle, so the
     mark, the name and both gaps each give up a little rather than any one of
     them shrinking to nothing. */
  .has-rail .brand__mark    { display: block; width: 34px; height: 19px; }
  .has-rail .brand           { gap: 0.55rem; }
  .has-rail .brand__name    { font-size: 0.95rem; }
  /* The 560px rule takes the strapline off small screens; it is the second
     line of the lockup now, so it comes back. */
  .site-header .brand__tag  { display: block; font-size: 0.72rem; margin-top: 0; }

  /* Spread out: a two-line lockup needs the bar to grow with it rather than
     squeeze it, and the toggle wants air either side.

     The width rule matters more than it looks. .shell on phones carries a
     21px auto margin (from width:calc(100% - 2.5rem)) on top of its own 21px
     padding, so the bar's content was sitting 43px in on each side and the
     lockup was fighting for room that the gutter had already taken. The bar
     takes a single 20px gutter instead, which is 45px back. */
  .site-header__inner {
    width: 100%;
    margin-inline: 0;
    padding-inline: 1.25rem;
    min-height: 74px;
    gap: 0.8rem;
    padding-block: 0.4rem;
  }
}

/* The phone layout continues. (It is split in two here only because a narrow
   360px exception used to sit between the halves; the exception is gone with
   the tyre it was there to drop.) */
@media (max-width: 40em) {

  /* --- hero ------------------------------------------------------------- */
  /* The buttons go: the rail at the bottom of the screen carries the same
     primary action and is visible at every scroll position, and two identical
     cyan buttons 60px apart reads as a bug rather than as emphasis. */
  .hero__grid    { padding-block: 1.6rem 2.2rem; gap: 0; }
  .home .hero .btn-row { display: none; }
  /* Headline, then the proof. The paragraph was five lines of phone screen
     between the two, saying what the photograph says faster — that part still
     holds, so it stays hidden. What went with it was the only words on the
     first screen that named the service, which left a stranger reaching the
     price having read a metaphor and looked at a picture. One line replaces
     it, above the photograph, short enough not to reopen the problem. */
  .home .hero__sub     { display: none; }
  .hero .hero__line {
    margin: 0 0 1.4rem;
    font-size: 1rem;
    line-height: 1.5;
    /* Full text colour rather than the muted grey the desktop paragraph
       takes — the same call this block already made for .u-phone-only, since
       at phone sizes the grey does more fading than ranking. Ink on cream is
       14.23:1, against 8.6:1 for the muted it replaces. */
    color: var(--text);
  }
  /* The price, in the card colour, on the photograph that earns it. Ink type
     on a cyan fill — the rule the site runs on for the accent on a light
     ground, and the one place in the hero the colour gets to be a block. */
  .ba__price {
    position: absolute; z-index: 2;
    right: 0.7rem; bottom: 0.7rem;
    margin: 0;
    padding: 0.4rem 0.85rem;
    border-radius: 999px;
    background: var(--accent-bright);
    color: var(--accent-ink);
    font-family: var(--font-display);
    font-size: 0.82rem; font-weight: 600;
  }
  .ba__price b { font-size: 1.02rem; font-weight: 800; letter-spacing: -0.02em; }

  /* Two facts, built the way every other repeated unit on this site is built:
     a white surface on a soft shadow, figure over label, centred. Same
     construction as the stat row further down the page, so the hero is not
     inventing a third way to present a number. */
  .hero__trust {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.6rem;
    margin: 1.3rem 0 0;
    padding: 0;
    list-style: none;
    border-top: 0;
  }
  .hero__trust li {
    padding: 0.9rem 0.6rem;
    background: var(--surface);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    text-align: center;
    font-size: 0.76rem; line-height: 1.3;
    color: var(--muted);
  }
  .hero__trust b {
    display: block;
    font-family: var(--font-display);
    font-size: 1.3rem; font-weight: 800; letter-spacing: -0.03em;
    color: var(--text);
    margin-bottom: 0.15rem;
  }

  /* Mark and slogan. The mark is ink, not cyan: on this cream the card colour
     sits at 1.25:1 and a cyan stroke would be decoration you cannot see. */
  /* Sits between the photograph and the buttons: the before/after raises the
     question of who is turning up, and this answers it before the ask. */
  .hero__intro {
    display: block;
    margin-top: 1rem;
    font-family: var(--font-display);
    font-size: 0.98rem; font-weight: 600;
    line-height: 1.45;
    color: var(--text);
  }
  .hero__intro em {
    font-style: normal;
    box-shadow: inset 0 -0.32em 0 var(--accent-bright);
  }
  /* The route to her page is the end of her own sentence rather than a button
     under it — a second full-width button beside "Get my free quote" competed
     with the one action the hero is for. */
  .hero__intro a {
    white-space: nowrap;
    font-weight: 700;
    border-bottom: 2px solid var(--accent-bright);
    padding-bottom: 1px;
  }

  /* Under the photo, where the eye lands once it has read the before/after. */
  .home .hero__acts    { display: grid; gap: 0.6rem; margin-top: 1.2rem; }
  .home .hero__acts .btn { width: 100%; }
  .hero__badge   { margin-bottom: 1rem; padding: 0.35rem 0.8rem; font-size: 0.8rem; }
  .home .hero__showcase { display: none; }

  .home .ba {
    display: block;
    position: relative;
    /* Ours horizontally, the page's vertically. Without this the browser
       claims the horizontal drag for a scroll it is not going to do. */
    touch-action: pan-y;
    margin-top: 1.35rem;
    aspect-ratio: 4 / 5;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--ink);
    box-shadow: var(--shadow);
    container-type: inline-size;
  }
  /* Each half is the full width of the box, so both crop identically and the
     wipe stays flush; only the photograph behind it changes. The jpg is the
     fallback declaration — image-set hands webp to anything that takes it. */
  .ba__shot {
    position: absolute; top: 0; left: 0;
    height: 100%; width: 100cqw;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
  }
  .ba__shot--before {
    background-image: url("../assets/audi-before-seat.jpg");
    background-image: image-set(url("../assets/audi-before-seat.webp") type("image/webp"),
                                url("../assets/audi-before-seat.jpg")  type("image/jpeg"));
  }
  .ba__shot--after {
    background-image: url("../assets/audi-after-wheel.jpg");
    background-image: image-set(url("../assets/audi-after-wheel.webp") type("image/webp"),
                                url("../assets/audi-after-wheel.jpg")  type("image/jpeg"));
  }
  .ba__clip   { position: absolute; inset: 0; width: 50%; overflow: hidden; will-change: width; }
  /* Not the stock round knob with two chevrons in it. The divider is the tool:
     a squeegee blade — a cyan edge with a tall, slim ink grip on it, ribbed
     the way a handle is. It sits low rather than dead centre so it does not
     land on the middle of the photograph. */
  .ba__handle {
    position: absolute; top: 0; bottom: 0; left: 50%;
    width: 3px;
    background: var(--accent-bright);
    pointer-events: none;
    box-shadow: 0 0 18px rgba(10, 13, 14, 0.55);
  }
  .ba__handle::after {
    content: "";
    position: absolute; top: 62%; left: 50%;
    transform: translate(-50%, -50%);
    width: 16px; height: 68px;
    border-radius: 8px;
    background: var(--ink);
    border: 1px solid var(--accent-bright);
    box-shadow: 0 4px 16px rgba(10, 13, 14, 0.55);
  }
  /* Three ribs down the grip, in the accent. */
  .ba__handle::before {
    content: "";
    position: absolute; top: 62%; left: 50%; z-index: 2;
    transform: translate(-50%, -50%);
    width: 6px; height: 22px;
    background:
      linear-gradient(var(--accent-bright), var(--accent-bright)) 0 0 / 1px 100% no-repeat,
      linear-gradient(var(--accent-bright), var(--accent-bright)) 50% 0 / 1px 100% no-repeat,
      linear-gradient(var(--accent-bright), var(--accent-bright)) 100% 0 / 1px 100% no-repeat;
    opacity: 0.75;
  }
  /* The range is still the value and still the thing a keyboard drives, but it
     no longer takes the pointer: iOS will not jump a range to a tapped point
     the way a desktop browser does, so on a phone you had to land exactly on a
     56px invisible thumb, in the vertical middle of a 420px photo, to move it
     at all. The container handles pointers now and writes the value here. */
  .ba__range {
    position: absolute; inset: 0; z-index: 3;
    width: 100%; height: 100%; margin: 0;
    opacity: 0; pointer-events: none;
    -webkit-appearance: none; appearance: none; background: none;
  }
  .home .ba { cursor: ew-resize; }
  .home .ba:focus-within { outline: 3px solid var(--accent-bright); outline-offset: 2px; }
  /* Not two rounded pills either. These are the house uppercase micro-label,
     set as square ink chips on the photograph — the before side plain, the
     after side carrying the accent as type, which is the rule the rest of the
     site runs on for anything sitting on a dark ground. */
  .ba__tags {
    position: absolute; left: 0; right: 0; top: 0.7rem; z-index: 2;
    display: flex; justify-content: space-between;
    padding-inline: 0.7rem; pointer-events: none;
  }
  .ba__tags span {
    padding: 0.32rem 0.6rem;
    border-radius: 3px;
    background: rgba(10, 13, 14, 0.72);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.16);
    font-family: var(--font-display);
    font-size: 0.62rem; font-weight: 700;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: rgba(255, 255, 255, 0.9);
  }
  .ba__tags span:last-child {
    color: var(--accent-bright);
    border-color: rgba(133, 229, 232, 0.45);
  }
  /* Faded rather than removed, so the chip does not pop in and out as the
     divider crosses it. */
  .ba__tags span {
    transition: opacity 0.18s var(--ease);
  }
  .ba__tags span.is-hidden { opacity: 0; }
  .home .ba__hint {
    display: block;
    margin-top: 0.7rem;
    text-align: center;
    font-size: 0.84rem;
    color: var(--muted);
  }

  /* --- gallery ---------------------------------------------------------- */
  /* Five stacked squares was 894px of one section. Sideways is the one place
     swiping is right: hiding the next photo costs nothing. */
  .home .gallery--feature {
    display: flex;
    gap: 0.65rem;
    grid-template-columns: none;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-inline: 1.25rem;
    margin-inline: -1.25rem;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .home .gallery--feature::-webkit-scrollbar { display: none; }
  .home .gallery--feature figure { flex: 0 0 72%; scroll-snap-align: center; }
  .home .gallery--feature img { aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--radius-sm); }

  /* --- pricing ---------------------------------------------------------- */
  /* Keyed off .has-price-tabs — home and services both carry the control now.
     Any other page with a .price-grid and no control keeps its cards. */
  .has-price-tabs .price-grid { display: none; }
  .has-price-tabs .price-tabs { display: block; margin-top: 1.4rem; }

  /* All three figures stay on screen — a phone visitor is comparing them, and
     a control that shows one at a time takes the comparison away. Unselected
     prices keep full-strength ink for that reason; only the label greys back. */
  .price-tabs__seg {
    display: flex; gap: 2px; padding: 4px;
    background: var(--surface);
    border-radius: 999px;
    box-shadow: var(--shadow);
  }
  /* Labels only. The figures were up here so all three prices stayed on
     screen at once; they are back in the panel now and the control is a
     plain switch again. */
  .price-tabs__seg button {
    flex: 1; min-height: 48px; padding: 0 0.3rem;
    display: flex; align-items: center; justify-content: center;
    border: 0; border-radius: 999px; background: none;
    font-family: var(--font-display); color: var(--muted);
    white-space: nowrap;
    transition: background 0.16s var(--ease), color 0.16s var(--ease);
  }
  .price-tabs__seg .lbl {
    font-size: 0.88rem; font-weight: 700; letter-spacing: -0.01em;
  }
  /* The card colour as a fill with ink on it — the rule the rest of the
     stylesheet runs on. It is never type on this ground. */
  .price-tabs__seg button[aria-selected="true"]      { background: var(--accent-bright); color: var(--accent-ink); }

  .price-tabs__panel {
    margin-top: 0.9rem; padding: 1.25rem 1.15rem;
    background: var(--surface);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
  }
  .price-tabs__top  { display: flex; align-items: baseline; gap: 0.65rem; }
  /* The tab above already says which vehicle this is, and the icon was
     costing 56px of a 290px row — enough to wrap "Mid-size SUV / Truck"
     onto two lines next to a vertically centred figure. */
  .price-tabs__icon { display: none; }
  .price-tabs__name { font-family: var(--font-display); font-size: 0.95rem; font-weight: 700; letter-spacing: -0.02em; }
  .price-tabs__amt  {
    margin-left: auto;
    font-family: var(--font-display); font-size: 1.75rem; font-weight: 800;
    letter-spacing: -0.04em; font-variant-numeric: tabular-nums; white-space: nowrap;
  }
  .price-tabs__fits { margin-top: 0.75rem; font-size: 0.92rem; color: var(--muted); }
  .price-tabs__inc  { margin-top: 1.1rem; padding-top: 1.05rem; border-top: 1px solid var(--line); }
  .price-tabs__inc > p {
    margin-bottom: 0.6rem;
    font-family: var(--font-display); font-size: 0.72rem; font-weight: 700;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted);
  }
  .price-tabs__inc ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
  .price-tabs__inc li { display: flex; gap: 0.55rem; align-items: flex-start; font-size: 0.92rem; }
  .price-tabs__inc svg { width: 15px; height: 15px; flex: none; margin-top: 0.3rem; }
  .price-tabs__panel .btn { margin-top: 1.2rem; }

  /* Add-ons drop from cards to pills — three cards was ~350px of page for
     three numbers. The li stops being the card (block, no chrome) and the
     head becomes the pill, inline so it shrinks to its own text. */
  /* Pills are for the HOME page's compact strip only — three names and three
     numbers, no descriptions, which as cards was ~350px of page. services.html
     uses .addons--stack, where every add-on carries a line of copy explaining
     it; stripping the card off those would leave the description floating
     under a pill with nothing holding it. That variant just gets phone padding.
     .addons--compact carries its own padding and type sizes at a higher
     specificity than the bare element selectors, so these have to match it
     rather than sit under it. */
  .addons.addons--compact { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
  .addons--compact .addon {
    display: block; padding: 0; gap: 0;
    background: none; border: 0; box-shadow: none;
  }
  .addons--compact .addon__head {
    display: inline-flex; align-items: baseline; justify-content: flex-start; gap: 0.4rem;
    padding: 0.5rem 0.9rem;
    background: var(--surface);
    border-radius: 999px;
    box-shadow: var(--shadow);
  }
  .addons--compact .addon__name  { font-size: 0.86rem; font-weight: 600; }
  .addons--compact .addon__price { font-size: 0.86rem; font-weight: 800; }

  /* The contact banner's steps card inherits --surface at 5% white from the
     band. At desktop size, against a lot of surrounding black, that reads as a
     card; on a phone, where the card is most of the screen, it is a dark box
     on a dark ground you can barely make out. It goes cream.
     The band works by re-pointing tokens on the subtree, so the honest way to
     undo it for one component is to re-point them back rather than override
     the type colours one at a time — the literals below are the :root values,
     which the band has already overwritten by the time this rule is read.
     Keep them in step with section 1 if those change. */
  .page-banner__steps {
    --surface: #FFFFFF;
    --text:    #18201F;
    --muted:   #4E5958;
    --accent:  #0A0D0E;
    --line:    rgba(18, 25, 26, 0.12);
    background: var(--paper);
    color: var(--text);
  }
  .addons--stack .addon { padding: 1.15rem 1.2rem; gap: 0.5rem; }
  .addons--stack .addon__name  { font-size: 1.05rem; }
  .addons--stack .addon__price { font-size: 1.05rem; }
  .addons--stack .addon p { font-size: 0.9rem; }
  .addons { gap: 0.85rem; }

  .price-note   { font-size: 0.88rem; }

  /* --- the rest --------------------------------------------------------- */
  .promises { margin-top: 1.6rem; }
  .promises li { padding-block: 0.9rem; font-size: 0.97rem; }
  /* The split's desktop gutter is up to 4.5rem, which on a phone is just
     dead space between a paragraph and the photo under it. */
  /* The link sat 42px under the paragraph and the photograph another 28px
     under that, which on a phone is a paragraph, a pause, a link, a pause. */
  .split, .area-grid { gap: 1.1rem; }
  .split__copy .textlink, .split > div > .textlink { margin-top: 0.85rem; }
  /* The link now sits under the photograph rather than under the copy. It is
     a separate phone-only element, so the one in the copy column goes. */
  /* .split--stats gives the frame order:2 below 899px so the photograph drops
     under the copy; the link pair carries order:3 to land beneath it. */
  .split__links { margin-top: 1.2rem; }
  .frame--tall .portrait-placeholder { aspect-ratio: 4 / 3; }
  .frame--tall img { aspect-ratio: 16 / 10; object-fit: cover; }
  /* The condensed phone paragraph, on the home page and on services. Full
     text colour rather than muted — at 0.97rem the grey was doing more fading
     than hierarchy, and var(--text) resolves correctly on both grounds: ink
     on the cream band, white inside an ink one. */
  .u-phone-only { color: var(--text); font-size: 0.97rem; margin-top: 1.1rem; }
  .city-list { gap: 0.5rem; margin: 1.1rem 0; }
  .city-list li { padding: 0.5rem 0.95rem; font-size: 0.9rem; }
  .home .map-placeholder { display: none; }   /* about.html shows a real one */

  /* Four stacked columns was 1,344px of footer nobody scrolls to.
     minmax(0,1fr) rather than 1fr: a plain fr floors at min-content, and
     avabright2006@gmail.com is a 223px unbreakable token, so the first
     column would take 70% of the row and the second would get the scraps. */
  /* The desktop footer is a four-column sitemap. Squeezed onto a phone it was
     either 1,344px of stacked column or, in two columns, 134px-wide cells that
     put "Bonney Lake" on two lines. Neither is what a phone footer looks like.
     This is the ordinary mobile pattern instead: one column, each group under
     a small label, every link a full-width row you can hit with a thumb,
     hairline between rows, and the legal line centred at the bottom. */
  .footer-grid {
    display: block;
    padding-block: 1.75rem 0.5rem;
  }
  .footer-col { margin-bottom: 1.5rem; }
  .footer-col:last-child { margin-bottom: 0.5rem; }
  .footer-col h4 { margin-bottom: 0.2rem; }

  .site-footer ul { gap: 0; }
  .site-footer li { border-bottom: 1px solid rgba(255, 255, 255, 0.1); }
  .site-footer li:last-child { border-bottom: 0; }
  /* Rows, not a list — 48px each so they are actually tappable. The service
     area column is <p> not <a>, so it stays a plain line rather than pretending
     to be a link. */
  .site-footer li > a { display: flex; align-items: center; min-height: 48px; }
  .site-footer li > p { padding-block: 0.6rem; margin: 0; }
  .site-footer li, .site-footer .footer-col p { font-size: 0.94rem; }
  .site-footer a, .site-footer p { overflow-wrap: anywhere; }

  /* The brand blurb is the one place a paragraph belongs down here. */
  .footer-brand { margin-bottom: 1.75rem; }
  .footer-brand p { font-size: 0.9rem; }

  .footer-bottom {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.35rem;
    padding-block: 1.4rem;
    font-size: 0.82rem;
  }
  .footer-bottom .spacer { margin-left: 0; }

  /* --- the deep-clean checklist ------------------------------------------ */
  /* Seven rows at desktop padding, under a 4/5 photograph that took most of a
     screen on its own. The photo comes down to a band, the rows tighten, and
     the index stops being a number in accent-coloured text — on this ground
     the accent resolves to ink, so it was reading as part of the sentence.
     It becomes a chip: the card colour as a fill with ink on it. */
  .band-grid { gap: 1.5rem; }
  /* The photo sat square-cornered and flush, the one image on the page not
     built like the rest of the site's imagery. Same radius and shadow as
     every other figure now, and a band rather than a portrait so it does not
     take a screen on its own. */
  .band-media {
    border-radius: var(--radius);
    box-shadow: var(--shadow);
  }
  .band-media img { aspect-ratio: 16 / 10; }
  .band-list li {
    grid-template-columns: 1.9rem 1fr;
    gap: 0.15rem 0.85rem;
    padding-block: 0.95rem;
  }
  .band-list b {
    display: grid; place-items: center;
    width: 1.9rem; height: 1.9rem;
    border-radius: 7px;
    background: var(--accent-bright);
    color: var(--accent-ink);
    font-size: 0.76rem; font-weight: 800; letter-spacing: 0.02em;
  }
  .band-list strong { font-size: 1rem; margin-bottom: 0.2rem; }
  .band-list span   { font-size: 0.87rem; line-height: 1.5; }
  /* On an ink band the chip inverts: the accent goes back to being the type. */
  .section--ink .band-list b { background: rgba(133, 229, 232, 0.14); color: var(--accent-bright); }

  /* --- the other four pages --------------------------------------------- */
  /* The home page gets the segmented control instead of the cards; services is
     the page you go to *for* the detail, so the cards stay — just at phone
     size. The desktop padding is up to 2.4rem on all four sides of a card,
     which on a 335px column is more margin than card. */
  .price-card { padding: 1.4rem 1.25rem; }
  .price-card__icon { width: 42px; height: 24px; margin-bottom: 0.9rem; }
  .price-card h3 { font-size: 1.2rem; }
  .price-card__fits { font-size: 0.9rem; }
  .price-grid { gap: 0.85rem; }

  /* Two-up is already the base below 760px; this only tightens the gutter and
     stops the tiles going letterbox on a narrow column. */
  /* .ba-card is a <figure> that never had its UA margin reset, so it carried
     margin:1em 40px — 80px of a 290px track, leaving a 210px card adrift in a
     full-width row. The caption then laid out as a row with the vehicle name
     set to nowrap, so "Chrysler 300" ran 26px past the card and was cut off by
     the card's own overflow:hidden. Full width here, and the caption stacks.
     (Desktop carries the same 80px inset; there it reads as generous spacing
     rather than as a fault, so it is left alone.) */
  .ba-card { margin: 0; }
  .ba-card__foot {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    padding: 1.1rem 1.15rem 1.25rem;
  }
  .ba-card__foot h3   { font-size: 1.05rem; }
  .ba-card__foot span { white-space: normal; font-size: 0.9rem; }

  /* The job walkthrough swipes: it is a sequence — before, before, after,
     after — and one frame at a time is how a sequence is read. The finished
     interiors stay a grid, because that section is a body of work and the
     point of it is how much there is. The rail hangs into the gutters so the
     next photo peeks in and the gesture is visible without a caption telling
     anyone to swipe. */
  .gallery--tall {
    display: flex;
    grid-template-columns: none;
    gap: 0.6rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding-inline: 1.25rem;
    margin-inline: -1.25rem;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .gallery--tall::-webkit-scrollbar { display: none; }
  .gallery--tall figure { flex: 0 0 84%; scroll-snap-align: center; }
  .gallery--tall figure img { aspect-ratio: 3 / 4; object-fit: cover; }

  .gallery { gap: 0.5rem; }
  .gallery figure img { aspect-ratio: 1; object-fit: cover; }

  /* Captions come off the photographs — at this size they cover a third of
     the image to say what the image already shows. The one thing worth
     keeping is which half of the job you are looking at, so on the
     walkthrough the Before/After word survives as a corner chip and the rest
     of the caption goes. Same chip as the slider in the home hero. */
  .gallery figcaption, .gallery--feature figcaption { display: none; }
  .gallery--tall figure { position: relative; }
  .gallery--tall figcaption {
    display: block;
    /* inset:auto on the two edges the base rule pins. It sets
       `inset: auto 0 0 0`, so without this the chip keeps the full width and
       height of the tile — and with a backdrop-filter on it, that blurred the
       whole photograph instead of the 60px behind the word. */
    position: absolute;
    inset: 0.6rem auto auto 0.6rem;
    padding: 0.32rem 0.6rem;
    border-radius: 3px;
    background: rgba(10, 13, 14, 0.72);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.16);
    font-family: var(--font-display);
    font-size: 0; /* hides the " — mats & pedals" half without a second element */
  }
  .gallery--tall .ba-tag {
    font-size: 0.62rem; font-weight: 700;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: rgba(255, 255, 255, 0.9);
  }
  /* The two afters carry the accent, the way the slider's after chip does. */
  .gallery--tall figure:nth-child(n+3) figcaption { border-color: rgba(133, 229, 232, 0.45); }
  .gallery--tall figure:nth-child(n+3) .ba-tag { color: var(--accent-bright); }

  /* About's portrait is 4/5 of a full-width column — nearly a whole screen of
     placeholder before any copy. */
  .portrait-placeholder { aspect-ratio: 3 / 2; padding: 1.5rem; }
  .about-hero { gap: 1.75rem; }

  /* One card per row down here, so the label and the price sit on one line
     with the chip pushed to the end, and the row gets a tap-sized height.
     Everything else about these — the surface, the radius, the shadow, the
     chip — is in section 15 and applies at every width. */
  .option {
    align-items: center;
    padding: 0.85rem 1rem;
    min-height: 60px;
  }
  .option__body { flex-direction: row; align-items: center; gap: 0.75rem; }
  .option__label { font-size: 0.96rem; line-height: 1.35; }
  .option__price { margin-left: auto; flex: none; }
  .field-grid { gap: 1rem; }
  /* Centred form. The controls stay full width and their typed text stays
     left-aligned — centring what someone types is the one part of a form you
     should never centre, because the cursor moves as they type. Everything
     around them lines up on the centre: labels, legends, helper text, the
     error summary and the submit. */
  .form-layout { gap: 2rem; }
  .form-card { text-align: center; }
  .form-card .field { text-align: center; }
  /* :not(.option) matters. .option is a <label>, so a bare label rule here
     overrode its display:flex and dropped the checkbox onto its own line
     above the words instead of beside them. */
  .form-card label:not(.option),
  .form-card .fieldset__legend,
  .form-card .form-note { display: block; text-align: center; }

  /* The grey line under every input turned a nine-field form into a wall, so
     it went — first on phones, then everywhere, and the .hint class with it.
     What those lines were carrying is in the labels and the placeholders now:
     the year in "Vehicle year, make and model", the driveway in the address
     placeholder, "optional" in the add-ons legend, the hours in the rail
     beside the form. This is what the label side of that costs. */
  .req-alt { font-weight: 500; color: var(--muted); }

  /* Checkbox beside the words, vertically centred on them. */
  .form-card .option { display: flex; align-items: center; text-align: left; }
  .form-card .option input { align-self: center; margin-top: 0; }
  .form-card .input,
  .form-card .select,
  .form-card .textarea { text-align: left; }
  .form-card .option { text-align: left; }
  .form-card fieldset { text-align: center; }
  .form-foot { display: grid; justify-items: center; text-align: center; }
  .form-foot .btn { width: 100%; }

  /* Interior pages open on the ink banner rather than the hero. Same 1.6rem
     off the nav that the home hero uses, so the top of every page sits at the
     same height. */
  .page-banner {
    padding-block: 1.6rem 2.2rem;
    /* A crisp edge where the ink meets the cream, instead of two flat slabs
       butted together. */
    border-bottom: 1px solid rgba(133, 229, 232, 0.30);
  }
  /* .page-banner__arc is already in the markup on all four interior pages and
     has been display:none since the technical treatment came out. On a phone
     the band is mostly headline and card, and the black around them reads as
     dead space, so the arc comes back as a pool of the card colour low and to
     the right — away from the eyebrow, whose cyan type on a 15% cyan wash is
     the first thing to lose contrast if the ground behind it lifts.
     .page-banner is already position:relative with overflow:hidden, and the
     shell after it is positioned too, so the content stacks above this. */
  .page-banner__arc {
    display: block;
    position: absolute;
    right: -25%;
    bottom: -35%;
    width: 95%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(closest-side, rgba(133, 229, 232, 0.26), rgba(133, 229, 232, 0) 74%);
    pointer-events: none;
  }
  /* The shell inside the banner carries its own clamp(3rem,6vw,5rem) of block
     padding on top of the section's, which is where the ~50px of dead space
     above every interior page title came from. It has to be written at
     .page-banner .shell to outrank the rule setting it. The section owns the
     spacing now; the grid just owns the gap. */
  .page-banner .shell { padding-block: 0; }
  .page-banner__grid  { gap: 1.6rem; }
  .page-banner .eyebrow { margin-bottom: 0.7rem; }
  .page-banner .lede { font-size: 0.97rem; }

  /* The eyebrow was a soft cyan wash with cyan type — legible, but it read as
     a grey blob at this size against all that black. A hairline of the accent
     around it makes it a deliberate object, without lifting the ground behind
     the type. */
  .page-banner .eyebrow {
    border: 1px solid rgba(133, 229, 232, 0.32);
    padding-inline: 0.9rem;
  }

  /* The steps card under the Contact headline carried desktop padding, which
     on a phone made it read as a slab rather than a card. */

  /* The photo banner runs the other way round: the section gives up its
     padding and the shell takes it back, because the picture needs height
     above the type and the type wants to sit near the bottom of it. 8.5rem
     puts the eyebrow just past halfway down a 375px screen, which leaves the
     car readable and still lands the headline and the lede above the fold.

     The hairline the eyebrow picks up two rules above is for a pill on flat
     ink. There is no pill here, so it comes back off. */
  .page-banner--photo { padding-block: 0; }
  .page-banner--photo .shell { padding-block: 8.5rem 2rem; }
  .page-banner--photo .eyebrow { border: 0; padding-inline: 0; }
  .page-banner__facts { gap: 0.4rem 1.2rem; font-size: 0.95rem; }

  /* --- the rail --------------------------------------------------------- */
  /* 52px button + 0.6rem of rail padding top and bottom = 73px. The old 64px
     left the last 9px of every page sitting under the rail. */
  .has-rail { padding-bottom: calc(77px + env(safe-area-inset-bottom)); }
  /* The rail was a stock white circle with a handset in it next to a button —
     the phone-OS default, and it looked borrowed. It is one object now: a
     single pill split down the middle, ink on the left carrying the call in
     the card colour, the card colour on the right carrying the quote in ink.
     The one accent doing both jobs at once, in the one control that follows
     you down every page. */
  .has-rail .action-rail {
    --rail-shadow: 0 2px 6px rgba(10, 13, 14, 0.18), 0 14px 34px -12px rgba(10, 13, 14, 0.6);
    /* Not just position — .action-rail is display:none by default above this
       breakpoint, and this rule is what switches it on. */
    display: block;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    padding: 0.7rem 1.25rem calc(0.7rem + env(safe-area-inset-bottom));
    /* No bar behind it. The pill floats and the page runs underneath, which
       is why its own shadow is deeper than a resting card's — that shadow is
       now the only thing separating it from whatever is scrolling past. */
    background: none;
    border-top: 0;
    pointer-events: none;
  }
  .action-rail__bar { pointer-events: auto; }
  /* Two buttons rather than one split pill, at the proportions the split had:
     the call sized to its own content, the quote taking the rest. */
  .action-rail__bar {
    display: grid; grid-template-columns: auto 1fr;
    gap: 0.5rem;
  }
  .action-rail__bar--single { grid-template-columns: 1fr; }

  .action-rail__call,
  .action-rail__quote {
    display: inline-flex; align-items: center; justify-content: center;
    gap: 0.5rem;
    min-height: 54px;
    font-family: var(--font-display);
    font-size: 1rem; font-weight: 700; letter-spacing: -0.01em;
  }
  .action-rail__call,
  .action-rail__quote { border-radius: 999px; box-shadow: var(--rail-shadow); }
  .action-rail__call {
    padding-inline: 1.15rem 1.25rem;
    background: var(--ink);
    color: var(--accent-bright);
  }
  .action-rail__call svg { width: 18px; height: 18px; }
  .action-rail__call--wide { padding-inline: 1.4rem; }
  .action-rail__quote {
    padding-inline: 1rem;
    background: var(--accent-bright);
    color: var(--accent-ink);
  }
  .action-rail__bar a:active { filter: brightness(0.94); }
}
