/* ==========================================================================
   05 WHY US / ABOUT — split. Two photographs on the left, one overlapping the
   other; argument and credential rows on the right. 2 images.
   ========================================================================== */

/* the grid breaks below reach for the viewport edge; the section clips them so
   the desktop scrollbar can never turn a deliberate hang into a scrollbar */
.whyus { background: var(--surface-alt); overflow: hidden; }

.whyus__inner {
  display: grid;
  gap: var(--space-stack);
  align-items: center;
}

/* --- the photo pair ----------------------------------------------------- */
.whyus__figs { position: relative; }

/* clip-path removes box-shadow outright. On the near-black ground the cast
   shadow was doing nothing anyway — the surface step and the bezel carry it. */
.whyus__fig-main {
  aspect-ratio: var(--ratio-tall);
  border-radius: var(--radius-card);
  clip-path: var(--chamfer-clip);
}
.whyus__fig-main::after { background: var(--chamfer-edge), var(--overlay-media); }

/* One page's main frame is a 3:2 exterior. The portrait crop threw away the
   car, the driveway and the sun the paragraph beside it argues about and left
   a headlight on a lawn, so that page states its own ratio rather than the
   component assuming every main frame is a portrait bay shot. */
.whyus--landscape .whyus__fig-main { aspect-ratio: var(--ratio-bleed); }

/* The sub frame overlaps the main frame's block-end inline-start corner, which
   is the corner every .chip owns. On a landscape main frame the chip is wide
   relative to the frame and the sub cut its last word off at 390, so here the
   chip reads from the block-start. From --bp-lg the frame is wide enough that
   nothing reaches the chip, and the stamp takes the block-start corner. */
.whyus--landscape .whyus__fig-main .chip {
  inset-block-start: var(--chip-offset);
  inset-block-end: auto;
}

.whyus__fig-sub {
  aspect-ratio: var(--ratio-card);
  width: 58%;
  border-radius: var(--radius-media);
  border: var(--border-width-bar) solid var(--surface-alt);
  clip-path: var(--chamfer-clip);
  margin-block-start: calc(var(--space-3xl) * -1);
  margin-inline-start: auto;
  margin-inline-end: calc(var(--gutter) * -1);
  position: relative;
}

/* Narrow, the stamp is a block in the figures' own flow. Absolutely placed it
   landed on the same bottom-inline-start corner every .chip uses, so it covered
   the main frame's chip and hung past the viewport edge at 390. It only becomes
   an overlay once there is a column to overlay — see the --bp-lg block. */
.whyus__stamp {
  z-index: var(--z-raised);
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  width: max-content;
  max-width: 100%;
  margin-block-start: var(--space-md);
  padding: var(--space-xs) var(--space-sm);
  border-radius: var(--radius-inset);
  background: var(--surface-accent);
  color: var(--text-on-accent);
  box-shadow: var(--shadow-card);
}
.whyus__fig-sub::after { background: var(--chamfer-edge), var(--overlay-media); }

.whyus__stamp-fig {
  font-family: var(--font-mono);
  font-size: var(--text-h3);
  font-weight: var(--weight-bold);
  line-height: var(--leading-flat);
  letter-spacing: var(--tracking-mono-tight);
}
.whyus__stamp-label {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-on-accent-muted);
}

/* --- the argument -------------------------------------------------------- */
.whyus__body { display: flex; flex-direction: column; gap: var(--space-md); }

.whyus__prose {
  font-size: var(--text-body);
  line-height: var(--leading-relaxed);
  color: var(--text-muted);
  max-width: var(--width-measure);
}

/* base.css strips link styling site-wide, so an in-prose link here renders as
   plain text. Same construction as .refusal__why a — one underline in accent
   ink, one colour change on hover. */
.whyus__prose a {
  color: var(--text-secondary);
  text-decoration: underline;
  text-decoration-color: var(--border-accent);
  text-underline-offset: var(--space-3xs);
  transition: color var(--dur-fast) var(--ease-state);
}
.whyus__prose a:hover { color: var(--text-primary); }

/* --- the readings ---------------------------------------------------------
   The block-02 prose column runs to about half the height of the photograph
   pair beside it, which left a bare quadrant the width of a card. These are
   the same figures the section already argues with, set as instrument rows so
   the column carries data to its foot instead of ground. */
.whyus__readings { display: grid; gap: var(--space-3xs); }

.whyus__reading {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-sm);
  align-items: baseline;
  padding-block: var(--space-2xs);
  background: var(--tick-rule-fine);
  background-position: bottom;
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-mono-label);
  text-transform: uppercase;
  color: var(--text-faint);
}
.whyus__reading-val {
  font-size: var(--text-spec);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-mono-tight);
  color: var(--text-secondary);
}
.whyus__reading-val b { color: var(--text-accent); font-weight: var(--weight-medium); }

.whyus__rows { display: grid; gap: var(--space-xs); }

.whyus__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-sm);
  align-items: center;
  --chamfer: var(--chamfer-sm);
  padding: var(--space-xs);
  border: var(--border-width-hair) solid var(--border-hairline);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
  background: var(--chamfer-edge), var(--surface-page);
  transition: border-color var(--dur-fast) var(--ease-state), transform var(--dur-fast) var(--ease-lift);
}
.whyus__row:hover { border-color: var(--border-accent-soft); transform: translate3d(var(--space-3xs), 0, 0); }

.whyus__row-title {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}
.whyus__row-desc {
  display: block;
  font-size: var(--text-caption);
  line-height: var(--leading-snug);
  color: var(--text-muted);
}

