/* ==========================================================================
   06 MEASUREMENT — the positioning argument. Offset overlap: the tall panel
   photograph bleeds past the right viewport edge and the mono readout block
   overlaps its left third. Grid break #1. 1 image.
   ========================================================================== */

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

/* docs/art-direction.md: surfaces alternate so the page is never one tone for
   more than two blocks. On a page whose neighbours both sit on --surface-page
   this block takes the alternating band instead. */
.measure--alt { background: var(--surface-alt); }

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

.measure__media {
  position: relative;
  aspect-ratio: var(--ratio-card);
  border-radius: var(--radius-card);
  clip-path: var(--chamfer-clip);
}
.measure__media::after { background: var(--chamfer-edge), var(--overlay-media); }

.measure__body { display: flex; flex-direction: column; gap: var(--space-md); }

.measure__quote {
  font-family: var(--font-display);
  font-size: var(--text-lead);
  font-weight: var(--weight-medium);
  line-height: var(--leading-body);
  color: var(--text-secondary);
  padding-inline-start: var(--space-md);
  border-inline-start: var(--border-width-slab) solid var(--surface-accent);
}

/* --- the readout ledger --------------------------------------------------
   The head and the rows were two independent grids sharing a written-out track
   list, so the auto column sized to "DEPTH" in one and to "118 um" in the
   other and the headers never sat over their columns. They now share ONE track
   list, declared once on the panel as --measure-cols and inherited: the same
   guarantee subgrid gave, minus the requirement that the panel be a grid.
   The panel is a flex column instead, which is what lets the note sit on the
   panel foot when the pair of panels is stretched to a common height. */
.measure__panel {
  --measure-cols: minmax(0, 1.7fr) minmax(min-content, 1fr) minmax(0, 1.2fr);
  display: flex;
  flex-direction: column;
  padding: var(--card-pad-lg);
  background: var(--chamfer-edge), var(--surface-raised);
  border: var(--border-width-hair) solid var(--border-strong);
  border-radius: var(--radius-card);
  clip-path: var(--chamfer-clip);
}

/* --- the drive-time pair --------------------------------------------------
   The city pages read an area against one figure and have no third datum, so
   the panel's own three tracks would leave a dead column and hang the head
   over nothing. Two tracks, declared once, inherited by the head and the rows
   exactly as the three-track list is. specs/021-city-pages.md block 03. */
.measure__panel--pair { --measure-cols: minmax(0, 1fr) auto; }

/* Below --bp-md the three-track list resolved the name column to 77px and every
   service wrapped to two or three lines, because the third datum was given more
   room than the thing it describes. Narrow, the row is name + figure, and the
   third datum drops to its own line underneath. */
.measure__panel-head,
.measure__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "name  price"
    "meta  meta";
  column-gap: var(--space-sm);
  row-gap: var(--space-3xs);
  align-items: baseline;
  /* docs/uniqueness.md move 6: every horizontal rule on the page is a tick
     rule. background-color stays free for the hover so the two do not fight. */
  background: var(--tick-rule-fine);
  background-position: bottom;
}
.measure__panel-head > span:nth-child(1),
.measure__panel-name { grid-area: name; }
.measure__panel-head > span:nth-child(2),
.measure__depth { grid-area: price; text-align: end; }
.measure__panel-head > span:nth-child(3),
.measure__defect { grid-area: meta; text-align: start; }

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

/* The rows take whatever height the panel was stretched to. A five-row add-on
   panel beside a twelve-row service panel otherwise left 336px of bare card at
   its foot; grown and centred, the same panel reads as the sparser of two
   instruments rather than as a box someone forgot to fill. Where the panel is
   not stretched — every service page — there is no free space and no growth. */
.measure__row {
  flex: 1 0 auto;
  align-content: center;
  padding-block: var(--space-2xs);
  transition: background-color var(--dur-fast) var(--ease-state);
}
.measure__row:hover { background-color: var(--surface-accent-wash); }

.measure__panel-name {
  font-family: var(--font-display);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}
