/* Hallmark · genre: editorial · design-system: design.md · designed-as-app
 * scope: SYSTEM LAYER ONLY — macrostructure deferred by client decision.
 *   The v2 page structure (section order, layout, copy, nav shape, footer shape)
 *   is client-approved and untouched. The three macrostructure families named in
 *   design.md are agreed but NOT built; do not read this stamp as a claim that
 *   index.html is Photographic or services.html is Long Document. See
 *   design.md § Applied vs deferred.
 * theme: custom, derived from the client's approved brand
 *   paper oklch(15.3% 0.007 258) · accent oklch(56.1% 0.188 261)
 *   axes: paper-band dark / display-style display-condensed / accent-hue cool
 * type: Anton (display, roman) + Instrument Sans (body) — 2 families
 * enrichment: none — the client's own photography carries the page
 * contrast: pass (40–41) · tokens: pass (48) · chrome: pass (47) · honest: pass (46)
 * mobile: pass (34, 49, 50, 51, 55)
 * pre-emit critique: P4 H4 E5 S5 R5 V3   (V3 by design — this pass deliberately
 *   preserves the previous structure, so structural variety is out of scope)
 *
 * AR Auto Detailing. Originally implemented from the Claude Design project
 * "AR Auto Detailing Website" (index.dc.html); the design's inline styles were
 * collected here and its `style-hover` pseudo-attributes became real :hover
 * rules. This pass put that collection on a token system.
 */

:root {
  /* --- Colour ----------------------------------------------------------
     Declared hex-first, OKLCH-second. A browser too old for OKLCH keeps the
     hex through the cascade; everything current gets the wide-gamut value.
     This site has no build step and serves a regional customer base, so a
     silent colour failure is not an acceptable risk. */

  --paper: #0a0c0f;
  --paper: oklch(15.3% 0.007 258);
  --paper-2: #0e1116;
  --paper-2: oklch(17.7% 0.011 261);
  --paper-3: #12161d;
  --paper-3: oklch(19.9% 0.015 262);

  /* The one light panel on the site. Not pure white: #fff on this paper reads
     synthetic next to the blue-tinted neutrals around it. */
  --panel: #f4f6f9;
  --panel: oklch(97.2% 0.005 258);
  --panel-ink: #3a4048;
  --panel-ink: oklch(36.9% 0.016 256);

  --ink-strong: #f2f5fa;
  --ink-strong: oklch(96.9% 0.007 261);
  --ink: #e8eaee;
  --ink: oklch(93.7% 0.006 265);
  --ink-2: #c4cad2;
  --ink-2: oklch(83.7% 0.013 256);
  --muted: #9aa3ad;
  --muted: oklch(71.1% 0.018 251);
  /* Was #5f6873, which measured 3.46:1 on --paper — under the 4.5:1 floor, and
     it was carrying the enquiry form's placeholders. Now 5.4:1. */
  --faint: #7d8794;
  --faint: oklch(62.0% 0.023 255);

  /* --accent is a FILL, never ink: at this lightness it is 4.10:1 on --paper,
     which fails body text. Accent-coloured *text* uses --accent-hi (5.6:1). */
  --accent: #2f6de1;
  --accent: oklch(56.1% 0.188 261);
  --on-accent: #ffffff;
  --on-accent: oklch(100% 0 0);
  --accent-hi: #4d86ef;
  --accent-hi: oklch(63.4% 0.169 261);
  --accent-soft: #7ba6f5;
  --accent-soft: oklch(72.7% 0.125 262);

  --focus: var(--accent-hi);

  --rule: rgba(255, 255, 255, 0.08);
  --edge: rgba(255, 255, 255, 0.25);
  --edge-strong: rgba(255, 255, 255, 0.35);
  --field-edge: rgba(255, 255, 255, 0.12);

  /* Scrims are tokenised rather than written inline so a paper change cannot
     silently desynchronise the eight gradients that sit over photography. */
  --scrim-15: rgba(10, 12, 15, 0.15);
  --scrim-20: rgba(10, 12, 15, 0.2);
  --scrim-30: rgba(10, 12, 15, 0.3);
  --scrim-35: rgba(10, 12, 15, 0.35);
  --scrim-40: rgba(10, 12, 15, 0.4);
  --scrim-45: rgba(10, 12, 15, 0.45);
  --scrim-75: rgba(10, 12, 15, 0.75);
  --scrim-85: rgba(10, 12, 15, 0.85);
  --scrim-88: rgba(10, 12, 15, 0.88);
  --scrim-92: rgba(10, 12, 15, 0.92);
  --scrim-95: rgba(10, 12, 15, 0.95);

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

  --font-display: Anton, sans-serif;
  --font-body: "Instrument Sans", sans-serif;

  --text-2xs: 12px;
  --text-xs: 13px;
  --text-sm: 14px;
  --text-md: 15px;
  --text-lg: 16px;
  --text-xl: 17px;
  --text-2xl: 20px;
  --text-3xl: 22px;
  --text-4xl: 24px;
  --text-5xl: 30px;

  --display-hero: clamp(44px, 8vw, 104px);
  --display-page: clamp(38px, 6vw, 72px);
  --display-section: clamp(30px, 4vw, 46px);
  --display-sub: clamp(28px, 3.6vw, 42px);
  --display-row: clamp(28px, 3.6vw, 40px);

  /* Uppercase glyphs have no descenders, so at sub-1.0 leading the cap-tops of
     a wrapped line collide with the line above it. Anton is worse than most. */
  --lh-display: 1.02;

  --track-btn: 2px;
  --track-label: 1.5px;
  --track-eyebrow: 2.5px;

  /* --- Space ------------------------------------------------------------
     Twelve steps. The v2 sheet had no scale — values ran 6, 7, 10, 11, 13, 14,
     15, 18, 22, 26, 30, 34, 44px. Each was snapped to the nearest step here;
     maximum movement is 4px and most moved 1–2px. */

  --space-3xs: 4px;
  --space-2xs: 8px;
  --space-xs: 12px;
  --space-sm: 16px;
  --space-md: 20px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-2xl: 40px;
  --space-3xl: 48px;
  --space-4xl: 64px;
  --space-5xl: 88px;
  --space-6xl: 120px;

  /* Section cadence. Deliberately NOT part of the spacing scale — these are
     viewport-responsive rhythm, not increments. */
  --shell: 1200px;
  --shell-wide: 1280px;
  --gutter: clamp(20px, 5vw, 40px);
  --block: clamp(64px, 10vh, 112px);
  --block-2: clamp(64px, 10vh, 100px);
  --block-3: clamp(48px, 9vh, 88px);

  /* Height of the fixed header, used to keep anchored sections clear of it.
     Tracks .brand__logo: the v3 logo bump of 30px -> 40px added 10px here. */
  --nav-h: 138px;

  /* --- Motion ------------------------------------------------------------ */

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 120ms;
  --dur: 200ms;

  --radius-card: 4px;
  --radius-btn: 3px;
  --radius-pill: 999px;
}

