/* ============================================================
   Bathman Refinishing — Variation A · "The Surface"
   Warm-neutral editorial. Fraunces display / Karla text.
   Signature: the glaze sweep — a drag reveal that re-coats
   both the photograph and the headline as you pull it.
   ============================================================ */

/* ---------- tokens ---------- */
:root {
  --porcelain: #f6f3ee;
  --chalk:     #fffdfa;
  --ink:       #191512;
  --ink-soft:  #4a423a;
  --stone:     #8a8279;
  --brass:     #a47c3a;
  --brass-dim: #c9b48a;
  --walnut:    #4a3527;
  --hairline:  rgba(25, 21, 18, .13);

  --display: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --text:    "Karla", "Helvetica Neue", Arial, sans-serif;

  --t-xs:   .75rem;
  --t-sm:   .8125rem;
  --t-base: 1.0625rem;
  --t-lg:   clamp(1.125rem, .98rem + .5vw, 1.375rem);
  --t-xl:   clamp(1.45rem, 1.1rem + 1.3vw, 2rem);
  --t-2xl:  clamp(1.9rem, 1.3rem + 2.4vw, 3rem);
  --t-3xl:  clamp(2.5rem, 1.1rem + 5.2vw, 5.5rem);

  --gutter: clamp(1.25rem, 5vw, 4.5rem);
  --stack:  clamp(4rem, 8vw, 8rem);
  --measure: 33rem;
  --edge:   min(1240px, 100% - var(--gutter) * 2);

  --ease: cubic-bezier(.22, .61, .36, 1);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--porcelain);
  color: var(--ink);
  font: 400 var(--t-base)/1.65 var(--text);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
button { font: inherit; color: inherit; }
/* Mobile touch: fire taps immediately (no 300ms double-tap wait) and suppress
   the default grey flash — :active/:focus states below still show feedback.
   The reveal stage keeps its own touch-action (pan-y) for the drag gesture. */
a, button, summary, label, select {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

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

.wrap { width: var(--edge); margin-inline: auto; }

/* The masthead is sticky, so an anchor jump would otherwise land its heading
   underneath it. Every in-page target clears the header plus a little air. */
:target,
#top, #work, #reviews, #services, #area, #faq, #quote { scroll-margin-top: 5.5rem; }
/* Phones run a taller masthead — below 430px the wordmark stacks onto two
   lines beside the two-line phone lockup — so the offset grows with it. */
@media (max-width: 860px) {
  :target,
  #top, #work, #reviews, #services, #area, #faq, #quote { scroll-margin-top: 6.25rem; }
}

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--porcelain);
  padding: .75rem 1.25rem;
}
.skip:focus { left: 1rem; top: 1rem; }

/* ---------- shared type ---------- */
.eyebrow {
  font-size: var(--t-xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--stone);
  font-weight: 600;
}
.lede {
  font-size: var(--t-lg);
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: var(--measure);
}
/* a lede that no longer shares its row with an image can run wider */
.lede--wide { max-width: 52rem; }

/* Section headings — Fraunces, soft optical wonk */
.h-sect {
  font-family: var(--display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 30, "WONK" 1;
  font-weight: 500;
  font-size: var(--t-2xl);
  line-height: 1.07;
  letter-spacing: -.018em;
  max-width: 20ch;
}

/* A section heading that stands alone — no eyebrow, no lede beneath it.
   Given a little more air so a three-word head still reads as a section
   opener rather than a stray line above the list. */
.h-sect--lead { font-size: var(--t-2xl); max-width: none; }

/* An unverified claim. Subtle in A by design; every instance is
   catalogued in REVIEW-BEFORE-PUBLISH.md for the owner to confirm. */
.claim {
  border-bottom: 1px dotted var(--brass-dim);
  cursor: help;
}

/* ---------- header ---------- */
.masthead {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--porcelain) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease);
}
.masthead[data-stuck="true"] { border-bottom-color: var(--hairline); }
.masthead__in {
  width: var(--edge); margin-inline: auto;
  display: flex; align-items: center; gap: 2rem;
  padding-block: 1.05rem;
}
.wordmark {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 600;
  font-size: 1.15rem;
  letter-spacing: -.02em;
  text-decoration: none;
  white-space: nowrap;
}
.wordmark span { color: var(--brass); }
.masthead nav { margin-left: auto; display: flex; gap: 1.85rem; }
.masthead nav a {
  font-size: var(--t-sm);
  letter-spacing: .04em;
  text-decoration: none;
  color: var(--ink-soft);
  padding-block: .3rem;
  border-bottom: 1px solid transparent;
  transition: color .2s, border-color .2s;
}
.masthead nav a:hover { color: var(--ink); border-bottom-color: var(--brass); }
.tel-pill {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px;
  font-size: var(--t-sm); font-weight: 700; letter-spacing: .02em;
  text-decoration: none;
  padding: .6rem 1.1rem;
  border: 1px solid var(--brass);
  border-radius: 100px;
  color: var(--ink);
  transition: background .25s var(--ease), color .25s var(--ease);
}
.tel-pill:hover { background: var(--brass); color: var(--chalk); }
.masthead nav + .tel-pill { margin-left: 0; }

/* ---------- phone lockup ----------
   Vanity spelling above, dialable digits below. Both lines belong to one
   link, so the whole stack is the tap target — the digits are never a
   separate, smaller thing to hit. B-A-T-H-M-A-N = 228-4626. */
.tel-stack {
  display: flex; flex-direction: column; align-items: center;
  line-height: 1.12;
}
.tel-stack__vanity {
  font-weight: 700;
  letter-spacing: .06em;
}
.tel-stack__digits {
  font-size: .82em;
  font-weight: 600;
  letter-spacing: .04em;
  opacity: .78;
  font-variant-numeric: tabular-nums;
}
.tel-pill { padding-block: .5rem; }
.tel-pill .tel-stack__vanity { font-size: 1.02em; }