/* The figure is the thing this panel is read for, so it carries the hierarchy
   in size and weight. It was the same tonal value as the name beside it and
   only the accent hue told them apart, which is hierarchy by colour. */
.measure__depth {
  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);
  white-space: nowrap;
}
.measure__defect {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--tracking-mono-label);
  color: var(--text-muted);
}

/* auto absorbs whatever height a stretched panel was given, so the note sits on
   the panel foot rather than leaving the dead quadrant open underneath it */
.measure__note {
  margin-block-start: auto;
  padding-block-start: var(--space-sm);
  font-size: var(--text-caption);
  line-height: var(--leading-snug);
  color: var(--text-muted);
}

.measure__col { display: flex; flex-direction: column; gap: var(--space-stack); }

/* --- the index price panel: two instrument columns, not one 660px box -----
   Stretched, not start-aligned: the five-row add-on panel ended 302px above the
   twelve-row service panel and left the right quadrant of the section dead. */
.measure__panels { display: grid; gap: var(--grid-gap); }

@media (min-width: 768px) {
  .measure__panel-head,
  .measure__row {
    grid-template-columns: var(--measure-cols);
    grid-template-areas: "name price meta";
  }
  .measure__panel-head > span:nth-child(3),
  .measure__defect { text-align: end; }

  /* two tracks, so the row is one area wide and the "meta" line is not
     reserved under a datum that does not exist */
  .measure__panel--pair .measure__panel-head,
  .measure__panel--pair .measure__row { grid-template-areas: "name price"; }
}

@media (min-width: 1024px) {
  .measure__panels { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }

  .measure__inner {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    align-items: center;
    column-gap: var(--space-3xl);
  }
  /* the head sits on the photograph's top edge. Centred, it floated half a
     screen down the column and opened bare ground between the block above and
     this one's heading. */
  .measure__col { grid-column: 1; grid-row: 1; align-self: start; }
  .measure__media {
    grid-column: 2;
    grid-row: 1;
    aspect-ratio: var(--ratio-tall);
    /* 50vw is measured from this element's own containing block, not the page,
       so the old calc(50% - 50vw) pulled the photograph 670px out and .measure
       clipped a third of it — and, being ratio-locked, it grew to 1664px tall
       and opened a screen of bare ground beside the reading column.
       The gutter plus the wrap's outer margin is the real distance to the
       viewport edge. */
    /* 100vw counts the classic Windows scrollbar and <body> stops growing at
       --width-page, so the raw expression overstated the wrap's outer margin
       by half a scrollbar at every width and by hundreds of pixels above
       1,920 — where the frame ran past the viewport edge and .measure clipped
       it. Capped at the page width the wide case is exact; the ~8px scrollbar
       residue has no CSS remedy, no unit reports the viewport without it. */
    margin-inline-end: calc(var(--gutter) * -1 - max(0px, (min(100vw, var(--width-page)) - var(--width-wide)) / 2));
    border-start-end-radius: var(--radius-sharp);
    border-end-end-radius: var(--radius-sharp);
  }
  /* the offset overlap belongs to the service-page layout only: unscoped it
     also pushed the index's left price panel under its add-on panel */
  .measure__col .measure__panel {
    position: relative;
    z-index: var(--z-raised);
    margin-inline-end: calc(var(--space-4xl) * -1);
  }

  /* A landscape frame crushed into the portrait track loses everything except
     its middle sixth. Where the file is 16:9 the media states its own ratio.
     Declared after .measure__media: same specificity, so order decides. */
  .measure__media--wide { aspect-ratio: var(--ratio-card); }
}

/* --------------------------------------------------------------------------
   THE MIRRORED, UNCARDED VARIANT — one city page's block 03.
   The other city page runs this block as a raised instrument panel overlapping
   a photograph that hangs off the END viewport edge. Printing the same shape
   under the same verbatim h2 is what still made the two pages read as one page
   seen twice, and changing the frame and the eyebrow was a caption change, not
   a structural one. Here the drive times are set inline in the reading column
   as bare ruled rows — no card, no raised surface, no overlap, therefore
   nothing covering the chip — and the photograph takes the START column and
   hangs off the start edge instead. Same component, same rows, mirrored shape.
   -------------------------------------------------------------------------- */