/* `clip`, not `hidden`: clip preserves position: fixed on descendants, and the
   nav depends on that. Without this the 320px viewport scrolled sideways. */
html,
body {
  margin: 0;
  padding: 0;
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  scroll-behavior: smooth;
}

/* The nav is fixed, so anchored sections must stop clear of it. Since the brand
   moved to its own centred row the header is roughly 100px tall; --nav-h carries
   the measurement so the two cannot drift apart silently. */
[id] {
  scroll-margin-top: var(--nav-h);
}

/* Keyboard focus must stay visible: removing the ring is an accessibility
   failure Lighthouse flags, so it is replaced rather than deleted. Never
   transitioned — a ring that fades in leaves keyboard users with no indicator
   at the moment they need one. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--space-xs) var(--space-md);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}

.skip-link:focus {
  left: var(--space-2xs);
  top: var(--space-2xs);
  color: var(--on-accent);
}

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

a {
  color: var(--accent-hi);
  text-decoration: none;
}

a:hover {
  color: var(--accent-soft);
}

::selection {
  background: var(--accent);
  color: var(--on-accent);
}

.accent {
  color: var(--accent-hi);
}

/* --- Brand lockup ------------------------------------------------------- */

/* The artwork already reads "AR AUTO DETAILING", so it replaces the type
   lockup instead of sitting beside it. Sized by height with an automatic width:
   the width/height attributes on the tag give the browser the aspect ratio, so
   the space is still reserved before the file arrives and nothing shifts.

   40px is past the ceiling, deliberately. The logo master is 206px wide, which
   leaves only 65px of artwork height, so 30px was the largest exactly-sharp
   lockup on a 2x screen. The client asked for a bigger logo in v3 and accepted
   the trade: at 40px the mark is drawn 124x40, so it is upscaled about 1.23x on
   a 2x screen and 1.85x on a 3x phone, and is mildly soft on both. _fit() never
   upscales, so no rebuild fixes this — it needs a vector or a 1000px export of
   the logo, at which point only logo.jpg changes and these sizes stay put. */