/* the two-line lockup needs a shorter uppercase tracking than a normal btn */
.btn--tel { padding-block: .8rem; letter-spacing: 0; text-transform: none; }
.btn--tel .tel-stack__vanity {
  font-size: var(--t-sm); letter-spacing: .09em; text-transform: uppercase;
}
.btn--tel .tel-stack__digits { letter-spacing: .06em; }

/* Inline in a sentence — stays on one line, digits de-emphasised. The
   vertical padding lifts it to the WCAG 2.2 §2.5.8 24px floor; an inline
   link in body copy is only ~22px tall on its own. */
.tel-inline {
  color: var(--brass); font-weight: 700; white-space: nowrap;
  display: inline-block; padding-block: .18rem;
}
.tel-inline span { font-weight: 600; opacity: .8; }
/* Below 860px the nav is hidden, and the pill must go back to the top-right
   corner. It does NOT do that on its own: `display: none` removes an element
   from the layout but NOT from selector matching, so `.masthead nav +
   .tel-pill` above keeps firing here — cancelling `margin-left: auto` with no
   nav left to push against. The pill then sits immediately after the wordmark,
   mid-header, with the whole right-hand gutter empty: measured 99px of dead
   space at 360, 132px at 393, 168px at 430 and 380px at 768. Restoring the
   auto margin where the nav is gone is the whole fix; the desktop override
   above must stay, because there the nav really is the thing to sit beside. */
@media (max-width: 860px) {
  .masthead nav { display: none; }
  .masthead nav + .tel-pill { margin-left: auto; }
}
/* Narrow phones: the two-line phone lockup is wider than the old single-line
   pill, so the wordmark stacks onto two lines instead of truncating to
   "Bathman Refini…". Two two-line blocks side by side read as deliberate. */
@media (max-width: 430px) {
  .masthead__in { gap: .75rem; align-items: center; }
  .wordmark {
    min-width: 0; font-size: 1.02rem; line-height: 1.12;
    display: flex; flex-direction: column;
  }
  .tel-pill { flex: none; padding: .5rem .8rem; }
  .tel-pill .tel-stack__vanity { font-size: .95rem; }
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: .6rem;
  padding: 1.0rem 1.9rem;
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--ink);
  border-radius: 2px;
  cursor: pointer;
  transition: transform .25s var(--ease), background .25s var(--ease),
              color .25s var(--ease), border-color .25s var(--ease);
}
.btn--solid { background: var(--ink); color: var(--porcelain); }
.btn--solid:hover { background: var(--brass); border-color: var(--brass); transform: translateY(-2px); }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--porcelain); transform: translateY(-2px); }
.btn--light { background: var(--porcelain); color: var(--ink); border-color: var(--porcelain); }
.btn--light:hover { background: var(--brass); border-color: var(--brass); color: var(--chalk); transform: translateY(-2px); }

/* ============================================================
   HERO — type beside the evidence
   ============================================================ */
.hero {
  position: relative;
  width: var(--edge);
  margin-inline: auto;
  padding-block: clamp(1.75rem, 3vw, 2.5rem) 0;
}
.hero__eyebrow { margin-bottom: 1rem; }

/* The headline is ordinary page type now, not two clipped copies inside the
   photograph, so it no longer needs locked font metrics or nowrap. */
.hero__title {
  font-family: var(--display);
  font-optical-sizing: none;
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500;
  font-size: var(--t-3xl);
  line-height: .96;
  letter-spacing: -.03em;
  text-wrap: balance;
  color: var(--ink);
}
.hero__title em { font-style: italic; color: var(--brass); }

/* The reveal stage. Two stacked layers; the top one is clipped by --pos, so
   dragging sweeps a fresh coat across the picture.
   4:5 at EVERY width, matching the 4:5 masters, so object-fit: cover never has
   anything to crop — the visitor sees 100% of the file on every device. The old
   stage was a 16:10/2.5:1 band, which showed 45–86% of the file depending on
   screen and, worse, forced a band-shaped source crop that was unreadable. */
.reveal {
  position: relative;
  width: var(--edge);
  margin: 1.25rem auto 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 3px;
  background: var(--ink);
  touch-action: pan-y;
  cursor: ew-resize;
  --pos: 50%;
}

/* Single column below 901px, stacked in DOM order — except the deck, which
   drops below the buttons. Proof before prose: on a phone the fixture has to
   change before the visitor will read anything, and with the deck in its
   reading position the photograph started 61% of the way down the first screen,
   behind a wall of text. `order` moves only the deck, which is not focusable,
   so the slider and the buttons keep their DOM order on screen.
   Capped well short of full width — at 768px a full-bleed 4:5 stage would stand
   862px tall and become a wall. NB: `100%` here, not var(--edge): --edge is
   `100% - gutter*2`, and nested inside .hero it subtracts the gutter a second
   time, which is what made the stage narrower than the text beside it. */
@media (max-width: 900px) {
  .hero { display: flex; flex-direction: column; }
  .hero__deck { order: 1; margin-top: 1.75rem; }
  .hero .reveal { width: 100%; max-width: 30rem; margin-inline: 0; }
}

/* Two columns from 901px. The fold is the scarce resource, so the stage is
   sized by HEIGHT and its width follows from the ratio — that way the whole
   hero lands in the first screenful without the picture being cropped to fit.

   The two flexible rows (1fr top and bottom) exist so the copy CENTRES against
   the stage instead of stacking at its top. Once the stage is allowed to grow
   past 600px the copy no longer fills the column, and top-aligned type beside a
   tall photograph leaves a wedge of white under the trust bullets. The copy
   elements keep their own grid areas — no wrapper element, so the DOM and the
   reading order are untouched. */