@media (min-width: 900px) {
  /* the photographs take the narrow track whichever side they are on: in the
     wide one the pair runs half again the height of the prose beside it and
     opens a bare cell the size of a card */
  .whyus__inner { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--space-3xl); }
  /* Which side the photographs are on is stated on the container as
     --figs-end, not detected with :has(). Firefox before 121 — the 115 ESR on
     managed desktops included — treats a rule containing :has() as invalid and
     drops it, and the four pages that put the pair in the END column would get
     the START-column track sizing: the photographs in the 7fr track, running
     half again the height of the prose beside them, opening exactly the bare
     cell this rule exists to close. */
  .whyus__inner--figs-end { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .whyus__rows { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* GRID BREAK #1. calc(var(--gutter) * -1) alone only reached the container's
     own padding edge, which is why the break was invisible: the sub figure's
     right edge landed exactly on .wrap--wide's. The second term is the wrap's
     outer margin, so the object carries on to the viewport edge and the break
     is the gutter plus that margin wide.
     Which object breaks follows which side the photographs are on, because the
     sub figure sits at the pair's end edge and can only reach the outside of
     the page from the end column. From the start column the stamp does it. */
  .whyus__inner {
    /* gutter first, then as much of the wrap's own outer margin as there is,
       capped so the break never runs off the viewport and gets clipped */
    /* 100vw is the viewport INCLUDING the classic scrollbar, and <body> stops
       at --width-page, so the wrap's outer margin is measured from the
       narrower of the two. Uncapped, a 2,560px screen computed a 500px reach
       against a real 180px one and the object was cut off by the section's
       own clip. The remaining error is half a scrollbar, ~8px, and there is
       no CSS unit that reports the viewport without it. */
    --whyus-break: calc(var(--gutter) * -1 - max(0px, min(var(--space-3xl), (min(100vw, var(--width-page)) - var(--width-wide)) / 2)));
  }
  /* sits on the figure pair, not inside either media box — .media clips */
  .whyus__stamp {
    position: absolute;
    inset-block-end: var(--space-2xl);
    margin-block-start: 0;
  }
  .whyus__inner > .whyus__figs:last-child .whyus__fig-sub { margin-inline-end: var(--whyus-break); }
  .whyus__inner > .whyus__figs:first-child .whyus__stamp { inset-inline-start: var(--whyus-break); }
  /* From the end column the sub figure carries the break, so the stamp has no
     structural job out there: at --whyus-break it floated in the gutter between
     the prose and the photographs, touching neither. It moves onto the main
     frame's free corner instead — block-start, because every .chip already owns
     block-end-inline-start and the sub figure owns the bottom of the pair, and
     because that corner is on the frame whatever ratio the frame is cut to. */
  .whyus__inner > .whyus__figs:last-child .whyus__stamp {
    inset-block-start: var(--space-md);
    inset-block-end: auto;
    inset-inline-start: var(--space-md);
  }
  .whyus--landscape .whyus__fig-main .chip {
    inset-block-start: auto;
    inset-block-end: var(--chip-offset);
  }

  /* The prose column runs shorter than the photographs on two of the four
     pages and left ~280px of bare body column under the readout while the
     photographs carried on to the section foot. The column now fills the row
     and the readout is anchored to its foot, so the argument opens at the top
     of the photographs and the data closes level with their bottom edge. */
  .whyus__body { align-self: stretch; }
  .whyus__readings { margin-block-start: auto; }
}

/* --------------------------------------------------------------------------
   STACKED — one page in four runs block 02 on a different rhythm. Photographs
   full width across the top, the argument set in columns underneath, so the
   second block on the site is not the same split composition four times over.
   specs/020-service-pages.md, Block 02.
   -------------------------------------------------------------------------- */
.whyus--stacked .whyus__figs { display: grid; gap: var(--grid-gap); }
.whyus--stacked .whyus__fig-main { aspect-ratio: var(--ratio-card); }
.whyus--stacked .whyus__fig-sub {
  width: auto;
  border: 0;
  margin-block-start: 0;
  margin-inline: 0;
}

@media (min-width: 900px) {
  .whyus--stacked .whyus__inner { grid-template-columns: minmax(0, 1fr); gap: var(--space-stack); }
  /* A grid item that carries an aspect-ratio does not stretch, so the two
     frames only close on one bottom edge if the tracks are cut in the same
     proportion as the ratios: 9/8 of the width for 3:2 against 4:3 puts both
     photographs at exactly the same height at every viewport. */
  .whyus--stacked .whyus__figs { grid-template-columns: minmax(0, 9fr) minmax(0, 8fr); }
  .whyus--stacked .whyus__fig-main { aspect-ratio: var(--ratio-bleed); }
}

/* head under the band on the left, the two paragraphs set as two columns beside
   it, the readout closing the left column. Only from --bp-xl: three columns of
   a 950px page set the prose at 25 characters, so below that the argument stays
   a single measure under the band. */
@media (min-width: 1280px) {
  .whyus--stacked .whyus__body {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: var(--space-3xl);
    row-gap: var(--space-stack);
    align-items: start;
  }
  .whyus--stacked .sec-head { grid-column: 1; grid-row: 1; margin-block-end: 0; }
  .whyus--stacked .whyus__prose { grid-row: 1; }
  .whyus--stacked .whyus__readings { grid-column: 1; grid-row: 2; margin-block-start: 0; }
}

/* --------------------------------------------------------------------------
   THE LANDSCAPE PAIR CARRIES THE READOUT. On the page that runs --landscape
   the figure pair is 555px tall against a 1036px argument, and .whyus__inner's
   centring split the difference into ~240px of ground above the frames and
   ~240px below — two voids the width of a card in the end column. The readings
   move out of the prose column into the figure column and close it, so the
   column carries data to the section foot instead of ground at both ends.
   -------------------------------------------------------------------------- */
.whyus--landscape .whyus__figs .whyus__readings { margin-block-start: var(--space-md); }

@media (min-width: 900px) {
  .whyus--landscape .whyus__figs {
    display: flex;
    flex-direction: column;
    align-self: stretch;
  }
  /* a stretched flex column would otherwise shrink the ratio-locked frames */
  .whyus--landscape .whyus__figs > * { flex: 0 0 auto; }
  .whyus--landscape .whyus__figs .whyus__readings { margin-block-start: auto; }
}

/* ==========================================================================
   03 LIMITS — the page's spine. One plate divided into four cells, not four
   cards: a plate is not a link and must not behave like one. Every card on
   this site lifts on hover; this block deliberately does not, which is most
   of what stops it reading as a card grid. 0 images.
   ========================================================================== */

.refusal { background: var(--surface-page); overflow: hidden; }

/* A real surface step, not a 4/255 one: --surface-sunken on --surface-page is
   invisible, and the bleed variant strips the border, so the plate has to
   carry its own tone or it reads as loose text on the page ground. */
.refusal__plate {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  background: var(--surface-raised);
  border: var(--border-width-hair) solid var(--border-soft);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
}

/* The accent is each cell's OPENING rule, never an inline-start bar: on a
   two-column plate that bar lands on the column seam and draws exactly the
   vertical divider docs/uniqueness.md move 3 killed on the stat band, while
   the first and third bars fall off the viewport edge under --bleed. */
.refusal__cell {
  display: grid;
  gap: var(--space-2xs);
  align-content: start;
  padding: var(--card-pad-lg);
  border-block-start: var(--border-width-bar) solid var(--surface-accent);
}

.refusal__idx {
  font-size: var(--text-spec);
  letter-spacing: var(--tracking-mono-label);
  color: var(--text-accent);
}
.refusal__claim {
  font-size: var(--text-h3);
  font-weight: var(--weight-display);
  line-height: var(--leading-snug);
  color: var(--text-primary);
}
.refusal__why {
  max-width: var(--width-measure);
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-muted);
}
.refusal__why a {
  color: var(--text-secondary);
  text-decoration: underline;
  text-decoration-color: var(--border-accent);
  text-underline-offset: var(--space-3xs);
  transition: color var(--dur-fast) var(--ease-state);
}
.refusal__why a:hover { color: var(--text-primary); }

.refusal__rule { margin-block-start: var(--space-md); }

/* The bleed variant: the plate crosses both container edges and loses its side
   borders and its chamfer (same exemption work.css takes for .workband — a
   100vw box has no visible corner to cut). The block-start and block-end
   hairlines stay, so the plate still closes against the page. */
/* The band is a direct child of <section class="refusal"> on every page that
   sets --bleed, and the section is a child of <body>, so it is already the
   full page width and needs no vw arithmetic at all. The previous
   `width: 100vw` overhung the viewport by half a scrollbar on Windows and by
   half the excess above --width-page, and .refusal's overflow: hidden was
   what hid it. Same correction as .workband; reasoning in base.css .bleed. */
.refusal--bleed .refusal__band { width: auto; margin-inline: 0; }
.refusal--bleed .refusal__plate {
  border-inline: 0;
  border-radius: var(--radius-sharp);
  clip-path: none;
}
/* the plate crosses both viewport edges, so its own padding is the only thing
   holding the copy clear of a landscape notch under viewport-fit=cover */
.refusal--bleed .refusal__cell {
  padding-inline: max(var(--card-pad-lg), var(--gutter));
  padding-inline: max(var(--card-pad-lg), var(--gutter), env(safe-area-inset-left, 0px)) max(var(--card-pad-lg), var(--gutter), env(safe-area-inset-right, 0px));
}

/* --------------------------------------------------------------------------
   THE LIGHT BAND. Every other page on the site carries exactly one tonal break
   — the bone Process band — and the city pages have no Process block, so they
   ran their whole length on one tone. The plate that takes it is this one: it
   is the page's spine, it has no hover state and no photograph, and it is the
   only block whose ink list is short enough to flip without re-inking a
   component. Construction copied from process.css: bone ground, grain at
   --grain-opacity-invert, every annotation ink swapped for its -on-invert pair.
   The accent stays a FILL here (the cell's opening rule) and never sets text —
   on bone it measures 1.9:1. docs/art-direction.md.
   -------------------------------------------------------------------------- */
.refusal--light {
  position: relative;
  background: var(--surface-invert);
  color: var(--text-on-invert);
  --tick-ink: var(--tick-ink-invert);
  --tick-ink-major: var(--tick-ink-invert-major);
  --chamfer-edge-ink: var(--chamfer-edge-ink-invert);
}
.refusal--light::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--grain-image);
  background-size: var(--grain-size) var(--grain-size);
  opacity: var(--grain-opacity-invert);
  pointer-events: none;
}
.refusal--light > * { position: relative; z-index: var(--z-content); }

.refusal--light .sec-title { color: var(--text-on-invert); }
.refusal--light .sec-spec { color: var(--text-on-invert-muted); }
.refusal--light .sec-spec b { color: var(--text-on-invert-accent); }
.refusal--light .eyebrow { color: var(--text-on-invert-muted); --bracket-color: var(--border-on-invert-strong); }
.refusal--light .eyebrow__idx { color: var(--text-on-invert); }

.refusal--light .refusal__plate {
  background: var(--surface-invert-raised);
  border-color: var(--border-on-invert-strong);
}
.refusal--light .refusal__idx { color: var(--text-on-invert-accent); }
.refusal--light .refusal__claim { color: var(--text-on-invert); }
.refusal--light .refusal__why { color: var(--text-on-invert-muted); }
.refusal--light .refusal__why a {
  color: var(--text-on-invert);
  text-decoration-color: var(--text-on-invert-accent);
}
.refusal--light .refusal__why a:hover { color: var(--text-on-invert-accent); }

@media (min-width: 768px) {
  /* 2x2, never 4-up: the reasons run 20-50 words and are unequal, so four
     columns set the longest cell at eleven lines beside a three-line one.
     1fr rows even the pair: a one-line reason otherwise sits at half the
     height of its neighbour. In one column the rows stack, so they don't. */
  .refusal__plate { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr; }

  /* THE COLUMN SEAM. At 1920 a cell is 960px wide and holds 572px of text, so
     without a seam the plate read as two rows of prose under two long accent
     rules rather than as one plate divided into four. This is a hairline in the
     plate's own border ink, not the accent divider docs/uniqueness.md move 3
     killed: it is the same edge the plate already draws around itself, carried
     inward. Rows need no seam — the accent opening rule already separates them. */
  .refusal__cell:nth-child(even) { border-inline-start: var(--border-width-hair) solid var(--border-soft); }
  .refusal--light .refusal__cell:nth-child(even) { border-inline-start-color: var(--border-on-invert-strong); }
}