.brand__logo {
  display: block;
  width: auto;
  height: 40px;
}

.brand__logo--sm {
  height: var(--space-xl);
}

.nav__brand:hover .brand__logo {
  opacity: 0.82;
}

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

/* nowrap: a button label that breaks onto two lines reads as a styling error
   rather than a deliberate line. "What is a ceramic coating?" came within
   ~10px of wrapping at 320px. */
.btn {
  display: inline-block;
  padding: var(--space-sm) var(--space-xl);
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
  white-space: nowrap;
  transition: background-color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}

.btn:active {
  transform: translateY(1px);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.btn--primary {
  background: var(--accent);
  color: var(--on-accent);
}

.btn--primary:hover {
  background: var(--accent-hi);
  color: var(--on-accent);
}

.btn--primary:disabled:hover,
.btn--primary[aria-disabled="true"]:hover {
  background: var(--accent);
}

/* `background` is explicit because this modifier is now used on a <button> as
   well as on links, and a button carries the browser's own grey buttonface
   background until something replaces it: white text on it is unreadable. */
.btn--outline {
  border-color: var(--edge);
  background: transparent;
  color: var(--ink-strong);
}

.btn--outline-scrim {
  border-color: var(--edge-strong);
  background: var(--scrim-30);
  color: var(--ink-strong);
}

.btn--outline:hover,
.btn--outline-scrim:hover {
  border-color: var(--accent-hi);
  color: var(--accent-hi);
}

.btn--outline:disabled:hover,
.btn--outline[aria-disabled="true"]:hover {
  border-color: var(--edge);
  color: var(--ink-strong);
}

.btn--compact {
  padding: var(--space-xs) var(--space-md);
  letter-spacing: var(--track-label);
}

/* --- Nav ---------------------------------------------------------------- */

/* The brand sits on its own centred row above the links rather than being
   centred between them. A three-column "links | logo | actions" bar is the
   other way to centre a logo, but it only stays centred while both flanks
   happen to be the same width, and it has nowhere to go on a phone. Stacking
   is centred at every viewport and needs no breakpoint to hold it together. */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: grid;
  justify-items: center;
  gap: var(--space-xs);
  padding: var(--space-xs) clamp(var(--space-sm), 4vw, var(--space-xl));
  background: var(--scrim-85);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--rule);
}

.nav__brand {
  display: flex;
  align-items: center;
  justify-content: center;
}

.nav__links {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: clamp(var(--space-sm), 2.5vw, var(--space-xl));
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 1.8px;
  text-transform: uppercase;
}

/* On a phone the row is four links plus a button, which wraps to two lines and
   makes the fixed header tall enough to eat the top of every page. The button
   is the one item that is pure duplication: Contact sits immediately beside it
   and goes to the same place.

   NOTE (audit, open): this means the primary CTA disappears exactly where it
   matters most. Resolving it properly is a nav-structure change and belongs to
   the deferred structural pass — see design.md § Applied vs deferred. The
   --nav-h bump below keeps anchor offsets honest in the meantime. */
@media (max-width: 600px) {
  .nav__links .btn--compact {
    display: none;
  }
}

/* Four links wrap to two rows well before 320px, which makes the fixed header
   taller than --nav-h and pushes anchored sections underneath it. */
@media (max-width: 420px) {
  :root {
    --nav-h: 174px;
  }
}

.nav__link {
  color: var(--muted);
  transition: color var(--dur) var(--ease-out);
}

.nav__link--active {
  color: var(--ink-strong);
}

.nav__link:hover {
  color: var(--accent-hi);
}

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

.hero {
  position: relative;
  min-height: 92vh;
  display: flex;
  align-items: flex-end;
  background-image: linear-gradient(
      180deg,
      var(--scrim-35) 0%,
      var(--scrim-15) 45%,
      var(--scrim-92) 100%
    ),
    url("images/car-detailing-lamborghini-huracan-westbrook-qld.webp");
  background-size: cover;
  background-position: center 62%;
}

.hero__inner {
  width: 100%;
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--space-6xl) var(--gutter) var(--block-3);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  margin-bottom: var(--space-lg);
  padding: var(--space-2xs) var(--space-sm);
  border: 1px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--scrim-40);
  font-size: var(--text-2xs);
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
  color: var(--ink-2);
}