@media (min-width: 901px) {
  .hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: 1fr auto auto auto auto auto 1fr;
    column-gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
  .hero__eyebrow { grid-area: 2 / 1; }
  .hero__title   { grid-area: 3 / 1; }
  .hero__deck    { grid-area: 4 / 1; }
  .hero__foot    { grid-area: 5 / 1; }
  .hero__trust   { grid-area: 6 / 1; }
  .hero .reveal {
    grid-area: 1 / 2 / 8 / 3;
    align-self: center;
    /* The 600px ceiling that used to close this clamp was the whole bug. Above
       roughly 840px of viewport it bound, and the hero froze at a fixed 640px
       no matter how tall the window was — 67% of a 1080p screen, with 361px of
       the next section's top padding showing under it and reading as an
       unfinished page. The formula was always right; only the cap was wrong.
       The 1000px ceiling left in its place is a guard for very tall windows,
       not a working limit — `audit-c.mjs` now asserts the fold is filled from
       BOTH sides, so neither this nor a future shrink can drift unnoticed. */
    --stage-h: clamp(360px, calc(100svh - 15rem), 1000px);
    height: var(--stage-h);
    width: calc(var(--stage-h) * 4 / 5);
    margin: 0;
  }
}

/* Past ~1600px the stage is wide enough that the 1240px --edge starts squeezing
   the copy column instead of the picture — at 1920 the text had 504px to the
   photograph's 672. Widen the hero (and only the hero) so both halves grow
   together; every section below keeps the 1240px measure, which is a reading
   width and should not track the monitor. */
@media (min-width: 1600px) {
  .hero { width: min(1480px, 100% - var(--gutter) * 2); }
}

.reveal__layer { position: absolute; inset: 0; }
.reveal__layer img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  user-select: none; -webkit-user-drag: none;
}
/* "after" sits on top, clipped from the left edge to the handle */
.reveal__layer--after { clip-path: inset(0 0 0 var(--pos)); }

/* Each caption hugs its own outer edge, so the clip never eats it:
   "before" pins left, "after" pins right.
   These used to ride on a full-width gradient scrim that carried the headline
   too. With the type gone the scrim went with it, so each caption carries its
   own small plate instead — a few hundred square px of cover rather than half
   the photograph. */
.reveal__cap {
  position: absolute;
  bottom: clamp(.7rem, 2.5vw, 1.15rem);
  padding: .34rem .6rem;
  border-radius: 2px;
  font-family: var(--text);
  font-size: var(--t-xs);
  letter-spacing: .2em;
  text-transform: uppercase;
  font-weight: 700;
}
.reveal__layer--before .reveal__cap {
  left: clamp(.7rem, 2.5vw, 1.15rem);
  color: #e2d9cb;
  background: rgba(18,14,10,.74);
}
.reveal__layer--after .reveal__cap {
  right: clamp(.7rem, 2.5vw, 1.15rem);
  color: var(--brass-dim);
  background: rgba(14,11,8,.78);
}

/* The "after" caption is pinned right and lives inside the clipped layer, so
   any part of it left of the handle gets cut. At wide widths it is short
   enough to sit clear; on a narrow phone it isn't, and reads "TER — ONE DAY".
   Shorten it there rather than let the clip eat the word. */
.reveal__cap-short { display: none; }
@media (max-width: 420px) {
  .reveal__cap-long  { display: none; }
  .reveal__cap-short { display: inline; }
}

/* handle */
.reveal__handle {
  position: absolute; top: 0; bottom: 0;
  left: var(--pos);
  width: 2px;
  margin-left: -1px;
  background: linear-gradient(to bottom,
    transparent, var(--brass-dim) 12%, var(--chalk) 50%, var(--brass-dim) 88%, transparent);
  z-index: 4;
}
.reveal__grip {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--chalk);
  border: 1px solid var(--brass-dim);
  box-shadow: 0 6px 26px rgba(20,16,12,.4);
  transition: transform .2s var(--ease);
}
.reveal:hover .reveal__grip { transform: translate(-50%, -50%) scale(1.06); }
.reveal__grip::before,
.reveal__grip::after {
  content: ""; position: absolute;
  width: 0; height: 0;
  border-block: 5px solid transparent;
}
.reveal__grip::before { left: 15px; border-right: 7px solid var(--ink); }
.reveal__grip::after  { right: 15px; border-left: 7px solid var(--ink); }
.reveal__range {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0; margin: 0; cursor: ew-resize;
  z-index: 5;
}
.reveal__range:focus-visible ~ .reveal__handle .reveal__grip {
  outline: 2px solid var(--brass);
  outline-offset: 3px;
}

/* hero footer: ctas + trust. Both now sit inside .hero__copy, so they take the
   column width rather than measuring themselves against the page. */
.hero__foot {
  margin-top: 1.5rem;
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem;
}
.hero__trust {
  display: flex; flex-wrap: wrap; gap: .5rem 1.4rem;
  margin-top: 1.25rem;
  font-size: var(--t-sm); color: var(--stone);
}
.hero__trust li { display: flex; align-items: center; gap: .5rem; }
.hero__trust li::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--brass); flex: none;
}
.hero__deck {
  margin-top: 1.25rem;
  max-width: 46rem;
  font-size: var(--t-lg);
  line-height: 1.5;
  color: var(--ink-soft);
}
.hero__deck strong { color: var(--ink); font-weight: 700; }

/* ============================================================
   prose — the privacy page only
   The landing page is composed section by section and needs no generic type
   rules; a policy page is the one place on this site that is just running
   text, so it gets a measure, a heading rhythm and nothing else.
   ============================================================ */
/* The two links to the privacy page sit inside small print, which rendered
   them 42×15px — under the WCAG 2.2 §2.5.8 24px floor, and caught by
   audit-c.mjs the moment they were added. Padded to clear it without changing
   the type size or the line rhythm of the paragraph they live in. */