.measure--inline .measure__panel {
  padding: 0;
  background: none;
  border: 0;
  border-radius: var(--radius-sharp);
  clip-path: none;
}
/* the frame here is a 3:2 file and states its own ratio, the way --wide does */
.measure--inline .measure__media { aspect-ratio: var(--ratio-bleed); }

@media (min-width: 1024px) {
  /* the reading column is the wide one on this side of the mirror */
  .measure--inline .measure__inner { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  .measure--inline .measure__col { grid-column: 2; }
  .measure--inline .measure__media {
    grid-column: 1;
    /* stretched, not ratio-locked: at 3:2 the frame closed 531px into an 825px
       row and left ~294px of ground under it. A grid item with a definite
       stretched height ignores aspect-ratio, and .media already covers, so the
       photograph fills the column and the reading column sets the height. */
    align-self: stretch;
    aspect-ratio: auto;
    /* the same reach as the end-side bleed, measured from this element's own
       containing block: the gutter plus whatever the wrap's outer margin is */
    margin-inline-start: calc(var(--gutter) * -1 - max(0px, (min(100vw, var(--width-page)) - var(--width-wide)) / 2));
    margin-inline-end: 0;
    border-start-start-radius: var(--radius-sharp);
    border-end-start-radius: var(--radius-sharp);
    border-start-end-radius: var(--radius-card);
    border-end-end-radius: var(--radius-card);
  }
  /* no overlap and no raised layer: the rows belong to the column */
  .measure--inline .measure__col .measure__panel {
    position: static;
    margin-inline-end: 0;
  }

  /* the frame reaches the start viewport edge here, so the chip reads from the
     inside corner rather than sitting 8px off the edge of the page */
  .measure--inline .measure__media .chip {
    inset-inline-start: auto;
    inset-inline-end: var(--chip-offset);
  }
}

/* --------------------------------------------------------------------------
   THE TIER PANEL — the same instrument, read on three channels instead of one.
   Service · Duration · I · II · III. docs/content.md §Vehicle size tiers.

   Wide, five tracks on the panel's own inherited track list, so the head sits
   over its columns exactly as it does on the three-track version. Narrow, a
   three-column money table does not fit at 390 and a table that scrolls
   sideways hides two thirds of the prices as surely as a dropdown would, so
   the row becomes a card: name and duration on one line, then one full-width
   row per size, each carrying its own numeral. Nothing leaves the DOM.
   -------------------------------------------------------------------------- */
.measure__panel--tiers {
  --measure-cols: minmax(0, 1.7fr) minmax(min-content, 0.8fr) repeat(3, minmax(min-content, 0.78fr));
}

.measure__panel--tiers .measure__panel-head,
.measure__panel--tiers .measure__row {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: none;
  row-gap: var(--space-2xs);
  align-items: center;
}
.measure__panel--tiers .measure__row { padding-block: var(--space-xs); }

.measure__panel--tiers .measure__panel-name { grid-column: 1; grid-row: 1; }
.measure__panel--tiers .measure__defect { grid-column: 2; grid-row: 1; text-align: end; }
.measure__panel--tiers .tierfig { grid-column: 1 / -1; }

.measure__panel--tiers .measure__panel-head > span { grid-row: 1; }
.measure__panel--tiers .measure__panel-head > span:nth-child(1) { grid-column: 1; text-align: start; }
.measure__panel--tiers .measure__panel-head > span:nth-child(2) { grid-column: 2; text-align: end; }
/* the three channel names have no columns to sit over until the table is a
   table; until then every figure carries its own numeral instead */
.measure__panel--tiers .measure__panel-head > span:nth-child(n + 3) { display: none; }

/* the key is the legend for twenty-one figures: full width, above both panels */
.measure__panels > .tierkey { grid-column: 1 / -1; }

@media (min-width: 768px) {
  .measure__panel--tiers .measure__panel-head,
  .measure__panel--tiers .measure__row {
    grid-template-columns: var(--measure-cols);
    grid-template-areas: none;
    row-gap: var(--space-3xs);
  }
  /* the three channel names, pinned to the three channels. Without an explicit
     column each one auto-places against the base rule's unresolved grid-area
     and the head reads II III I. */
  .measure__panel--tiers .measure__panel-head > span:nth-child(n + 3) {
    display: block;
    grid-row: 1;
    text-align: end;
  }
  .measure__panel--tiers .measure__panel-head > span:nth-child(3) { grid-column: 3; }
  .measure__panel--tiers .measure__panel-head > span:nth-child(4) { grid-column: 4; }
  .measure__panel--tiers .measure__panel-head > span:nth-child(5) { grid-column: 5; }
  .measure__panel--tiers .tierfig { grid-column: auto; grid-row: 1; }
  /* one figure across three channels, not the same number printed three times */
  .measure__panel--tiers .tierfig--span { grid-column: 3 / -1; }
}

@media (min-width: 1024px) {
  /* five channels want the wider of the two tracks; the five-row add-on panel
     beside it does not */
  .measure__panels--tiers { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); }
}