.badge__dot {
  display: inline-block;
  width: var(--space-2xs);
  height: var(--space-2xs);
  border-radius: 50%;
  background: var(--accent-hi);
}

/* overflow-wrap: long compound words (a model name, an uppercase brand) have no
   break opportunity at display sizes and would otherwise run off a 320px
   screen. min-width: 0 lets the element shrink inside a flex/grid parent. */
.hero__title {
  margin: 0 0 var(--space-md);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-hero);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

/* The v4 positioning line, between the h1 and the lede. Display face so it reads
   as part of the lockup rather than as the first line of body copy, but a tier
   down in size and colour so it never competes with the h1 above it. */
.hero__tag {
  margin: 0 0 var(--space-md);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
  color: var(--accent-hi);
}

.hero__lede {
  max-width: 560px;
  margin: 0 0 var(--space-xl);
  font-size: clamp(var(--text-lg), 1.6vw, 19px);
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}

.hero__actions {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

/* --- Section shell ------------------------------------------------------ */

.section {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--block) var(--gutter);
}

.section--flush-top {
  padding-top: 0;
}

.section--wide {
  max-width: var(--shell-wide);
}

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
  margin-bottom: var(--space-3xl);
}

.section__head--tight {
  margin-bottom: var(--space-xl);
}

.section__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-section);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.section__link {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
  white-space: nowrap;
}

/* --- Service cards ------------------------------------------------------ */

/* Explicit counts rather than auto-fit. There are exactly four services and
   auto-fit could never fit four 290px columns inside the 1200px shell, so it
   always broke to three plus a stranded fourth. Stepping 4 -> 2 -> 1 keeps the
   set reading as a set, which matters more now that the order is deliberate. */
.services {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-sm);
}

@media (max-width: 1080px) {
  .services {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .services {
    grid-template-columns: minmax(0, 1fr);
  }
}

.service-card {
  display: block;
  padding: var(--space-xl) var(--space-lg);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  color: inherit;
  transition: background-color var(--dur) var(--ease-out);
}

.service-card:hover {
  background: var(--paper-3);
  color: inherit;
}

/* --accent-hi, not --accent: the numerals are 15px regular, and --accent
   measures 3.99:1 on this surface. */
.service-card__num {
  margin-bottom: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--text-md);
  letter-spacing: var(--track-btn);
  color: var(--accent-hi);
}

.service-card__title {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-3xl);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.service-card__body {
  margin: 0;
  font-size: var(--text-md);
  line-height: 1.6;
  color: var(--muted);
}

/* --- Full-bleed image band ---------------------------------------------- */

.band {
  position: relative;
  min-height: 56vh;
  display: flex;
  align-items: center;
  background-image: linear-gradient(
      90deg,
      var(--scrim-88) 0%,
      var(--scrim-45) 60%,
      var(--scrim-20) 100%
    ),
    url("images/detailing-bay-audi-rs3-westbrook-qld.webp");
  background-size: cover;
  background-position: center;
}

.band__inner {
  width: 100%;
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--block-3) var(--gutter);
}

.band__copy {
  max-width: 520px;
}

.band__eyebrow {
  margin-bottom: var(--space-sm);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--accent-hi);
}

.band__title {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-sub);
  line-height: 1.1;
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.band__text {
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1.7;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* --- Pillars ------------------------------------------------------------ */

.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: clamp(var(--space-xl), 4vw, var(--space-3xl));
}

.pillar__rule {
  width: var(--space-xl);
  height: 3px;
  margin-bottom: var(--space-md);
  background: var(--accent);
}

.pillar__title {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-2xl);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.pillar__body {
  margin: 0;
  font-size: var(--text-md);
  line-height: 1.7;
  color: var(--muted);
}

/* --- Recent work -------------------------------------------------------- */

.work {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: var(--space-sm);
}

.work__item {
  display: block;
  overflow: hidden;
  border-radius: var(--radius-card);
}

.work__img {
  display: block;
  width: 100%;
  height: 280px;
  object-fit: cover;
  transition: transform var(--dur) var(--ease-out);
}

/* The zoom lives here and NOT on .gallery__cell: this one is a real link, so
   the hover is promising something that actually happens. */
.work__item:hover .work__img,
.work__item:focus-visible .work__img {
  transform: scale(1.03);
}

/* --- Closing CTA -------------------------------------------------------- */