.form__note a,
.foot__legal a {
  display: inline-block;
  padding-block: .34rem;
  min-height: 24px;
}

.prose { max-width: 68ch; }
.prose h2 {
  font-family: var(--display);
  font-optical-sizing: none;
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500;
  font-size: var(--t-xl);
  line-height: 1.15;
  letter-spacing: -.015em;
  margin: 2.75rem 0 .9rem;
}
.prose p { margin: 0 0 1.1rem; color: var(--ink-soft); }
.prose ul { margin: 0 0 1.4rem; padding-left: 1.1rem; color: var(--ink-soft); }
.prose li { margin-bottom: .55rem; }
.prose strong { color: var(--ink); font-weight: 700; }

/* ============================================================
   sections
   ============================================================ */
.sect { padding-block: var(--stack); }
.sect--tint { background: var(--chalk); }
.sect--dark { background: var(--walnut); color: var(--porcelain); }
.sect__head { margin-bottom: clamp(2.5rem, 5vw, 4rem); }

/* --- the credo (owner, 2026-08-13) ---
   "Quality workmanship at an affordable price", the last thing read before the
   estimate form. Sits between #faq and #quote in the markup.

   THIS IS THE SECOND BUILD. The first set the line alone, in caps, at display
   size, on a full-bleed ink slab — and read as a cheap advertisement. The
   diagnosis was not typographic: the sentence is the most generic claim in the
   trade, and enlarging a generic claim isolates it as a slogan. The fix is to
   corroborate rather than enlarge — the promise signed on the left, a customer
   who wrote the same thing on the right. Two columns also fill the width the
   slab left empty, so the layout problem and the credibility problem had the
   same answer.

   Porcelain, not ink: the page is a warm editorial ground throughout, and the
   one black band was the loudest thing on it. A single hairline above the grid
   is all the separation this needs — the same device .claims and .quotes use —
   and the porcelain → chalk step into #quote closes it without a second rule.

   No top padding on the section: #faq already ends on a full --stack, so the
   rule would otherwise float in the middle of a very large gap. */
.credo { background: var(--porcelain); padding-block: 0 clamp(3rem, 6vw, 5rem); }
.credo__grid {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
  border-top: 1px solid var(--hairline);
  padding-top: clamp(2.5rem, 5vw, 3.75rem);
}
.credo__line {
  font-family: var(--display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 30, "WONK" 1;
  font-weight: 500;
  font-size: var(--t-2xl);
  line-height: 1.08;
  letter-spacing: -.018em;
  max-width: 18ch;
  margin-top: 1rem;
}
.credo__sig {
  margin-top: 1.5rem;
  font-size: var(--t-sm); letter-spacing: .06em; color: var(--ink-soft);
}
.credo__sig span { font-weight: 700; color: var(--ink); letter-spacing: .02em; }
.credo__sig span::after { content: " ·"; color: var(--stone); font-weight: 400; }

/* The proof column. A brass-dim edge rather than a card: the page has no
   boxes, and a bordered panel here would be the only one on it. */
.credo__proof { border-left: 2px solid var(--brass-dim); padding-left: clamp(1.25rem, 2.5vw, 2rem); }
.credo__proof blockquote p {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-size: var(--t-lg);
  line-height: 1.45;
  quotes: "\201C" "\201D";
}
.credo__proof blockquote p::before { content: open-quote; margin-left: -.42em; color: var(--brass-dim); }
.credo__proof blockquote p::after  { content: close-quote; color: var(--brass-dim); }
.credo__proof figcaption {
  margin-top: 1.15rem;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .25rem .9rem;
  font-size: var(--t-xs); letter-spacing: .1em; text-transform: uppercase;
  color: var(--stone);
}
.credo__who { font-weight: 700; color: var(--ink-soft); }
.credo__where::before, .credo__proof figcaption time::before {
  content: "·"; margin-right: .9rem; color: var(--hairline);
}
/* Yelp's Display Requirements apply at EVERY appearance of review content, so
   the link travels with the quote. Never hidden, never nofollow-stripped. */
/* min-height + inline-flex, matching `.quotes figcaption a`. Without it this
   link renders 20px tall — under the WCAG 2.2 §2.5.8 24px floor. An uppercase
   var(--t-xs) link is ~20px on its own line, so the floor has to be set
   explicitly every time this pattern is used; audit-c.mjs caught it here. */
.credo__proof figcaption a {
  margin-left: auto;
  display: inline-flex; align-items: center; min-height: 24px;
  color: var(--brass); white-space: nowrap;
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: var(--brass-dim);
}
.credo__proof figcaption a:hover,
.credo__proof figcaption a:focus-visible { color: var(--walnut); text-decoration-color: var(--walnut); }
.credo__proof figcaption sup { font-size: .7em; vertical-align: super; line-height: 0; }

@media (max-width: 820px) {
  .credo__grid { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .credo__proof figcaption a { margin-left: 0; }
}


/* --- section head paired with a supporting image on the right --- */
.sect__split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .8fr);
  gap: clamp(1.75rem, 4vw, 4.5rem);
  align-items: center;
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
.sect__split .sect__head { margin-bottom: 0; }
.sect__media { margin: 0; position: relative; }
.sect__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 3px;
  background: var(--ink);
}
.sect__media figcaption {
  margin-top: .6rem;
  font-size: var(--t-xs); letter-spacing: .04em;
  color: var(--stone);
}
@media (max-width: 820px) {
  .sect__split { grid-template-columns: 1fr; gap: 1.5rem; }
  .sect__media { order: -1; }               /* image leads on mobile */
  .sect__media img { aspect-ratio: 16 / 10; }
}