/* ==========================================================================
   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); }
}

/* ==========================================================================
   06 ACCREDITATION — the largest real gap against the reference board. Built
   with the M10 bordered-cell device the trust rail uses, one cell of which is
   a photograph.

   The marks are set as TYPE, not logotypes. We have no licence to reproduce
   the Gtechniq, XPEL or IDA wordmarks, and an approximation of a certification
   mark is worse than none — it is the one class of graphic where a redraw is
   a false claim rather than a style choice. 1 image.
   ========================================================================== */

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

.certs__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  border: var(--border-width-hair) solid var(--border-soft);
  clip-path: var(--chamfer-clip);
  background: var(--chamfer-edge), var(--surface-page);
}

/* the photograph is a cell, not a banner: it sits inside the same 1px
   division as the four marks so the block reads as one instrument plate */
.certs__frame {
  position: relative;
  aspect-ratio: var(--ratio-card);
  border-block-end: var(--border-width-hair) solid var(--border-soft);
}

.certs__cell {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding: var(--card-pad-lg);
  border-block-end: var(--border-width-hair) solid var(--border-soft);
  transition: background-color var(--dur-fast) var(--ease-state);
}
.certs__cell:hover { background: var(--surface-raised); }
.certs__cell:last-child { border-block-end: 0; }

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

.certs__line {
  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-secondary);
}

.certs__means {
  margin-block-start: auto;
  padding-block-start: var(--space-sm);
  background: var(--tick-rule-fine);
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
  color: var(--text-muted);
}

@media (min-width: 768px) {
  .certs__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .certs__frame { grid-column: 1 / -1; aspect-ratio: var(--ratio-wide); }
  .certs__cell { border-inline-start: var(--border-width-hair) solid var(--border-soft); }
  .certs__cell:nth-child(even) { border-inline-start: 0; }
  .certs__cell:nth-last-child(-n + 2) { border-block-end: 0; }
}

@media (min-width: 1024px) {
  .certs__grid { grid-template-columns: minmax(0, 1fr) repeat(2, minmax(0, 1fr)); }
  .certs__frame { grid-column: 1; grid-row: 1 / span 2; aspect-ratio: auto; border-block-end: 0; }
  .certs__cell { border-inline-start: var(--border-width-hair) solid var(--border-soft); }
  .certs__cell:nth-child(even) { border-inline-start: var(--border-width-hair) solid var(--border-soft); }
  .certs__cell:nth-child(2),
  .certs__cell:nth-child(3) { border-block-end: var(--border-width-hair) solid var(--border-soft); }
  .certs__cell:nth-child(4),
  .certs__cell:nth-child(5) { border-block-end: 0; }
}

/* ==========================================================================
   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); }
}