.cta {
  border-top: 1px solid var(--rule);
  background: var(--paper-2);
}

/* Used where the section above is already the raised surface, so the two do
   not merge into one undifferentiated slab. */
.cta--plain {
  background: transparent;
}

.cta__inner {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--block-3) var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xl);
  flex-wrap: wrap;
}

.cta__title {
  margin: 0 0 var(--space-2xs);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-sub);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.cta__text {
  margin: 0;
  font-size: var(--text-lg);
  color: var(--muted);
}

.cta__actions {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

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

.footer {
  border-top: 1px solid var(--rule);
}

.footer__inner {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--space-3xl) var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
}

.footer__brand {
  display: flex;
  align-items: center;
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-lg);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}

.footer__link {
  color: var(--muted);
  white-space: nowrap;
  transition: color var(--dur) var(--ease-out);
}

.footer__link:hover {
  color: var(--accent-hi);
}

.footer__meta {
  font-size: var(--text-xs);
  color: var(--faint);
}

/* --- Inner-page hero ---------------------------------------------------- */

.page-hero {
  padding: clamp(130px, 20vh, 180px) 0 var(--block-3);
}

.page-hero--image {
  position: relative;
  padding: clamp(140px, 22vh, 200px) 0 var(--block-3);
  background-image: linear-gradient(
      180deg,
      var(--scrim-75) 0%,
      var(--scrim-95) 100%
    ),
    url("images/car-wash-foam-pre-wash-westbrook-qld.webp");
  background-size: cover;
  background-position: center 40%;
}

.page-hero__inner {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.page-hero__inner--wide {
  max-width: var(--shell-wide);
}

.eyebrow {
  margin-bottom: var(--space-xs);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--accent-hi);
}

.page-hero__title {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-page);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.page-hero__lede {
  max-width: 560px;
  margin: 0;
  font-size: var(--text-xl);
  line-height: 1.65;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* --- Service rows ------------------------------------------------------- */

/* min() on the track floor: a bare minmax(320px, 1fr) is wider than the content
   box at a 320px viewport, which pushed the whole page sideways. */
.svc {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--block-2) var(--gutter);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: clamp(var(--space-xl), 5vw, var(--space-4xl));
  align-items: center;
}

.svc-band {
  border-top: 1px solid var(--rule);
  background: var(--paper-2);
}

.svc__media {
  overflow: hidden;
  border-radius: var(--radius-card);
}

.svc__img {
  width: 100%;
  height: clamp(280px, 40vw, 420px);
  object-fit: cover;
  display: block;
}

.svc__img--tall {
  height: clamp(320px, 44vw, 480px);
  object-position: center 70%;
}

.svc__num {
  margin-bottom: var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--text-md);
  letter-spacing: var(--track-btn);
  color: var(--accent-hi);
}

.svc__title {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-row);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.svc__lede {
  margin: 0 0 var(--space-lg);
  font-size: var(--text-lg);
  line-height: 1.7;
  color: var(--muted);
  text-wrap: pretty;
}

.svc__list {
  display: grid;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-md);
  line-height: 1.55;
  color: var(--ink-2);
}

.svc__list li {
  position: relative;
  padding-left: var(--space-lg);
}

/* The design drew these bullets as dash glyphs. Drawing them in CSS instead
   keeps them out of the text layer, where screen readers would announce them. */
.svc__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: var(--space-xs);
  height: 2px;
  background: var(--accent-hi);
}

.svc__cta {
  display: inline-block;
  margin-top: var(--space-lg);
  padding: var(--space-xs) var(--space-lg);
  font-size: var(--text-xs);
}

/* --- Ceramic explainer --------------------------------------------------- */

/* The client asked for this after seeing a competitor do it with a video
   background, and said in the same breath that the competitor's site was "a
   bit much". So it is the same shell as every other section: type, a rule, and
   the three-column pillar grid already used on the home page. No new colours,
   no imagery, nothing that moves. */
.explainer {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--block-2) var(--gutter);
}