/* --- the argument: three plain statements on brass hairlines --- */
.claims { display: grid; gap: 0; margin-top: 1rem; }
.claims li {
  display: grid;
  grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: 1rem 3rem;
  padding-block: 2rem;
  border-top: 1px solid var(--hairline);
  align-items: start;
}
.claims li:last-child { border-bottom: 1px solid var(--hairline); }
.claims dt {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500;
  font-size: var(--t-xl);
  line-height: 1.1;
  letter-spacing: -.02em;
  color: var(--brass);
}
.claims dd { margin: 0; color: var(--ink-soft); max-width: 46ch; }
@media (max-width: 720px) {
  .claims li { grid-template-columns: 1fr; gap: .5rem; }
}

/* --- reviews (Yelp) ---
   Pull-quotes, not a widget. The section is typographic on purpose: a
   third-party review carousel would drag in external JS, a font and a
   layout that belongs to someone else's brand, and this page has no
   dependencies to spend. Hairline rules and the display face carry it,
   the same way .claims and .services do.

   No star glyphs anywhere: Yelp requires their official branded sprite
   and forbids generic stars, so the rating is a numeral until that asset
   is dropped in (ASSETS-YELP.md). */

/* The live rating strip. `hidden` in the markup; app.js clears it only after
   /api/yelp answers, so a static deploy never shows an empty shell.
   [hidden] needs the !important guard because the flex display below would
   otherwise win over the UA's `display:none`. */
.yelp-strip[hidden] { display: none !important; }
.yelp-strip {
  display: inline-flex;
  align-items: baseline;
  gap: .75rem 1rem;
  flex-wrap: wrap;
  margin-top: 2rem;
  padding: .7rem 1.1rem;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  background: var(--chalk);
  text-decoration: none;
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
.yelp-strip:hover, .yelp-strip:focus-visible { border-color: var(--brass-dim); background: #fff; }
.yelp-strip__score {
  display: inline-flex;
  align-items: baseline;
  gap: .45rem;
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 600;
  font-size: var(--t-xl);
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
}
.yelp-strip__of { font-family: var(--text); font-size: var(--t-sm); font-weight: 400; color: var(--stone); letter-spacing: 0; }
.yelp-strip__meta { font-size: var(--t-sm); color: var(--ink-soft); }
.yelp-strip__mark { font-weight: 700; color: var(--ink); }
.yelp-strip sup { font-size: .6em; vertical-align: super; line-height: 0; }

/* Quote grid. Two columns from 860px; the cards are uneven in length by
   nature, so they align to the top rather than stretching to match. */
.quotes {
  list-style: none;
  margin: 3.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0 3.5rem;
  grid-template-columns: 1fr;
}
.quotes li { border-top: 1px solid var(--hairline); padding-block: 2.25rem; }
.quotes figure { display: grid; gap: 1.25rem; }
.quotes blockquote p {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 400;
  font-size: var(--t-lg);
  line-height: 1.45;
  letter-spacing: -.01em;
  color: var(--ink);
  max-width: 42ch;
  /* Typographic quotes are drawn by CSS so the quoted text in the HTML stays
     byte-for-byte what the customer wrote — nothing is added inside the
     string itself, which Yelp's no-modification rule turns into a
     correctness constraint rather than a nicety. */
  quotes: "\201C" "\201D";
}
.quotes blockquote p::before { content: open-quote; margin-left: -.42em; color: var(--brass-dim); }
.quotes blockquote p::after  { content: close-quote; color: var(--brass-dim); }
.quotes figcaption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .35rem .9rem;
  font-size: var(--t-xs);
  letter-spacing: .04em;
  color: var(--stone);
}
.quotes__who { font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); }
.quotes__where::before, .quotes figcaption time::before { content: "·"; margin-right: .9rem; color: var(--hairline); }
/* The underline is text-decoration rather than a border because the link also
   has to clear the WCAG 2.2 §2.5.8 24px tap-target floor: at this type size
   the text box is only 22px, so the box needs vertical padding — and a
   border-bottom would ride down with it, detaching the rule from the words.
   inline-flex + min-height pads the target without moving the underline. */
.quotes figcaption a {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  color: var(--brass);
  text-decoration: underline;
  text-decoration-color: var(--brass-dim);
  text-underline-offset: 3px;
  white-space: nowrap;
}
.quotes figcaption a:hover, .quotes figcaption a:focus-visible { color: var(--walnut); text-decoration-color: var(--walnut); }
.quotes figcaption sup { font-size: .7em; vertical-align: super; line-height: 0; }

.quotes__foot {
  margin-top: 2.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--hairline);
  display: grid;
  gap: 1.25rem;
  justify-items: start;
}
/* The button's tracking would otherwise push the ® a full letter-space away
   from the mark it belongs to. */
.quotes__foot sup { font-size: .65em; vertical-align: super; line-height: 0; letter-spacing: 0; margin-left: -.35em; }
/* Required attribution — small, but it must never be display:none. */
.quotes__attr { font-size: var(--t-xs); line-height: 1.6; color: var(--stone); max-width: 62ch; }

@media (min-width: 860px) {
  .quotes { grid-template-columns: 1fr 1fr; }
  /* With two columns the first TWO cards sit in the top row, so both need the
     rule that would otherwise only belong to child 1. */
  .quotes li:nth-child(-n+2) { border-top: 1px solid var(--hairline); }
}
@media (max-width: 520px) {
  /* The "Read on Yelp" link stops sharing a line with the attribution below
     560px; pushing it to its own row keeps the 44px tap target intact. */
  .quotes figcaption a { margin-left: 0; }
}

/* --- services --- */
.services { display: grid; gap: 0; }
.svc {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 1rem 2.5rem;
  padding-block: 2.25rem;
  border-top: 1px solid var(--hairline);
  align-items: baseline;
}
.services .svc:last-child { border-bottom: 1px solid var(--hairline); }
.svc__no {
  font-size: var(--t-xs); letter-spacing: .14em; color: var(--brass);
  font-weight: 700; font-variant-numeric: tabular-nums;
}
.svc__name {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500; font-size: var(--t-xl); line-height: 1.12;
  letter-spacing: -.02em;
}
.svc__body { color: var(--ink-soft); max-width: 44ch; }
@media (max-width: 820px) {
  .svc { grid-template-columns: 2.5rem minmax(0, 1fr); }
  .svc__body { grid-column: 2; }
}