/* --------------------------------------------------------------------------
   THE PLATE IS PLACED, NOT PRINTED. clip-path removes box-shadow outright, so
   on the bone variant the site's one light plate sat flat on the ground it was
   meant to lift off. --shadow-chamfer-invert is the drop-shadow pair made for
   a chamfered object on a light surface and was referenced nowhere until now;
   it goes on the band rather than the plate because a filter on a clipped
   element is applied after the clip, which is what makes the chamfer cast.
   -------------------------------------------------------------------------- */
.refusal--light .refusal__band { filter: var(--shadow-chamfer-invert); }

/* --------------------------------------------------------------------------
   THE HEAD AS THE PLATE'S FIRST CELL. Standing above the plate, the section
   head left #limits 741px tall around 374px of ink — 136px of bone over the
   eyebrow, 169px under the plate, and an empty 1180x290 beside a five-word h2
   — on the one block on the page that flips to bone, which made the emptiest
   block the brightest. Set as the plate's opening cell it becomes the block's
   first column and the accent opening rule runs unbroken across all three.
   -------------------------------------------------------------------------- */
.refusal--head-in-plate .refusal__head {
  max-width: none;
  margin-block-end: 0;
  padding: var(--card-pad-lg);
  border-block-start: var(--border-width-bar) solid var(--surface-accent);
}
/* the plate's own border is the boundary here, so the head does not draw the
   graduated tick rule .sec-head carries when it stands on the page ground */
.refusal--head-in-plate .refusal__head::before { content: none; }
.refusal--bleed .refusal__head { padding-inline: max(var(--card-pad-lg), var(--gutter)); }

@media (min-width: 768px) {
  /* While the plate is two columns wide the head spans them and the refusals
     take the row underneath: three columns of a 785px plate set 260px tracks
     and broke "two-year-old car." over four lines. Rows are auto here, not
     1fr — the 2x2 rule's even rows would otherwise stretch the head cell to
     the height of the refusals beside it and put the bone straight back. */
  .refusal--head-in-plate .refusal__plate { grid-auto-rows: auto; }
  .refusal--head-in-plate .refusal__head { grid-column: 1 / -1; }
}

@media (min-width: 1024px) {
  /* three equal columns: head, refusal, refusal. The 2x2 rule above cannot
     see the head, so it would have set the two refusals under it. */
  .refusal--head-in-plate .refusal__plate {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-auto-rows: 1fr;
  }
  .refusal--head-in-plate .refusal__head { grid-column: auto; }
  /* every cell now opens a column, so every cell takes the seam — :nth-child
     (even) counted from the plate and with the head at index 1 it landed on
     the first refusal only */
  .refusal--head-in-plate .refusal__cell { border-inline-start: var(--border-width-hair) solid var(--border-soft); }
  .refusal--light.refusal--head-in-plate .refusal__cell { border-inline-start-color: var(--border-on-invert-strong); }
}

/* ==========================================================================
   10 RECENT WORK — the photograph IS the section (M1, refs 01 and 06).
   100vw, no container, no chamfer, no inset frame, no card. Three unequal
   tiles butted with a 1px seam, an 11px mono label parked bottom-left, and
   zero padding at the foot so the band butts §11 directly. 3 images.
   ========================================================================== */

.work {
  background: var(--surface-page);
  padding-block: var(--space-section) 0;
  overflow: hidden;
}

.work__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-md);
  margin-block-end: var(--space-stack);
}

.work__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--text-muted);
}
.work__social a { transition: color var(--dur-fast) var(--ease-state); }
.work__social a:hover { color: var(--text-primary); }
.work__social-link { display: inline-flex; align-items: center; gap: var(--space-3xs); }

/* --------------------------------------------------------------------------
   THE BAND — the one place on the page where an image is not in a box
   -------------------------------------------------------------------------- */
/* NO 100vw HERE. The band is already a direct child of <section class="work">,
   which is a child of <body> and therefore exactly as wide as the page — so
   `width: auto` IS the full bleed, in every engine, with no arithmetic to get
   wrong. The 100vw version measured 1500px against a 1485px body on Windows
   Chrome and hung 7.5px off each edge, where .work's overflow: hidden cut 15px
   of photograph off the band and shifted both seams; above --width-page it
   overhung by half the excess. Neither is visible until it is measured, which
   is why it survived. */
.workband {
  display: grid;
  gap: var(--bleed-seam);
  background: var(--bleed-seam-ink);
}

.workband__tile {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: var(--ratio-bleed);
  background: var(--surface-media);
}
.workband__tile picture { display: contents; }
.workband__tile img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-entrance);
}
.workband__tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--scrim-bleed);
  pointer-events: none;
}
.workband__tile:hover img { transform: scale3d(var(--scale-bleed-hover), var(--scale-bleed-hover), 1); }
.workband__tile:focus-visible { outline: none; box-shadow: var(--focus-ring-inset); }

.workband__label {
  position: absolute;
  z-index: var(--z-content);
  inset-block-end: var(--bleed-label-inset);
  /* the band bleeds to the viewport edge, so under viewport-fit=cover this
     label is the one piece of copy that can land under a landscape notch */
  inset-inline-start: max(var(--bleed-label-inset), env(safe-area-inset-left, 0px));
  max-width: calc(100% - var(--bleed-label-inset) * 2);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  font-weight: var(--weight-medium);
  line-height: var(--leading-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-on-media);
}
.workband__label b { color: var(--text-accent); font-weight: var(--weight-medium); }

@media (min-width: 768px) {
  .workband {
    grid-template-columns: 38fr 34fr 28fr;
    height: var(--bleed-band-h);
  }
  .workband__tile { aspect-ratio: auto; height: 100%; }
  /* one tile, one track. The 3-track grid puts a lone tile in a 38fr column
     and leaves two thirds of a 100vw band empty. */
  .workband--single { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   09 PACKAGES — four tiers. Long Haul is lifted and accent-bordered; it is the
   only card on the page allowed to sit above its row. 0 images.
   ========================================================================== */

.packages { background: var(--surface-page); }

/* --------------------------------------------------------------------------
   THE LEDGER (M15, refs 16 and 18) — spec table as page layout. Four
   full-width hairline rows, name at display size, contents at 11px mono in two
   columns, price right-aligned hard outside the content grid. Replaces four
   near-identical dark card boxes, which was the anti-ref's exact shape and the
   one place this page repeated the services card rhythm.
   -------------------------------------------------------------------------- */
/* docs/uniqueness.md move 6: every horizontal rule on the page is a tick rule,
   the ledger's opening rule included. Each row closes itself. */
.ledger { background: var(--tick-rule); }

.ledger__row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-sm);
  align-items: center;
  min-height: var(--ledger-row-min-h);
  padding-block: var(--ledger-pad-block);
  padding-inline-start: var(--space-md);
  border-inline-start: var(--border-width-slab) solid transparent;
  overflow: hidden;
  /* the row rule, graduated. background-color is left free so the hover tint
     composites over the ticks instead of erasing them. */
  background: var(--tick-rule);
  background-position: bottom;
  transition:
    background-color var(--dur-fast) var(--ease-state),
    transform var(--dur-fast) var(--ease-lift);
}
.ledger__row:hover {
  background-color: var(--ledger-hover);
  transform: translate3d(0, var(--lift-ledger), 0);
}
/* the broad calibration of the one sheen mechanism: a 540px row needs a wider,
   slower band than a 180px button */
.ledger__row::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(var(--sheen-width-broad) * -2);
  width: var(--sheen-width-broad);
  background: var(--sheen-color);
  transform: skewX(var(--sheen-skew)) translate3d(0, 0, 0);
  transition: transform var(--dur-sheen-broad) var(--ease-state);
  pointer-events: none;
}
.ledger__row:hover::after { transform: skewX(var(--sheen-skew)) translate3d(700%, 0, 0); }

.ledger__row--feature { border-inline-start-color: var(--border-accent); }