.explainer__title {
  margin: 0 0 var(--space-sm);
  max-width: 20ch;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-row);
  line-height: 1.06;
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.explainer__lede {
  max-width: 68ch;
  margin: 0 0 var(--block-3);
  font-size: var(--text-xl);
  line-height: 1.7;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* Body copy inside the explainer, between the lede and a grid. Narrower than the
   lede and a tier quieter, so the section still reads top-down. */
.explainer__body {
  max-width: 74ch;
  margin: 0 0 var(--block-3);
  font-size: var(--text-md);
  line-height: 1.7;
  color: var(--muted);
  text-wrap: pretty;
}

/* Mid-section eyebrow. The section already owns its h2, and the cards below own
   h3, so these labels are deliberately not headings: making them one would put a
   second h2 inside a section that has a single subject. */
.explainer__sub {
  margin-bottom: var(--space-md);
}

/* Six benefits, three across. Explicit columns rather than auto-fit: six cards
   are meant to read as 3 x 2, and auto-fit would give four and a stranded two at
   this shell width. No icons, by the design system's no-enrichment rule. */
.benefits {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-lg);
  margin-bottom: var(--block-3);
}

.benefit {
  padding: var(--space-lg);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
}

.benefit__title {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-2xl);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
  min-width: 0;
}

.benefit__body {
  margin: 0;
  font-size: var(--text-md);
  line-height: 1.7;
  color: var(--muted);
}

@media (min-width: 560px) {
  .benefits {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 900px) {
  .benefits {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* The Magnum range: one strip of five on a wide screen, wrapping down to one on
   a phone. This is supplier product photography rather than the client's own
   work, which is why it is small, uniform and boxed: it reads as the products
   they stock, never as a gallery of their cars. */
.range {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  gap: var(--space-lg);
  margin: 0 0 var(--space-xl);
  padding: 0;
  list-style: none;
}

.range__item {
  display: flex;
  flex-direction: column;
}

/* Fixed 3:4 box. The five masters do not share an aspect ratio (Luminous X is
   considerably taller), so the crop happens here and each file keeps its own
   real dimensions in the markup. */
.range__img {
  width: 100%;
  aspect-ratio: 3 / 4;
  height: auto;
  object-fit: cover;
  display: block;
  margin-bottom: var(--space-sm);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
}

.range__name {
  margin: 0 0 var(--space-2xs);
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: 1.4;
  color: var(--ink);
  overflow-wrap: anywhere;
  min-width: 0;
}

.range__note {
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--faint);
}

/* The accreditation, and the one line saying whose photographs those are. Ruled
   off above rather than boxed: it is a footnote to the range, not a claim
   standing on its own. */
.range__accred {
  max-width: 74ch;
  margin: 0 0 var(--block-3);
  padding-top: var(--space-md);
  border-top: 1px solid var(--rule);
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--muted);
}

.range__accred a {
  color: var(--accent-hi);
  transition: color var(--dur) var(--ease-out);
}

.range__accred a:hover {
  color: var(--ink-strong);
}

/* Sits under the grid as the plain-language caveat. Bordered rather than
   boxed: a coloured callout would read as a warning, and it is not one. */
.explainer__note {
  max-width: 74ch;
  margin: 0;
  padding-left: var(--space-md);
  border-left: 2px solid var(--accent);
  font-size: var(--text-md);
  line-height: 1.7;
  color: var(--muted);
  text-wrap: pretty;
}

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

/* A uniform catalogue grid: every tile is the same 4:3 box, so a column's
   height is only its tile count and the three columns end level by
   construction. The previous version let each image keep its own aspect ratio,
   which made column height a running total of whatever ratios landed in it: the
   close-ups column had reached 9.0 column-widths against 4.9 and 5.8 either
   side, and every photo added made it worse, because the outer columns were
   full.

   Three fixed columns, each an explicit container, because the columns carry
   meaning: left-facing cars, close-ups, right-facing cars. An auto-fill grid
   would derive its column count from the viewport and reshuffle cells, either
   of which scatters a car out of the column it belongs to. */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-sm);
  align-items: start;
}

.gallery__col {
  display: grid;
  gap: var(--space-sm);
  align-content: start;
}

/* Each cell is a real link to the full frame, so it is an <a>: with the script
   it opens the lightbox, and without it the photograph opens on its own. That
   is also what earns the hover zoom, which this rule refused while the cells
   were plain divs promising a click that did not exist. */
.gallery__cell {
  display: block;
  overflow: hidden;
  border-radius: var(--radius-card);
  background: var(--paper-2);
}

/* The tiles are built pre-cropped to 4:3, so object-fit only has to absorb
   sub-pixel rounding. aspect-ratio holds the box open before the image lands,
   on top of the width/height attributes. */
.gallery__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform var(--dur) var(--ease-out);
}