/* --- gallery of before/after pairs --- */
.pairs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.pair figure { margin: 0; }
.pair .reveal {
  width: 100%; margin: 0;
  aspect-ratio: 4 / 5;
  border-radius: 2px;
}
.pair .reveal__grip { width: 44px; height: 44px; }
.pair .reveal__grip::before { left: 11px; }
.pair .reveal__grip::after  { right: 11px; }
.pair figcaption { margin-top: 1.1rem; }
.pair__name {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500; font-size: var(--t-lg); letter-spacing: -.015em;
}
.pair__note { margin-top: .3rem; font-size: var(--t-sm); color: var(--stone); }

/* ---------- featured comparison ---------- */
/* Left edge shared with the section heading and the diptych grid below —
   centring it left the caption on a different margin to everything else. */
/* 4:5 at every width, like every other photo on the page and like the 4:5
   masters themselves. This was a 3:2 stage holding a 4:5 file, which is the
   same defect the hero had: object-fit: cover threw away 47% of the frame
   above 700px and reduced the one pool step unit that photographs perfectly
   to an abstract close-up of its coping. Width is capped rather than the
   height cropped — at the old 880px a 4:5 stage would stand 1100px tall. */
.feature { margin: 0 0 clamp(2.5rem, 5vw, 4rem); max-width: 520px; }
.reveal--feature {
  width: 100%; margin: 0;
  aspect-ratio: 4 / 5;
  border-radius: 3px;
}
.feature figcaption { margin-top: 1.1rem; max-width: 52ch; }

/* ---------- diptych group heading ----------
   The grid used to start straight after the featured comparison's caption, so
   a visitor scrolling into it had to work out for themselves what the paired
   frames were. A subhead one step down from the section H2. */
.h-sub {
  font-family: var(--display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 30, "WONK" 1;
  font-weight: 500;
  font-size: var(--t-lg);
  line-height: 1.15;
  letter-spacing: -.012em;
}
.dips__head {
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--hairline);
}
.dips__note {
  margin-top: .5rem;
  max-width: 60ch;
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--stone);
}

/* ---------- diptychs ----------
   Two frames of the same job, side by side. Used where the camera moved
   between shots, which is most of them — a slider needs the two frames to
   register or the sweep reads as a glitch rather than a transformation. */