.ledger__name {
  font-size: var(--text-ledger);
  font-weight: var(--weight-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  color: var(--text-primary);
}

.ledger__contents {
  display: grid;
  gap: var(--space-3xs) var(--ledger-col-gap);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  line-height: var(--leading-micro);
  letter-spacing: var(--tracking-mono-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.ledger__item { display: flex; align-items: baseline; gap: var(--space-2xs); }
.ledger__item::before {
  content: "";
  width: var(--space-3xs);
  height: var(--space-3xs);
  border-radius: var(--radius-round);
  background: var(--surface-accent);
  flex: none;
}

.ledger__price {
  font-family: var(--font-mono);
  font-size: var(--text-price);
  font-weight: var(--weight-bold);
  line-height: var(--leading-flat);
  letter-spacing: var(--tracking-mono-tight);
  color: var(--text-accent-quiet);
}
.ledger__row--feature .ledger__price { color: var(--text-accent); }

/* the whole row is the target; the label is the accessible name */
.ledger__link { position: absolute; inset: 0; }
.ledger__link:focus-visible { outline: none; box-shadow: var(--focus-ring-inset); }

@media (min-width: 768px) {
  .ledger__contents { grid-template-columns: repeat(var(--ledger-micro-cols), minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .ledger__row {
    grid-template-columns: var(--ledger-grid);
    column-gap: var(--ledger-col-gap);
  }
  .ledger__price { text-align: end; }
}

/* --------------------------------------------------------------------------
   THE TIERED LEDGER — the same rows read on three channels. docs/content.md
   §Vehicle size tiers. Three of the four service pages take it; the film page
   does not, because its rows are coverage levels and not size classes, and
   that distinction is the whole point of .filmnote.

   Track list declared here rather than in tokens.css because it is this
   variant's own composition of the same idea --ledger-grid expresses, in the
   same fr-and-min-content vocabulary: no length in it that is not a keyword.
   -------------------------------------------------------------------------- */
.ledger--tiers {
  --ledger-cols-tier: minmax(0, 24fr) minmax(0, 34fr) repeat(3, minmax(min-content, 11fr));
}

/* the channel names, once there are channels to name. Below 1024 the row is a
   single column and each figure carries its own numeral instead. */
.ledger__head { display: none; }

.ledger--tiers .tierfig__v { font-size: var(--text-price); color: var(--text-accent-quiet); }
.ledger__row--feature .tierfig__v { color: var(--text-accent); }

@media (min-width: 1024px) {
  .ledger--tiers .ledger__row { grid-template-columns: var(--ledger-cols-tier); }
  .ledger__head {
    display: grid;
    grid-template-columns: var(--ledger-cols-tier);
    column-gap: var(--ledger-col-gap);
    /* the rows carry a 4px start border plus their own inset; the head has to
       stand on the same left rule or the numerals sit off their columns */
    padding-inline-start: calc(var(--space-md) + var(--border-width-slab));
    /* .ledger draws its opening tick rule at the top of its own box, and the
       head is the first thing in it: without this the numerals sit on the rule */
    padding-block: var(--space-sm) var(--space-2xs);
    font-family: var(--font-mono);
    font-size: var(--text-micro);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-muted);
  }
  /* three channel names over three channels. The key above already carries
     the group name, so the head does not print it twice. */
  .ledger__head > span { text-align: end; }
  .ledger__head > span:nth-child(1) { grid-column: 3; }
  .ledger__head > span:nth-child(2) { grid-column: 4; }
  .ledger__head > span:nth-child(3) { grid-column: 5; }
}

.packages__warranty {
  display: grid;
  gap: var(--space-xs);
  margin-block-start: var(--space-stack);
  padding: var(--card-pad-lg);
  background: var(--chamfer-edge), var(--surface-sunken);
  border: var(--border-width-hair) solid var(--border-strong);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
}
.packages__warranty-head {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.packages__warranty-list {
  display: grid;
  gap: var(--space-2xs);
}
.packages__warranty-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-xs);
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-muted);
  padding-block-end: var(--space-2xs);
  background: var(--tick-rule-fine);
  background-position: bottom;
}
.packages__warranty-key {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-secondary);
  white-space: nowrap;
}

@media (min-width: 768px) {
  .packages__warranty-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-xs) var(--space-lg); }
}

/* ==========================================================================
   04 SERVICES — 3x3 photo-top card grid, then a 3-up wide row for the
   remaining three services, then the add-on ledger. 12 images.
   ========================================================================== */

.services { background: var(--surface-page); }

.services__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--card-min), 1fr));
  gap: var(--grid-gap);
}

.svc {
  display: flex;
  flex-direction: column;
  background: var(--surface-raised);
  border: var(--border-width-hair) solid var(--border-hairline);
  border-radius: var(--radius-card);
  clip-path: var(--chamfer-clip);
  overflow: hidden;
  transition:
    transform var(--dur-fast) var(--ease-lift),
    background-color var(--dur-fast) var(--ease-state),
    box-shadow var(--dur-fast) var(--ease-lift);
}
.svc:hover {
  transform: translate3d(0, var(--lift-card), 0);
  background: var(--surface-raised-hover);
}
.svc:hover .media img { transform: scale3d(var(--scale-media-hover), var(--scale-media-hover), 1); }
.svc:hover .media::after { background: var(--chamfer-edge), var(--overlay-media-hover); }
.svc:hover .media::before { transform: skewX(var(--sheen-skew)) translate3d(1200%, 0, 0); }

.svc__media {
  aspect-ratio: var(--ratio-card);
  border-start-start-radius: var(--radius-card);
  border-start-end-radius: var(--radius-card);
}
/* the card's chamfer cuts through the photograph, so the hairline that
   replaces the lost border has to be drawn on the layer above the image */
.svc__media::after { background: var(--chamfer-edge), var(--overlay-media); }

.svc__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  flex: 1;
  padding: var(--card-pad);
}

.svc__title {
  font-size: var(--text-h3);
  line-height: var(--leading-snug);
  color: var(--text-primary);
}

.svc__desc {
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-muted);
}

.svc__specs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
  margin-block-start: auto;
  padding-block-start: var(--space-sm);
  background: var(--tick-rule-fine);
}
.svc__spec { display: flex; flex-direction: column; gap: var(--space-3xs); }
.svc__spec-key {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-faint);
}
.svc__spec-val {
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
}
.svc__spec-val--price { font-size: var(--text-price); color: var(--text-accent); }

.svc__cta { margin-block-start: var(--space-xs); align-self: flex-start; }

/* --------------------------------------------------------------------------
   WIDE ROW — the three services that do not fit the nine tiles
   -------------------------------------------------------------------------- */
.services__wide {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--card-min), 1fr));
  gap: var(--grid-gap);
  margin-block-start: var(--grid-gap);
}

.svcw {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: stretch;
  background: var(--chamfer-edge), var(--surface-alt);
  border: var(--border-width-hair) solid var(--border-hairline);
  border-radius: var(--radius-card);
  clip-path: var(--chamfer-clip);
  overflow: hidden;
  transition: background-color var(--dur-fast) var(--ease-state), transform var(--dur-fast) var(--ease-lift);
}
.svcw:hover { background: var(--chamfer-edge), var(--surface-raised); transform: translate3d(0, var(--lift-tile), 0); }
.svcw:hover .media::before { transform: skewX(var(--sheen-skew)) translate3d(1200%, 0, 0); }
.svcw:hover .media img { transform: scale3d(var(--scale-media-hover), var(--scale-media-hover), 1); }

.svcw__media { height: 100%; min-height: var(--icon-circle-lg); aspect-ratio: var(--ratio-wide); }
.svcw__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  padding: var(--card-pad);
}
.svcw__title { font-size: var(--text-h4); color: var(--text-primary); }
.svcw__desc { font-size: var(--text-caption); color: var(--text-muted); }
.svcw__price {
  margin-block-start: auto;
  padding-block-start: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-medium);
  color: var(--text-accent);
}

/* --------------------------------------------------------------------------
   ADD-ONS — a single dense ledger row
   -------------------------------------------------------------------------- */
.services__addons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-md);
  margin-block-start: var(--grid-gap);
  padding: var(--card-pad);
  border: var(--border-width-hair) solid var(--border-strong);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
  background: var(--chamfer-edge), var(--surface-sunken);
}
.services__addons-label {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.services__addons-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
}
.services__addon {
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
  font-size: var(--text-body-sm);
  color: var(--text-secondary);
}
.services__addon b {
  font-family: var(--font-mono);
  font-weight: var(--weight-medium);
  color: var(--text-accent);
}
.services__addon-note { font-size: var(--text-caption); color: var(--text-faint); }

/* --------------------------------------------------------------------------
   SECTION FOOT — the grid publishes the Tier I figure and hands the other two
   to the full price list. Nine tiles carrying twenty-seven prices reads as a
   spreadsheet; the route out has to be a visible part of the section, not a
   line of small print. docs/content.md §Vehicle size tiers.
   -------------------------------------------------------------------------- */
.services__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm) var(--space-md);
  margin-block-start: var(--grid-gap);
}
.services__foot .filmnote { flex: 1 1 var(--card-min-wide); margin-block-start: 0; }

/* The split only once the media column can hold a spec chip. Measured across
   the row's own breakpoints: the wide row is 3-up from 1024, which leaves the
   34% media column 82px of content against a 98px chip — that IS the clipped
   "FROM $1" the client caught, one breakpoint further out. It clears at 1200,
   where the column carries 112px. Below that the card stacks and the chip has
   the full width. */
@media (min-width: 1200px) {
  .svcw { grid-template-columns: minmax(0, 34%) minmax(0, 1fr); }
  .svcw__media { aspect-ratio: auto; }
}