.gallery__cell:hover .gallery__img,
.gallery__cell:focus-visible .gallery__img {
  transform: scale(1.03);
}

/* Below three columns the directional reading cannot survive, so the wrappers
   dissolve and the cells reflow into two. Two columns stay flush for the same
   reason three do: the tiles are all one size.

   It stays at two the whole way down rather than dropping to one. A single
   column of 27 photos is an 8000px scroll on a phone, and tapping a tile now
   enlarges it, which is exactly what makes a small tile worth having. */
@media (max-width: 900px) {
  .gallery {
    grid-template-columns: repeat(2, 1fr);
  }

  .gallery__col {
    display: contents;
  }
}

/* --- Lightbox ----------------------------------------------------------- */

/* Built by gallery.js, so none of this markup is in the HTML. A native <dialog>
   opened with showModal() brings focus trapping, Escape and inertness with it,
   which is most of what an accessible overlay has to get right. */
/* dvh, with vh underneath it for browsers that do not know the dynamic units:
   on a phone the difference is the address bar, and being wrong by that much is
   better than falling back to the UA dialog's shrink-to-fit height. */
.lightbox {
  width: 100vw;
  max-width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-height: 100vh;
  max-height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--scrim-95);
  color: var(--ink);
  overflow: hidden;
}

.lightbox::backdrop {
  background: var(--scrim-95);
}

/* A modal <dialog> makes the page inert but does not stop it scrolling behind
   the overlay, which on a phone reads as the photo drifting. gallery.js puts
   this class on <html> for the life of the dialog. */
.has-lightbox,
.has-lightbox body {
  overflow: hidden;
}

/* box-sizing is deliberately not globalised on this site (see design.md), so a
   full-height box that also has padding has to opt in locally. Without this the
   padding is added to the 100% and the caption and buttons fall off the bottom
   of the viewport. */
.lightbox__inner {
  box-sizing: border-box;
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md) var(--space-md);
}

.lightbox__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.lightbox__count {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* min-height: 0 lets the image shrink inside the grid row instead of forcing
   the row taller than the viewport. */
.lightbox__stage {
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox__img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--radius-card);
}

/* No caption. The description lives on the image's alt attribute, where a
   screen reader gets it, and is not printed under a photograph the visitor is
   already looking at. */
.lightbox__foot {
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox__nav {
  display: flex;
  gap: var(--space-2xs);
  flex-shrink: 0;
}

/* Text labels, not icon glyphs: this site has no icon set and inventing one for
   three controls would be the only enrichment on it. */
.lightbox__btn {
  padding: var(--space-2xs) var(--space-sm);
  border: 1px solid var(--edge);
  border-radius: var(--radius-btn);
  background: transparent;
  color: var(--ink-strong);
  font-family: inherit;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out);
}

.lightbox__btn:hover {
  border-color: var(--accent-hi);
  color: var(--accent-hi);
}

/* Pushed to the edges on a phone so each button sits under a thumb rather than
   both of them in the middle. */
@media (max-width: 560px) {
  .lightbox__foot {
    justify-content: space-between;
  }

  .lightbox__nav {
    flex: 1;
    justify-content: space-between;
  }
}

/* --- Contact ------------------------------------------------------------ */

.contact-grid {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--gutter) var(--block);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: clamp(var(--space-xl), 5vw, var(--space-3xl));
  align-items: stretch;
}

/* Flex, not grid, and stretched to the row height rather than sized by its own
   content: that is what lets .logo-strip take margin-top:auto below and finish
   flush with the bottom of the enquiry form beside it. The two boxes used to be
   in unrelated grids, so their bottom edges landed wherever the content totals
   happened to put them. */
.contact-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.card {
  padding: var(--space-lg);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
}

.card__label {
  margin-bottom: var(--space-2xs);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--track-btn);
  text-transform: uppercase;
  color: var(--accent-hi);
}

.card__label--spaced {
  margin-bottom: var(--space-xs);
}

.card__phone {
  font-family: var(--font-display);
  font-size: var(--text-5xl);
  letter-spacing: 1px;
  color: var(--ink-strong);
  transition: color var(--dur) var(--ease-out);
}

.card__phone:hover {
  color: var(--accent-hi);
}

/* Email is the third channel, behind the DMs and the phone, so it sits under the
   number at body size instead of competing with it. display:block because both
   are anchors and would otherwise share a line. */