.dips {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.dip figure { margin: 0; }
.dip__pair {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 2px; background: var(--hairline);
  border-radius: 2px; overflow: hidden;
}
.dip__half {
  position: relative; display: block; padding: 0;
  border: 0; background: var(--ink); cursor: zoom-in;
  line-height: 0;
}
.dip__half img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
/* Hover feedback only where there is a real pointer. Fading a full-size photo
   forces a repaint of a large element, and on a phone that landed on the tap
   itself — it was the slowest interaction on the page. It also has no business
   on touch, where the hover state sticks after the finger lifts. */
@media (hover: hover) and (pointer: fine) {
  .dip__half img { transition: opacity .3s var(--ease); }
  .dip__half:hover img { opacity: .88; }
}
.dip__tag {
  position: absolute; left: .5rem; top: .5rem;
  font-family: var(--text);
  font-size: .625rem; letter-spacing: .14em; text-transform: uppercase;
  font-weight: 700; line-height: 1;
  padding: .32rem .5rem;
  background: rgba(20,16,12,.66);
  color: var(--chalk);
  border-radius: 2px;
}
.dip__tag--after { color: var(--brass-dim); }
.dip figcaption { margin-top: 1rem; }

/* The .more disclosure button was removed with its markup — every job renders. */

/* The detail strip (.dtls/.dtl/.dtl__cap) was removed with its markup — it held
   unpaired singles, and every photograph in this section is now half of a
   before/after pair. Its phone snap-rail rules went with it. */

/* ---------- lightbox ----------
   Native <dialog>, so focus trapping and Esc come from the platform. */
.lb {
  border: 0; padding: 0; max-width: 100vw; max-height: 100dvh;
  width: 100%; height: 100%;
  /* Opaque on purpose. At 96% alpha the browser still has to composite the
     whole page underneath before it can show the dialog, which cost ~230ms of
     interaction latency on a throttled phone. Solid lets it skip all of that;
     the 4% was invisible anyway. */
  background: #0e0b08;
  color: var(--porcelain);
}
.lb::backdrop { background: #0e0b08; }
.lb__in {
  height: 100%;
  display: grid; grid-template-rows: 1fr auto;
  padding: clamp(1rem, 3vw, 2.5rem);
  gap: 1rem;
}
.lb__img {
  min-height: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  margin: 0 auto;
}
.lb__bar {
  display: flex; align-items: center; justify-content: center;
  gap: 1rem; flex-wrap: wrap;
  padding-bottom: env(safe-area-inset-bottom);
}
.lb__cap { font-size: var(--t-sm); color: color-mix(in srgb, var(--porcelain) 78%, transparent); text-align: center; }
.lb__btn {
  width: 48px; height: 48px; flex: none;
  display: grid; place-items: center;
  border: 1px solid rgba(246,243,238,.3); border-radius: 50%;
  background: transparent; color: var(--porcelain);
  font-size: 1.1rem; cursor: pointer;
}
.lb__btn:hover { background: rgba(246,243,238,.14); }
.lb__close {
  position: absolute; top: 1rem; right: 1rem;
  top: calc(1rem + env(safe-area-inset-top));
}

/* corner tags inside the pair sliders */
.tag {
  position: absolute; top: .85rem;
  font-size: var(--t-xs); letter-spacing: .16em; text-transform: uppercase;
  font-weight: 700;
  padding: .35rem .7rem;
  background: rgba(20,16,12,.62);
  backdrop-filter: blur(6px);
  color: var(--chalk);
  border-radius: 2px;
  z-index: 3;
  pointer-events: none;
}
.tag--before { left: .85rem; }
.tag--after  { right: .85rem; color: var(--brass-dim); }

/* --- process: a real sequence, so numbering earns its place --- */
.steps { display: grid; gap: clamp(2rem, 4vw, 3rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.step__no {
  font-family: var(--display);
  font-variation-settings: "SOFT" 0, "WONK" 1;
  font-weight: 300;
  font-size: 3.25rem; line-height: 1;
  color: var(--brass);
  opacity: .55;
}
.step__name {
  margin-top: .9rem;
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500; font-size: var(--t-xl); letter-spacing: -.02em;
}
.step__body { margin-top: .6rem; color: var(--ink-soft); }
.sect--dark .step__body { color: color-mix(in srgb, var(--porcelain) 74%, transparent); }
.sect--dark .step__no { color: var(--brass-dim); }
.step__img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 2px;
  margin-top: 1.4rem;
  border: 1px solid rgba(246, 243, 238, .14);
}

/* --- compare (qualitative — no figures in this variation) --- */
.compare {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: 1px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
}
.compare__col { background: var(--porcelain); padding: clamp(1.75rem, 3vw, 2.75rem); }
.compare__col--ours { background: var(--chalk); }
.compare__title {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500; font-size: var(--t-xl); letter-spacing: -.02em;
}
.compare__col--ours .compare__title { color: var(--brass); }
.compare ul { margin-top: 1.5rem; display: grid; gap: .85rem; }
.compare li {
  display: grid; grid-template-columns: 1.3rem 1fr; gap: .75rem;
  font-size: var(--t-sm); color: var(--ink-soft); line-height: 1.55;
}
.compare li::before { content: "—"; color: var(--stone); }
.compare__col--ours li::before { content: "✓"; color: var(--brass); font-weight: 700; }

/* --- service area --- */
.area { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: clamp(2rem, 5vw, 5rem); align-items: start; }
@media (max-width: 860px) { .area { grid-template-columns: 1fr; } }
.area__media { margin: 1.75rem 0 0; }
.area__media img {
  width: 100%;
  aspect-ratio: 5 / 3;
  object-fit: cover;
  border-radius: 3px;
  background: var(--ink);
}
.area__list {
  display: flex; flex-wrap: wrap; gap: .5rem;
}
.area__list li {
  font-size: var(--t-sm);
  padding: .45rem .9rem;
  border: 1px solid var(--hairline);
  border-radius: 100px;
  color: var(--ink-soft);
}

/* --- faq --- */
.faq { max-width: 52rem; }
.faq details {
  border-top: 1px solid var(--hairline);
}
.faq details:last-of-type { border-bottom: 1px solid var(--hairline); }
.faq summary {
  cursor: pointer; list-style: none;
  padding-block: 1.6rem;
  display: grid; grid-template-columns: 1fr 1.5rem; gap: 1.5rem; align-items: center;
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 500;
  font-size: var(--t-lg);
  line-height: 1.3;
  letter-spacing: -.015em;
  transition: color .2s;
}
.faq summary:hover { color: var(--brass); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; justify-self: end;
  width: 13px; height: 13px;
  border-right: 1.5px solid var(--brass);
  border-bottom: 1.5px solid var(--brass);
  transform: rotate(45deg) translate(-3px, -3px);
  transition: transform .3s var(--ease);
}
.faq details[open] summary::after { transform: rotate(225deg) translate(-2px, -2px); }
.faq__a { padding-bottom: 1.7rem; max-width: 62ch; color: var(--ink-soft); }
.faq__a p + p { margin-top: .85rem; }
/* Source line under the cost figures. Deliberately quieter than the answer —
   it is provenance, not argument — but the links keep a visible underline and
   enough vertical padding to clear the WCAG 2.2 §2.5.8 24px tap-target floor,
   which is what caught the Yelp links out when they were added. */
.faq__src { font-size: var(--t-xs); color: var(--stone); margin-top: 1rem; }
.faq__src a {
  color: inherit; text-decoration: underline;
  text-underline-offset: 2px;
  display: inline-block; padding-block: .18rem;
}
.faq__src a:hover { color: var(--brass); }

/* --- closing cta + estimate form --- */
.closer__btns { display: flex; flex-wrap: wrap; gap: 1rem; }

.quote {
  display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
@media (max-width: 900px) { .quote { grid-template-columns: minmax(0, 1fr); } }

.form { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 560px) { .form__row { grid-template-columns: 1fr; } }
.field { display: grid; gap: .4rem; }
.field label {
  font-size: var(--t-xs); font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--stone);
}
.field input, .field select, .field textarea {
  font: inherit; font-size: var(--t-base);
  padding: .8rem .9rem;
  border: 1px solid var(--hairline); border-radius: 2px;
  background: var(--chalk); color: var(--ink);
  min-height: 48px;
}
.field textarea { min-height: 110px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--brass);
  outline: 2px solid color-mix(in srgb, var(--brass) 32%, transparent); outline-offset: 0;
}
.field input.is-invalid, .field textarea.is-invalid, .field select.is-invalid {
  border-color: #b3261e; outline: 2px solid rgba(179, 38, 30, .22);
}
.form__note { font-size: var(--t-sm); color: var(--stone); }
.field__opt  { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--stone); }
.field__hint { font-size: var(--t-sm); color: var(--stone); }
.field__err  { font-size: var(--t-sm); font-weight: 700; color: #b3261e; }
.field__err:empty { display: none; }

.filepick { font-size: var(--t-sm); padding: .6rem .7rem; cursor: pointer; width: 100%; min-width: 0; }
.filepick::file-selector-button {
  font: inherit; font-size: var(--t-xs); font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  padding: .6rem .95rem; margin-right: .9rem;
  border: 1px solid var(--ink); background: var(--porcelain); color: var(--ink);
  border-radius: 2px; cursor: pointer;
}
.filepick::file-selector-button:hover { background: var(--brass); border-color: var(--brass); color: var(--chalk); }

.thumbs { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: .3rem; }
.thumbs:empty { display: none; }
.thumb { position: relative; width: 76px; height: 76px; }
.thumb img { width: 100%; height: 100%; object-fit: cover; border-radius: 2px; border: 1px solid var(--hairline); }
.thumb__rm {
  position: absolute; top: -9px; right: -9px;
  width: 26px; height: 26px; border-radius: 50%;
  border: none; background: var(--ink); color: var(--porcelain);
  font-size: 16px; line-height: 1; cursor: pointer;
  display: grid; place-items: center; padding: 0;
  box-shadow: 0 1px 5px rgba(20, 16, 12, .35);
}
.thumb__rm:hover { background: var(--brass); color: var(--chalk); }

.form__status {
  font-size: var(--t-sm); font-weight: 700;
  padding: .85rem 1rem; border-radius: 2px; border-left: 4px solid;
}
.form__status--pending { background: #f1ece3; border-color: var(--stone); color: var(--ink-soft); }
.form__status--ok      { background: #e9f3ea; border-color: #3f7d46; color: #245b2b; }
.form__status--error   { background: #fdecea; border-color: #b3261e; color: #7f1d17; }

/* --- footer --- */
.foot {
  background: var(--walnut); color: var(--porcelain);
  padding-block: clamp(3rem, 6vw, 5rem) 2rem;
}
.foot__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 2.5rem;
  padding-bottom: 3rem;
  border-bottom: 1px solid rgba(246,243,238,.16);
}
.foot h3 {
  font-size: var(--t-xs); letter-spacing: .16em; text-transform: uppercase;
  color: var(--brass-dim); font-weight: 700; margin-bottom: 1rem;
}
/* inline-block + vertical padding lifts each footer link to a ≥24px tap
   target (WCAG 2.2 §2.5.8) without changing the visual rhythm much */
.foot a { color: var(--porcelain); text-decoration: none; display: inline-block; padding-block: .28rem; }
.foot a:hover { color: var(--brass-dim); }
.foot li + li { margin-top: .5rem; }
.foot__wordmark {
  font-family: var(--display);
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-weight: 600; font-size: 1.3rem; letter-spacing: -.02em;
  margin-bottom: .75rem;
}
/* `a.` on purpose: `.foot a` above sets display:inline-block and, being
   class+type, outranks a bare `.foot__tel`. Without matching that specificity
   the two lines run together inline and the number wraps mid-digits
   ("678-228-" / "4626"). */
.foot a.foot__tel {
  font-family: var(--display);
  display: inline-flex; flex-direction: column; align-items: flex-start;
  margin-bottom: .35rem; line-height: 1.15;
}
.foot__tel-digits { white-space: nowrap; }
.foot__tel-vanity { font-size: 1.45rem; font-weight: 600; letter-spacing: -.01em; }
.foot__tel-digits {
  font-family: var(--text);
  font-size: var(--t-base); font-weight: 600; letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
  color: var(--brass-dim);
}
.foot__legal {
  padding-top: 2rem;
  display: flex; flex-wrap: wrap; gap: .75rem 2rem;
  font-size: var(--t-sm);
  color: color-mix(in srgb, var(--porcelain) 62%, transparent);
}

/* --- mobile sticky call bar --- */
.callbar {
  position: fixed; inset: auto 0 0 0; z-index: 60;
  display: none;
  gap: 1px; background: var(--hairline);
  box-shadow: 0 -6px 26px rgba(20,16,12,.16);
}
.callbar a {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  padding: .7rem .35rem;
  min-height: 56px;
  font-size: var(--t-sm); font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
  text-decoration: none;
  line-height: 1.15;
}
/* Call is the widest slot — it carries two lines and is the likeliest tap.
   Estimate and Text share the rest evenly. */
.callbar__quote { flex: 1 1 0; background: var(--porcelain); color: var(--ink); }
.callbar__text  { flex: 1 1 0; background: var(--ink); color: var(--porcelain); }
.callbar__call  { flex: 1.35 1 0; background: var(--brass); color: var(--chalk); }
.callbar__digits {
  font-size: .78em; font-weight: 600; letter-spacing: .04em;
  opacity: .85; text-transform: none;
  font-variant-numeric: tabular-nums;
}
/* below ~360px the three labels start to crowd — shed tracking, not targets */
@media (max-width: 380px) {
  .callbar a { letter-spacing: .01em; font-size: .78rem; padding-inline: .2rem; }
}
@media (max-width: 700px) {
  /* pad the bar past the home indicator on notched phones (needs
     viewport-fit=cover); body clears both the bar and the inset */
  .callbar { display: flex; padding-bottom: env(safe-area-inset-bottom); }
  body { padding-bottom: calc(3.6rem + env(safe-area-inset-bottom)); }
}

/* --- scroll reveal --- */
/* ---------- narrow screens ---------- */
@media (max-width: 900px) {
  .tel-pill { white-space: nowrap; }
}
@media (max-width: 560px) {
  .hero__foot .btn { flex: 1 1 100%; }
  .reveal__grip { width: 46px; height: 46px; }
  .reveal__grip::before { left: 12px; }
  .reveal__grip::after  { right: 12px; }
}

@media (prefers-reduced-motion: no-preference) {
  .rise { opacity: 0; transform: translateY(18px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
  .rise.is-in { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