@media (min-width: 1024px) {
  .services__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .services__wide { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ==========================================================================
   VEHICLE SIZE TIERS — the persistent key, the tier figure with its channel
   label, and the film footnote.

   Shared by four hosts: the /services/ price panel, the home service grid, and
   three of the four service-page ledgers. One sheet rather than four copies,
   because the key has to read identically on every page it appears on or it
   stops being a key. Loaded non-blocking like every other below-the-fold
   sheet. 0 images.

   The one structural idea: a price cell always carries its own channel label
   in the DOM. Wide, the column head names the channel and the label is taken
   out of the visual flow but left for a screen reader, so "$1,605" is never
   read as an unqualified figure. Narrow, the table becomes one card per
   service and the label is the only thing that says which size this is.
   Nothing is ever conditionally rendered — the layout changes, the disclosure
   does not.
   ========================================================================== */

/* --------------------------------------------------------------------------
   THE KEY — persistent, above the figures it explains. Not a tooltip: it is
   the legend for twenty-one numbers and it belongs on the page.
   -------------------------------------------------------------------------- */
.tierkey {
  --chamfer: var(--chamfer-sm);
  display: grid;
  gap: var(--space-xs);
  padding: var(--card-pad);
  background: var(--chamfer-edge), var(--surface-sunken);
  border: var(--border-width-hair) solid var(--border-strong);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
}

.tierkey__title {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}

.tierkey__list {
  display: grid;
  gap: var(--space-xs);
  padding: 0;
  margin: 0;
  list-style: none;
}

.tierkey__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--space-2xs);
  row-gap: var(--space-3xs);
  padding-block-end: var(--space-2xs);
  /* docs/uniqueness.md move 6: every rule on the page is a tick rule */
  background: var(--tick-rule-fine);
  background-position: bottom;
}
.tierkey__item:last-child { background: none; padding-block-end: 0; }

/* the numeral is the accented thing; the words beside it never are */
.tierkey__num {
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: start;
  min-width: var(--icon-md);
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-bold);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-mono-tight);
  color: var(--text-accent);
}
.tierkey__name {
  grid-column: 2;
  font-size: var(--text-body-sm);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-heading);
  color: var(--text-primary);
}
.tierkey__eg {
  grid-column: 2;
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  line-height: var(--leading-micro);
  letter-spacing: var(--tracking-mono-label);
  color: var(--text-faint);
}

.tierkey__note {
  font-size: var(--text-caption);
  line-height: var(--leading-snug);
  color: var(--text-muted);
}

@media (min-width: 768px) {
  /* Row subgrid, so the example vehicles sit on one line across all three
     readings. Without it each item is its own grid, tier III's two-line name
     pushes its examples down, and the key reads as three loose blocks between
     roughly 768 and 1100. Dropped whole where subgrid is unsupported, which
     leaves exactly the layout that was there before. */
  .tierkey__list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: auto auto;
    column-gap: var(--space-xs);
    row-gap: var(--space-3xs);
  }
  /* three readings side by side want a vertical axis between them, not three
     stacked horizontal rules */
  .tierkey__item {
    grid-row: span 2;
    grid-template-rows: subgrid;
    padding-block-end: 0;
    padding-inline-start: var(--space-sm);
    background: var(--tick-rule-vertical);
  }
  .tierkey__item:first-child { background: none; padding-inline-start: 0; }
  .tierkey__item:last-child { background: var(--tick-rule-vertical); }
}

/* --- the one-line variant — where the full key would outweigh what it keys.
   Same wording, set as a sentence against an accent rule. ------------------- */
.tierkey--line {
  display: block;
  padding: var(--space-xs) var(--space-sm);
  background: var(--surface-sunken);
  border: 0;
  border-inline-start: var(--border-width-bar) solid var(--border-accent-soft);
  border-radius: var(--radius-sharp);
  clip-path: none;
  max-width: var(--width-measure);
  margin-block-end: var(--space-md);
  font-size: var(--text-caption);
  line-height: var(--leading-body);
  color: var(--text-muted);
}
.tierkey--line b {
  font-family: var(--font-mono);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-mono-tight);
  color: var(--text-accent);
}

/* --------------------------------------------------------------------------
   THE TIER FIGURE — a price and the channel it was read on. The host row
   supplies the track; this supplies the pairing.
   -------------------------------------------------------------------------- */
.tierfig {
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
  min-width: 0;
}

.tierfig__k {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-faint);
}

.tierfig__v {
  font-family: var(--font-mono);
  font-size: var(--text-step);
  font-weight: var(--weight-bold);
  line-height: var(--leading-flat);
  letter-spacing: var(--tracking-mono-tight);
  color: var(--text-accent);
  white-space: nowrap;
}

/* A flat price spans the three channels instead of printing the same number
   three times. The span IS the statement: this one does not change with your
   car. Narrow, the same cell carries "I · II · III" as its label. */
.tierfig--span { justify-content: flex-start; }

/* Film. Not a gap and not an omission — a stated position, so it is drawn as a
   filled field rather than as three empty cells. The words stay off the accent
   ink; the accent is in the wash and the edge. */
.tierfig--quoted {
  justify-content: center;
  padding: var(--space-3xs) var(--space-2xs);
  background: var(--surface-accent-wash);
  border: var(--border-width-hair) solid var(--border-accent-soft);
  border-radius: var(--radius-inset);
}
.tierfig__v--words {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  line-height: var(--leading-micro);
  letter-spacing: var(--tracking-mono-label);
  color: var(--text-secondary);
  white-space: normal;
}

/* --- the channel label, once the column head names the channel --------------
   Not display:none: the figure is meaningless unqualified, so the label is
   taken out of the visual flow and left in the accessibility tree, which is
   what .sr-only does. It cannot be .sr-only itself because which of the two
   states applies is a question about the viewport, and the two hosts change
   layout at different widths. */
@media (min-width: 768px) {
  .tierfig--md .tierfig__k {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .tierfig--md { justify-content: flex-end; }
  .tierfig--md.tierfig--span { justify-content: center; }
}

@media (min-width: 1024px) {
  .tierfig--lg .tierfig__k {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .tierfig--lg { justify-content: flex-end; }
  .tierfig--lg.tierfig--span { justify-content: center; }
}

/* --------------------------------------------------------------------------
   THE FILM FOOTNOTE — the reason three rows carry no size price. It is the
   only place on the site that explains a refusal to publish a number, so it
   is set as a statement, not as small print.
   -------------------------------------------------------------------------- */
.filmnote {
  --chamfer: var(--chamfer-sm);
  margin-block-start: var(--space-md);
  padding: var(--card-pad);
  background: var(--chamfer-edge), var(--surface-sunken);
  border: var(--border-width-hair) solid var(--border-strong);
  border-inline-start: var(--border-width-slab) solid var(--surface-accent);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-muted);
}
.filmnote b {
  display: block;
  font-size: var(--text-h4);
  font-weight: var(--weight-bold);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}

/* ==========================================================================
   08 PROCESS — the page's only light band. Not five numbered circles on a
   line: a depth scale. The five steps sit on one graduated axis and only the
   two that move material carry a reading. Amber may fill a shape here but may
   never set text — on bone it measures 1.9:1. 0 images.
   ========================================================================== */

.process {
  position: relative;
  background: var(--surface-invert);
  color: var(--text-on-invert);
}
.process::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--grain-image);
  background-size: var(--grain-size) var(--grain-size);
  opacity: var(--grain-opacity-invert);
  pointer-events: none;
}

.process__inner { position: relative; z-index: var(--z-content); }

/* the light band flips every ink in the annotation layer */
.process .sec-title { color: var(--text-on-invert); }
.process .sec-lead { color: var(--text-on-invert-muted); }
.process .sec-spec { color: var(--text-on-invert-muted); }
.process .sec-spec b { color: var(--text-on-invert-accent); }
.process .eyebrow { color: var(--text-on-invert-muted); --bracket-color: var(--border-on-invert-strong); }
.process .eyebrow__idx { color: var(--text-on-invert); }
/* the light band recolours the tick language locally — the composed rules are
   now declared per-element, so the inks a section sets are the inks it gets */
.process {
  --tick-ink: var(--tick-ink-invert);
  --tick-ink-major: var(--tick-ink-invert-major);
}

/* --------------------------------------------------------------------------
   THE SCALE
   -------------------------------------------------------------------------- */
.process__steps {
  position: relative;
  display: grid;
  gap: var(--space-lg);
}

/* THE AXIS AT NARROW WIDTHS. Below 900 the scale used to disappear entirely —
   no axis, no graduations — which removed the clearest statement of the
   positioning on the width most visitors use. Same tick construction as the
   stat band and the desktop axis, stood on end and run through the marker
   gutter; the gap is bridged so the axis is continuous between steps.
   */
.process__steps::before {
  content: "";
  position: absolute;
  z-index: var(--z-below);
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--marker-dot-lg);
  background: var(--tick-rule-vertical);
  background-position-x: calc(var(--marker-dot-lg) / 2);
}

.process__step {
  display: grid;
  /* a fixed gutter, not auto: an auto column sizes to the marker in THAT step,
     so the small dots and the large ones would sit on different axes */
  grid-template-columns: var(--marker-dot-lg) minmax(0, 1fr);
  grid-template-areas:
    "marker depth"
    "marker title"
    "marker desc";
  column-gap: var(--space-md);
  align-items: center;
}