.card__email {
  display: block;
  margin-top: var(--space-2xs);
  font-size: var(--text-md);
  color: var(--muted);
  overflow-wrap: anywhere;
  transition: color var(--dur) var(--ease-out);
}

.card__email:hover {
  color: var(--accent-hi);
}

.card__note {
  margin: var(--space-xs) 0 0;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--muted);
}

.card__address {
  margin: 0;
  font-size: var(--text-md);
  line-height: 1.7;
  color: var(--ink);
}

.card__address span {
  color: var(--muted);
}

.socials {
  display: grid;
  gap: var(--space-xs);
  font-size: var(--text-md);
}

.social-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-xs);
  color: var(--ink);
  transition: color var(--dur) var(--ease-out);
}

.social-row:hover {
  color: var(--accent-hi);
}

.social-row span:last-child {
  color: var(--muted);
}

/* margin-top:auto pins this to the foot of the stretched column so its bottom
   edge lines up with the enquiry form's. Stretching the strip itself would do
   the same job, but --panel is the one light surface on the site and inflating
   it to fill the gap would make it the loudest thing on the page. Padding and
   border match .card and .enquiry so all four boxes share one inner edge. */
.logo-strip {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-lg);
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
}

.logo-strip img {
  width: 80px;
  height: 80px;
  object-fit: contain;
  display: block;
}

.logo-strip p {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--panel-ink);
}

/* --- Enquiry form ------------------------------------------------------- */

.enquiry {
  padding: clamp(var(--space-lg), 3.5vw, var(--space-xl));
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
}

.enquiry__title {
  margin: 0 0 var(--space-2xs);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-4xl);
  line-height: var(--lh-display);
  text-transform: uppercase;
  color: var(--ink-strong);
}

.enquiry__note {
  margin: 0 0 var(--space-lg);
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--muted);
}

.enquiry__fields {
  display: grid;
  gap: var(--space-sm);
}

.enquiry__pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));
  gap: var(--space-sm);
}

/* The field's own visible label. These were .visually-hidden, which left the
   placeholder as the only thing naming the field — and a placeholder vanishes
   the moment the customer starts typing. */
.field-label {
  display: block;
  margin-bottom: var(--space-3xs);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
}

.field {
  width: 100%;
  box-sizing: border-box;
  padding: var(--space-xs) var(--space-sm);
  background: var(--paper);
  border: 1px solid var(--field-edge);
  border-radius: var(--radius-btn);
  color: var(--ink);
  font-size: var(--text-md);
  font-family: inherit;
  transition: border-color var(--dur) var(--ease-out);
}

textarea.field {
  resize: vertical;
}

.field::placeholder {
  color: var(--faint);
}

/* An outline, not a box-shadow glow: the old 3px rgba(47,109,225,0.28) ring
   composited to 1.39:1 against the field, which is not an indicator. Border
   width never changes between states, so nothing shifts. */
.field:focus-visible {
  border-color: var(--accent);
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

.field:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Two destinations, side by side and equally reachable. The client's point was
   that a fair share of their customers are on Facebook and would never open
   Instagram, so this is not a primary with a fallback tucked under it. */
.enquiry__send {
  display: flex;
  gap: var(--space-xs);
  flex-wrap: wrap;
}

/* No `border: none` here: .btn already replaces the browser's button border
   with a transparent 1px one, and zeroing it would flatten .btn--outline. */
.enquiry__submit {
  flex: 1 1 190px;
  padding: var(--space-sm) var(--space-md);
  cursor: pointer;
  font-family: inherit;
  text-align: center;
}

/* Reserved height so an appearing status message cannot push the page down. */
.enquiry__status {
  min-height: 1lh;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--accent-soft);
}

/* --- 404 ---------------------------------------------------------------- */

.notfound {
  min-height: 72vh;
  display: flex;
  align-items: center;
}

.notfound__inner {
  max-width: var(--shell);
  margin: 0 auto;
  padding: clamp(140px, 22vh, 200px) var(--gutter) var(--block);
}

.notfound .hero__actions {
  margin-top: var(--space-xl);
}

@media (prefers-reduced-motion: reduce) {
  html,
  body {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }

  .work__img {
    transition: none;
  }

  .work__item:hover .work__img,
  .work__item:focus-visible .work__img {
    transform: none;
  }

  .gallery__img {
    transition: none;
  }

  .gallery__cell:hover .gallery__img,
  .gallery__cell:focus-visible .gallery__img {
    transform: none;
  }

  .btn:active {
    transform: none;
  }
}