.process__depth {
  grid-area: depth;
  font-family: var(--font-mono);
  font-size: var(--text-spec);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-mono-tight);
  color: var(--text-on-invert-accent);
}
.process__depth:empty { display: none; }

.process__marker {
  grid-area: marker;
  width: var(--marker-dot);
  height: var(--marker-dot);
  border-radius: var(--radius-round);
  background: var(--surface-invert-ink);
  align-self: center;
  justify-self: center;
  transition: transform var(--dur-fast) var(--ease-lift);
}
.process__step--major .process__marker {
  width: var(--marker-dot-lg);
  height: var(--marker-dot-lg);
  background: var(--surface-accent);
}
.process__step:hover .process__marker { transform: scale3d(var(--scale-media-hover), var(--scale-media-hover), 1); }

.process__title {
  grid-area: title;
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
  font-size: var(--text-h4);
  color: var(--text-on-invert);
  margin-block-end: var(--space-3xs);
}
.process__idx {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-mono-label);
  color: var(--text-on-invert-muted);
}

.process__desc {
  grid-area: desc;
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-on-invert-muted);
}

.process__foot {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-block-start: var(--space-stack);
  padding-block-start: var(--space-md);
}
.process__foot::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: var(--tick-rule-h);
  background: var(--tick-rule);
}
.process__foot-note { font-size: var(--text-body-sm); color: var(--text-on-invert-muted); }

.process :focus-visible { outline-color: var(--focus-ring-color-invert); }

@media (min-width: 900px) {
  /* four rows: reading · marker on the axis · title · description.
     subgrid keeps all five titles and descriptions on one baseline; without
     it they auto-size per column and read as a mistake rather than a stagger. */
  /* the track count follows the step count. A five-track scale carrying four
     steps insets the first marker and leaves a quarter of the axis bare after
     the last, which reads as a missing step rather than as a scale. */
  .process__steps {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-template-rows: auto var(--marker-dot-lg) auto auto;
    column-gap: var(--grid-gap);
    row-gap: var(--space-2xs);
  }
  /* The track count follows the step count, and it is stated in the markup
     rather than counted with :has(). Firefox has no :has() before 121 and
     Firefox 115 ESR is still the managed-desktop build; there the selector is
     invalid, the whole rule is dropped, a five-step scale keeps four tracks
     and .process__step:nth-child(5) below asks for a fifth column that does
     not exist — an implicit track, the axis short by a fifth, and the last
     step off the end of it. A class cannot fail that way in any engine. */
  .process__steps--5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .process__step {
    grid-row: 1 / span 4;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: subgrid;
    grid-template-areas: "depth" "marker" "title" "desc";
    text-align: center;
    justify-items: center;
  }
  .process__step:nth-child(1) { grid-column: 1; }
  .process__step:nth-child(2) { grid-column: 2; }
  .process__step:nth-child(3) { grid-column: 3; }
  .process__step:nth-child(4) { grid-column: 4; }
  .process__step:nth-child(5) { grid-column: 5; }

  /* the axis itself: same tick construction as the stat band, running the
     full width of the scale behind the markers */
  .process__steps::before {
    position: static;
    grid-column: 1 / -1;
    grid-row: 2;
    align-self: center;
    width: auto;
    height: var(--tick-rule-h);
    background: var(--tick-rule);
    background-position: 0 0;
  }

  .process__depth { align-self: end; padding-block-end: var(--space-2xs); }
  .process__depth:empty { display: block; }
  .process__title { justify-content: center; margin-block-end: 0; }
  .process__foot { justify-content: center; text-align: center; }
}

/* --------------------------------------------------------------------------
   NO ROW SUBGRID — Chrome before 117, Safari before 16. Firefox has had it
   since 71 and is not affected.
   Without it `grid-template-rows: subgrid` is dropped and the step becomes its
   own four-row grid inside a four-row span of the scale's. The scale's row 2
   still holds the continuous axis, but the step's marker row no longer lines
   up with it, so the rule crosses the titles and the markers sit off it — the
   one thing this section must not do, because the axis IS the argument.
   The fallback keeps the columns and the readings and drops the continuous
   rule: five markers, no line between them. The empty depth line is reserved
   rather than removed so the markers still land on one level across the row.
   -------------------------------------------------------------------------- */
@supports not (grid-template-rows: subgrid) {
  @media (min-width: 900px) {
    .process__steps { grid-template-rows: auto; }
    .process__steps::before { content: none; }
    .process__step {
      grid-row: auto;
      grid-template-rows: auto var(--marker-dot-lg) auto auto;
      /* the step is stretched by the tallest step in the row, and a grid
         container distributes that free space across its auto tracks — which
         put every step's marker at a different height even after the reading
         line was reserved. Packed to the start, the tracks are content-sized
         and only the reading line varies. */
      align-content: start;
    }
    /* Measured out rather than calculated: a hidden non-breaking space gives
       the empty reading exactly one line box at this element's own font-size
       and line-height, so the reservation cannot drift from --text-spec. */
    .process__depth:empty { display: block; visibility: hidden; }
    .process__depth:empty::before { content: "\00a0"; }
  }
}

/* ==========================================================================
   07 JOBS — horizontal scroll rail of documented jobs on the deepest surface.
   This is a GALLERY, not a comparison: matched before/after pairs do not exist
   yet and cropping two different photographs into a slider would lie about the
   one thing this business sells. See src/assets/photos/README.md. 6 images.
   ========================================================================== */

.jobs { background: var(--surface-sunken); overflow: hidden; }

.jobs__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-md);
  margin-block-end: var(--space-stack);
}

.jobs__hint {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}

.jobs__rail {
  display: flex;
  gap: var(--grid-gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-block-end: var(--space-sm);
  scrollbar-width: thin;
}
.jobs__rail::-webkit-scrollbar { height: var(--space-3xs); }
.jobs__rail::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: var(--radius-pill); }

.job {
  flex: 0 0 auto;
  width: var(--card-min-wide);
  max-width: 82vw;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  background: var(--surface-raised);
  border: var(--border-width-hair) solid var(--border-hairline);
  border-radius: var(--radius-card);
  clip-path: var(--chamfer-clip);
  overflow: hidden;
  transition: border-color var(--dur-fast) var(--ease-state), transform var(--dur-fast) var(--ease-lift);
}
.job:hover { border-color: var(--border-accent-soft); transform: translate3d(0, var(--lift-tile), 0); }
.job:hover .media img { transform: scale3d(var(--scale-media-hover), var(--scale-media-hover), 1); }
.job:hover .media::before { transform: skewX(var(--sheen-skew)) translate3d(1200%, 0, 0); }

.job__media { aspect-ratio: var(--ratio-tall); }
.job__media::after { background: var(--chamfer-edge), var(--overlay-media); }

.job__index {
  position: absolute;
  z-index: var(--z-content);
  /* top-LEFT: the chamfer cuts the top-right corner and would clip it */
  inset-block-start: var(--space-2xs);
  inset-inline-start: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--text-h4);
  font-weight: var(--weight-bold);
  color: var(--text-accent);
}

.job__body { display: flex; flex-direction: column; gap: var(--job-body-gap); padding: var(--card-pad); flex: 1; }
.job__title { font-size: var(--text-h4); color: var(--text-primary); }
.job__paint {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  line-height: var(--leading-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-secondary);
}
/* Not every frame in the rail is a vehicle, so not every card carries a paint
   name — and the ones that did not sat their title a whole eyebrow line above
   their neighbours. The line is reserved instead of the copy being invented. */
/* Reserved with :first-child rather than :not(:has()) — .job__paint is always
   the record's opening line when it exists, so the title being first IS the
   absence, and a selector every engine has read since 2011 says so. Firefox
   before 121, which includes the 115 ESR still shipping on managed desktops,
   drops any rule containing :has(), and there the reserved line disappeared
   and one card in the rail sat a line proud of its neighbours.
   The offset is the missing line PLUS the flex gap the missing element would
   have brought with it — the gap is read from the same custom property the
   container sets it from, so the two cannot drift. */
.job__body { --job-body-gap: var(--space-2xs); }
.job__body > .job__title:first-child {
  margin-block-start: calc(var(--text-micro) * var(--leading-micro) + var(--job-body-gap));
}
.job__desc { font-size: var(--text-body-sm); line-height: var(--leading-body); color: var(--text-muted); }

.job__foot {
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-block-start: auto;
  padding-block-start: var(--space-sm);
  background: var(--tick-rule-fine);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-faint);
}
.job__foot b { color: var(--text-secondary); font-weight: var(--weight-medium); }

/* the honest note card that closes the rail */
.job--note .job__body { justify-content: center; }
.job--note .media::after { background: var(--overlay-media-heavy); }
.job--note .job__note {
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-secondary);
}

/* --- the expanded record -------------------------------------------------
   A city page carries ONE job, not a rail, and a .job outside .jobs__rail
   renders at --card-min-wide and floats as a stray card. Expanded, the frame
   keeps the narrow track and the record takes the rest.
   The row wraps, and the body carries a real basis rather than 0, so that
   between --bp-md and --bp-lg — and on the record that carries two frames —
   the record drops under the frames instead of being crushed to a column of
   single words. specs/021-city-pages.md block 06. */
.job--expanded { width: auto; max-width: none; }

@media (min-width: 900px) {
  .job--expanded { flex-direction: row; flex-wrap: wrap; }
  /* NO ratio override. The two job frames are 4:5 and 3:4 portraits, and
     --ratio-card cut a 380x285 letterbox out of the middle of them: on the
     first record that removed the polisher and left a dark red smear. The
     rail's own --ratio-tall is the ratio the files were shot at. */
  .job--expanded .job__media { flex: 0 0 var(--card-min-wide); }
  /* Centring a full-height body put the closing rule at the foot of a 500px
     track with three lines of prose above it and ~90px of nothing between.
     The body is only as tall as the record, centred against the frame, so the
     DURATION rule closes the prose instead of floating below it. An expanded
     record also sets one step larger than a rail card — it is the page's one
     job, not one of six. */
  .job--expanded .job__body {
    flex: 1 1 var(--width-prose);
    align-self: center;
    padding: var(--card-pad-lg);
    --job-body-gap: var(--space-xs);
  }
  .job--expanded .job__title { font-size: var(--text-h3); }
  .job--expanded .job__desc { font-size: var(--text-lead); max-width: var(--width-measure); }

  /* TWO frames beside one record. At --card-min-wide the pair set the card
     509px tall around a 284px record and opened 225px of it as bare ground.
     The narrower track brings the frames' block size within reach of the
     record's and hands the width back to the record, which is what stops the
     expanded card reading as a 500px box with a paragraph floating in it. */
  /* Stated on the article as .job--pair, not detected with :has(): Firefox
     115 ESR has no :has() and would drop this rule, putting both frames back
     on --card-min-wide and reopening the 225px of bare ground under the
     record that the narrower track exists to close. */
  .job--pair .job__media { flex-basis: var(--card-min); }
}

@media (min-width: 1024px) {
  .jobs__rail { margin-inline-end: calc(50% - 50vw); padding-inline-end: var(--rail-peek); }
}

/* --------------------------------------------------------------------------
   THE PHOTOGRAPHY POLICY STANDFIRST. Every record in this rail names a car and
   a colour over a frame that is neither. The resolution is not faked matching
   photography: it is stating what the frames are, once, at the head of the
   rail, and letting every card inherit it. docs/content.md §Photography policy
   — the jobs rail. Chrome, not page copy: .jobs__policy is the exempt hook for
   the no-shared-sentence check, specs/021-city-pages.md criteria 47-50.
   -------------------------------------------------------------------------- */
.jobs__policy b {
  color: var(--text-secondary);
  font-weight: var(--weight-semibold);
}

/* ==========================================================================
   12 FAQ — two-column accordion on the deepest surface, oversized mono index.
   Built on <details> so it opens, closes and is keyboard reachable with JS
   off. The open row takes an accent slab bar on its leading edge. 0 images.
   ========================================================================== */

.faq { background: var(--surface-sunken); }

/* the two columns are one grid at every width. As a block below 900 the two
   .faq__col children butted together and the rhythm ran 12 / 0 / 12px. */
.faq__grid { display: grid; gap: var(--grid-gap-tight); align-items: start; }
.faq__cols { display: grid; gap: var(--grid-gap-tight); align-content: start; }

.faq__item {
  --chamfer: var(--chamfer-sm);
  border: var(--border-width-hair) solid var(--border-hairline);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
  background: var(--chamfer-edge), var(--surface-page);
  border-inline-start: var(--border-width-slab) solid var(--border-hairline);
  transition: border-color var(--dur-fast) var(--ease-state), background-color var(--dur-fast) var(--ease-state);
}
.faq__item:hover { border-color: var(--border-soft); }
.faq__item[open] {
  --chamfer-edge-ink: var(--chamfer-edge-ink-accent);
  border-inline-start-color: var(--border-accent);
  background: var(--chamfer-edge), var(--surface-alt);
}

.faq__q {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--space-sm);
  align-items: center;
  padding: var(--accordion-row-pad);
  cursor: pointer;
  list-style: none;
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}
.faq__q::-webkit-details-marker { display: none; }
/* the row is chamfered, so the outline would be clipped along the diagonal */
.faq__q:focus-visible { outline: none; box-shadow: var(--focus-ring-inset); }

.faq__index {
  font-family: var(--font-mono);
  font-size: var(--text-index);
  font-weight: var(--weight-bold);
  line-height: var(--leading-flat);
  letter-spacing: var(--tracking-mono-tight);
  color: var(--text-ghost);
  transition: color var(--dur-base) var(--ease-state);
}
/* accent ink lands on the numeral, never on the question. Hovering the row
   lights its index rather than setting eight words in the accent hue. */
.faq__item:hover .faq__index { color: var(--text-accent-quiet); }
.faq__item[open] .faq__index { color: var(--text-accent); }

.faq__marker {
  display: grid;
  place-items: center;
  width: var(--icon-lg);
  height: var(--icon-lg);
  color: var(--text-faint);
  transition: transform var(--dur-accordion) var(--ease-state), color var(--dur-fast) var(--ease-state);
}
.faq__item[open] .faq__marker { transform: rotate(45deg); color: var(--text-accent); }

.faq__a {
  padding: 0 var(--accordion-row-pad) var(--accordion-row-pad);
  padding-inline-start: calc(var(--accordion-row-pad) + var(--text-index));
  font-size: var(--text-body-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-muted);
  max-width: var(--width-measure);
}

.faq__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin-block-start: var(--space-stack);
  text-align: center;
}
.faq__foot-note { font-size: var(--text-body-sm); color: var(--text-muted); }

@media (min-width: 900px) {
  .faq__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   ONE COLUMN. Three questions do not divide into two: 2 + 1 ended the end
   column at the first item and left a hole the height of an answer beside the
   second. Three full-width rows are balanced by construction, and at this
   width the row is the same object as the .ledger rows further up the page.
   -------------------------------------------------------------------------- */
.faq--single .faq__grid { grid-template-columns: minmax(0, 1fr); }

/* ==========================================================================
   13 QUOTE — split. Form on the left, NAP panel on --radius-slab on the right.
   There is no form server: the form's action is a mailto: to the studio, which
   the browser performs with JS off. With JS on, js/modules/quote.js intercepts
   the submit and answers in .quote__sent, which carries the same message on a
   link the visitor presses. 0 images.
   ========================================================================== */

.quote { background: var(--surface-page); }

.quote__inner { display: grid; gap: var(--space-stack); align-items: start; }

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

.field { display: grid; gap: var(--space-3xs); }
.field--wide { grid-column: 1 / -1; }

.field__label {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.field__req { color: var(--text-accent); }

.field__input,
.field__select,
.field__textarea {
  --chamfer: var(--chamfer-sm);
  width: 100%;
  min-height: var(--control-h);
  padding: var(--space-2xs) var(--space-sm);
  background: var(--surface-inset);
  border: var(--border-width-hair) solid var(--border-strong);
  border-radius: var(--radius-inset);
  clip-path: var(--chamfer-clip);
  color: var(--text-primary);
  font-size: var(--text-body-sm);
  transition: border-color var(--dur-fast) var(--ease-state), background-color var(--dur-fast) var(--ease-state);
}
.field__textarea { min-height: var(--space-5xl); resize: vertical; line-height: var(--leading-body); }

/* iOS SAFARI ZOOMS THE VIEWPORT on focus for any field whose computed size is
   under 16px, and --text-body-sm is 15. On the site's only booking path that
   throws the layout sideways in the middle of typing and leaves the page
   zoomed afterwards. The other cure, maximum-scale=1 in the viewport meta,
   also kills pinch zoom for low-vision users, so it is not on the table.
   --text-body is exactly 16px, which is the threshold, and the fields are the
   only thing on the page that changes.
   Two conditions, because the two populations are not the same set: every
   phone and portrait tablet by width, and every touch screen at any width by
   pointer. Above both, the 15px calibration stands. */
@media (max-width: 1023px), (pointer: coarse) {
  .field__input,
  .field__select,
  .field__textarea { font-size: var(--text-body); }
}

/* THE SELECT IS THE ONE CONTROL EVERY ENGINE DRAWS DIFFERENTLY. Chrome puts a
   grey chevron inside the padding box, Firefox on Windows draws its own arrow
   and paints the popup from the control's own colours, and Safari and iOS
   overlay a rounded native bezel that ignores the chamfer entirely. Three
   renderings of one field. appearance: none takes the control back in all
   three; the -moz- and -webkit- lines stay because the unprefixed property is
   younger than the engines this pass is aimed at.
   The chevron is redrawn on the wrapper, not on the select: a background-image
   on the control itself is wiped by the `background` shorthand in the hover
   rule below, and this site has no gradient chevrons. Two borders on a square,
   turned 45deg — the same construction as the site's arrow marks. */
.field__select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-inline-end: calc(var(--space-sm) * 2 + var(--icon-sm));
}
.field--select { position: relative; }
.field--select::after {
  content: "";
  position: absolute;
  inset-inline-end: var(--space-sm);
  inset-block-end: calc(var(--control-h) / 2);
  width: var(--space-2xs);
  height: var(--space-2xs);
  border-inline-end: var(--border-width-medium) solid var(--text-muted);
  border-block-end: var(--border-width-medium) solid var(--text-muted);
  transform: translate3d(0, 50%, 0) rotate(45deg);
  pointer-events: none;
}
/* the popup list is UA chrome and inherits nothing, so it is inked here or it
   ships as near-black on near-black in Firefox on Windows, which paints the
   list from the control's own colours rather than from the system menu */
.field__select option { background: var(--surface-inset); color: var(--text-primary); }
.field__input:hover,
.field__select:hover,
.field__textarea:hover { border-color: var(--border-soft); background-color: var(--surface-inset-hover); }
/* chamfered, so the ring is drawn inside rather than as a clipped outline */
.field__input:focus-visible,
.field__select:focus-visible,
.field__textarea:focus-visible {
  outline: none;
  border-color: var(--border-accent);
  box-shadow: var(--focus-ring-inset);
}
.field__input::placeholder, .field__textarea::placeholder { color: var(--text-faint); }

.quote__consent {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-2xs);
  align-items: start;
  font-size: var(--text-caption);
  line-height: var(--leading-snug);
  color: var(--text-muted);
}
.quote__consent input { accent-color: var(--surface-accent); width: var(--icon-md); height: var(--icon-md); }

.quote__submit { justify-self: start; }

/* --- the confirmation panel ----------------------------------------------
   Swapped in for the form after a valid submit, and swapped back out by the
   "edit" button. Both boxes declare their own display, so both need the
   [hidden] pair: an author `display` beats the UA sheet's [hidden] rule and
   the panel would otherwise ship visible. */
.quote__form[hidden],
.quote__sent[hidden] { display: none; }

.quote__sent {
  --chamfer: var(--chamfer-md);
  --chamfer-edge-ink: var(--border-accent-soft);
  display: grid;
  justify-items: start;
  gap: var(--space-sm);
  padding: var(--card-pad-lg);
  border: var(--border-width-hair) solid var(--border-accent-soft);
  border-radius: var(--radius-card);
  clip-path: var(--chamfer-clip);
  background: var(--chamfer-edge), var(--surface-accent-wash);
}
/* chamfered: the outline would be clipped, so the ring is drawn inside */
.quote__sent:focus-visible { outline: none; box-shadow: var(--focus-ring-inset); }

.quote__sent-title { font-size: var(--text-h3); color: var(--text-primary); }
.quote__sent-body {
  max-width: var(--width-measure);
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-secondary);
}
.quote__sent-fallback {
  max-width: var(--width-measure);
  font-size: var(--text-caption);
  line-height: var(--leading-body);
  color: var(--text-muted);
}
.quote__sent-link {
  color: var(--text-accent);
  transition: color var(--dur-fast) var(--ease-state);
}
.quote__sent-link:hover { color: var(--text-accent-strong); }

/* the handoff and the way back, side by side until the column is too narrow */
.quote__sent-acts { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }

/* --- the NAP panel ------------------------------------------------------- */
.quote__nap {
  --chamfer: var(--chamfer-lg);
  display: grid;
  gap: var(--space-md);
  padding: var(--card-pad-lg);
  background: var(--chamfer-edge), var(--surface-raised);
  border: var(--border-width-hair) solid var(--border-hairline);
  border-radius: var(--radius-slab);
  clip-path: var(--chamfer-clip);
}

.nap__row { display: grid; gap: var(--space-3xs); }
.nap__key {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.nap__val { font-size: var(--text-body-sm); line-height: var(--leading-body); color: var(--text-secondary); }
.nap__val--big {
  font-family: var(--font-mono);
  font-size: var(--text-h4);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  transition: color var(--dur-fast) var(--ease-state);
}
a.nap__val--big:hover { color: var(--text-accent); }

.nap__hours { display: grid; gap: var(--space-3xs); }
.nap__hours-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  /* every horizontal rule on this site is a tick rule (docs/uniqueness.md
     move 6). This row was the last plain hairline left. */
  padding-block: var(--space-2xs);
  background: var(--tick-rule-fine);
  background-position: bottom;
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--text-muted);
}
.nap__hours-row b { color: var(--text-secondary); font-weight: var(--weight-medium); }

.nap__certs { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }
.nap__cert {
  padding: var(--space-3xs) var(--space-2xs);
  border: var(--border-width-hair) solid var(--border-accent-soft);
  border-radius: var(--radius-pill);
  background: var(--surface-accent-wash);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-mono-label);
}

/* --- /book/: the form IS the page ----------------------------------------
   The only page on the site with no hero, so the block has to clear the fixed
   header itself, and the masthead sets at display scale rather than at h2 —
   .sec-title would put the h1:body ratio at 3.5:1 and fail the type-contrast
   law. Same reasoning specs/020 records for .hero__title. The confirmation
   plate grows with it: at card scale it read as a notice dropped into a page
   whose whole job is the action it answers. */
.quote--page { padding-block-start: calc(var(--header-h) + var(--space-xl)); }
.quote--page .sec-title {
  font-size: var(--text-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
}
.quote--page .quote__sent { justify-self: stretch; --chamfer: var(--chamfer-lg); }
.quote--page .quote__sent-title { font-size: var(--text-h2); }

@media (min-width: 768px) {
  .quote__form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .quote__inner { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: var(--space-2xl); }
}

/* ==========================================================================
   14 FOOTER — dense four-column: Studio, Services, Service area, Hours.
   NAP identical to the quote panel and to the JSON-LD. 0 images.
   ========================================================================== */

.footer {
  background: var(--surface-sunken);
  padding-block: var(--space-lg) var(--space-lg);
}
.footer__rule { margin-block-end: var(--space-stack); }

.footer__top {
  display: grid;
  gap: var(--space-stack);
  padding-block-end: var(--space-stack);
  border-block-end: var(--border-width-hair) solid var(--border-hairline);
}


.footer__brand { display: grid; gap: var(--space-sm); align-content: start; }
.footer__mark {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--weight-display);
  letter-spacing: var(--tracking-label);
  color: var(--text-primary);
}
/* the identity block is the one place the gauge is allowed to lead, so it runs
   at --brandmark-h rather than the header's --icon-md */
.footer__mark-icon { width: var(--brandmark-h); height: var(--brandmark-h); }
.footer__mark-word { white-space: nowrap; }
.footer__mark-dot { color: var(--text-accent); }
.footer__line { font-size: var(--text-body-sm); line-height: var(--leading-body); color: var(--text-muted); max-width: var(--width-prose); }

.footer__cols { display: grid; gap: var(--space-stack); }

.footer__col-head {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
  margin-block-end: var(--space-xs);
}

.footer__list { display: grid; gap: var(--space-2xs); }
.footer__list a,
.footer__list span {
  font-size: var(--text-body-sm);
  display: inline-block;
}
.footer__list a {
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease-state), transform var(--dur-fast) var(--ease-lift);
}
.footer__list a:hover { color: var(--text-primary); transform: translate3d(var(--space-3xs), 0, 0); }
/* A span in this list is a fact, not a destination — the address lines. It was
   inheriting the link colour and the link box, so it read as a target that did
   nothing on click. One step quieter is the whole difference. */
.footer__list span { color: var(--text-faint); }

.footer__area-more {
  margin-block-start: var(--space-2xs);
  max-width: var(--width-measure);
  font-size: var(--text-caption);
  line-height: var(--leading-body);
  color: var(--text-faint);
}

.footer__hours-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-block: var(--space-3xs);
  border-block-end: var(--border-width-hair) solid var(--border-hairline);
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--text-muted);
}
.footer__hours-row b { color: var(--text-secondary); font-weight: var(--weight-medium); }

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-block-start: var(--space-md);
}
.footer__copy { font-size: var(--text-caption); color: var(--text-muted); }
.footer__social, .footer__legal { display: flex; flex-wrap: wrap; gap: var(--space-md); font-family: var(--font-mono); font-size: var(--text-caption); color: var(--text-muted); }
.footer__social a, .footer__legal a { transition: color var(--dur-fast) var(--ease-state); }
.footer__social a:hover, .footer__legal a:hover { color: var(--text-primary); }
.footer__social-link { display: inline-flex; align-items: center; gap: var(--space-3xs); }

.footer__disclaimer {
  margin-block-start: var(--space-sm);
  font-size: var(--text-micro);
  line-height: var(--leading-snug);
  color: var(--text-muted);
  max-width: var(--width-measure);
}

@media (min-width: 768px) {
  .footer__cols { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-lg); }
}
@media (min-width: 1024px) {
  .footer__top { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--space-2xl); }
}
