
/* ---------------------------------------------------------------------------
   Stoneva General Contractors Manhattan — the scope sheet
   Tokens are defined once here. See DESIGN-DNA.md for why each one is what it is.
   --------------------------------------------------------------------------- */

:root {
  --ground: #f7f5f1;
  --surface: #ffffff;
  --ink: #171513;
  --ink-muted: #5c554e;
  --accent: #9a3b25;
  --accent-deep: #6e2718;
  --line: #ded7cd;
  --line-strong: #c3b8aa;

  --ff-display: "Josefin Sans", "Trebuchet MS", sans-serif;
  --ff-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --s1: 4px;  --s2: 8px;  --s3: 16px; --s4: 24px;
  --s5: 40px; --s6: 64px; --s7: 96px; --s8: 140px;

  --container: 1180px;
  --measure: 68ch;
  --radius: 2px;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--ff-body);
  font-size: 19px;
  line-height: 1.65;
  font-weight: 400;
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--accent-deep); }

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

h1, h2, h3 {
  font-family: var(--ff-display);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.01em;
  margin: 0 0 var(--s4);
  text-wrap: balance;
}

h1 { font-size: clamp(2.4rem, 5.4vw, 4.1rem); }
h2 { font-size: clamp(1.7rem, 3.2vw, 2.5rem); }
h3 { font-size: clamp(1.15rem, 1.8vw, 1.35rem); font-weight: 600; }

p, ul, ol { margin: 0 0 var(--s4); max-width: var(--measure); }
ul, ol { padding-left: 1.25em; }
li { margin-bottom: var(--s2); }
strong { font-weight: 600; }

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--s4);
}

/* Visually hidden without a negative offset: left:-9999px widens the document, which shows up
   as real horizontal overflow once a clip is lifted. */
.skip-link {
  position: absolute; top: 0; left: 0; z-index: 100;
  width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
  background: var(--ink); color: #fff; padding: var(--s3) var(--s4);
}
.skip-link:focus {
  width: auto; height: auto; min-height: 44px; clip-path: none; overflow: visible;
  display: inline-flex; align-items: center;
}

/* --- header ------------------------------------------------------------- */

.site-header {
  border-bottom: 1px solid var(--line);
  background: var(--ground);
  position: sticky; top: 0; z-index: 40;
  /* The only shadow outside the trust seals, and it is doing a different job: it separates the
     sticky chrome from content passing underneath it. Kept below the seals' weight on purpose. */
  box-shadow: 0 6px 18px -14px rgba(14, 12, 11, 0.45);
}
/* The sticky box holds only the identity and the phone action, so it stays about 78px tall at
   every width. The navigation is a sibling bar below it and scrolls away, which is what keeps
   the persistent chrome small on a short phone viewport (finding B-15) while still leaving the
   call action permanently reachable — the reason no fixed bottom bar is needed. */
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3) var(--s4); min-height: 78px; flex-wrap: wrap;
}
/* The lockup: a designed mark plus the name typeset in the site's own display face, so the
   header uses two faces rather than three. */
.brand { display: flex; align-items: center; gap: var(--s3); text-decoration: none; color: var(--ink); }
.brand__mark { width: 40px; height: 40px; flex: 0 0 auto; }
/* STACKED. Set beside the wordmark under a 12ch cap the descriptor wrapped to three lines and
   measured 41px against the 24px name it is subordinate to, so the hierarchy read inverted. Under
   the name on one line it supports the wordmark instead of competing with it.
   THIS HUB KEEPS THE TWO-BAND HEADER, unlike its five siblings. Measured 2026-09-07: its eight nav
   items need a 1271px container and --container caps at 1180, so the one-row layout cannot hold
   them at any viewport width. Forcing it would mean 12.8px nav type — a worse nav bought to look
   like the Points. The rest of the header refinement applies here unchanged. */
.brand__lockup { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; min-width: 0; }
/* A BUSINESS NAME IS ONE TOKEN AND NEVER BREAKS. Without this it did: at 320 the phone band's
   nowrap row forced the identity to shrink, min-width:0 let it shrink past its own text, and the
   inherited overflow-wrap safeguard broke the wordmark into "St / on / ev / a" — four lines of
   two letters. The safeguard exists to stop a long unbroken string pushing the document sideways,
   which is right for a URL in body copy and catastrophic for the company's name in the header. */
.brand__word {
  font-family: var(--ff-display); font-weight: 700; font-size: 1.5rem; line-height: 1;
  letter-spacing: -0.01em; color: var(--ink);
  white-space: nowrap;
}
.brand__sub {
  font-family: var(--ff-body); font-weight: 500; font-size: 0.66rem; color: var(--ink-muted);
  letter-spacing: 0.1em; text-transform: uppercase; line-height: 1;
  white-space: nowrap;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* A native <details> was the obvious compact-nav pattern, but provenance.mjs reads every
   <details>/<summary> in the built page as a published FAQ question, so a "Menu" summary
   registered as an unsourced question. The nav stays visible instead. */

/* The nav lives INSIDE the sticky header, so the links stay on screen while the page scrolls. */
.site-nav { border-top: 1px solid var(--line); background: var(--ground); }
.site-nav ul { display: flex; flex-wrap: wrap; gap: 0 var(--s4); list-style: none; margin: 0; padding: 0; max-width: none; }

/* --- the menu button ------------------------------------------------------
   Hidden on desktop, where the nav is a permanent row. Shown below the nav
   breakpoint, where it collapses the same list into a panel. */
.nav-toggle { display: none; }
.nav-toggle__bars, .nav-toggle__bars::before, .nav-toggle__bars::after {
  display: block; width: 18px; height: 2px; background: currentColor; border-radius: 1px;
  transition: transform 160ms ease, opacity 160ms ease;
}
.nav-toggle__bars { position: relative; }
.nav-toggle__bars::before, .nav-toggle__bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle__bars::before { top: -6px; }
.nav-toggle__bars::after { top: 6px; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after { transform: translateY(-6px) rotate(-45deg); }
.site-nav a { display: inline-flex; align-items: center; min-height: 44px; color: var(--ink); text-decoration: none; font-size: 0.95rem; font-weight: 500; border-bottom: 2px solid transparent; }
.site-nav a:hover, .site-nav a[aria-current="page"] { color: var(--accent); border-bottom-color: var(--accent); }

.call-button {
  display: inline-flex; align-items: center; gap: var(--s2);
  background: var(--accent); color: #fff; text-decoration: none;
  font-weight: 600; font-size: 1rem; padding: 13px var(--s4);
  border-radius: var(--radius); white-space: nowrap; max-width: 100%;
  transition: background 160ms ease;
}
/* A phone number may never break across lines, whatever else in the label wraps. */
.nowrap { white-space: nowrap; }

/* A long service-specific CTA must wrap rather than push the page sideways. */
@media (max-width: 760px) {
  .call-button { white-space: normal; text-align: center; }
  .hero__actions { flex-direction: column; align-items: stretch; }
  .hero__actions .call-button { justify-content: center; }
}
.call-button:hover { background: var(--accent-deep); color: #fff; }
.call-button--ghost { background: transparent; color: var(--accent); border: 1px solid var(--line-strong); }
.call-button--ghost:hover { background: var(--accent); color: #fff; border-color: var(--accent); }

.header-actions { display: flex; align-items: center; gap: var(--s4); min-width: 0; }

/* Sized to the header row rather than to a hero. At 1rem on 13px padding it was the loudest
   element on the page and competed with the H1 and with the lead form's own submit. */
.site-header .call-button { font-size: 0.94rem; padding: 10px var(--s4); }

/* --- hero: typographic, no image behind the words ----------------------- */

.hero { padding: var(--s7) 0 var(--s6); border-bottom: 1px solid var(--line); }
.hero__eyebrow {
  font-family: var(--ff-body); font-size: 0.82rem; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent);
  margin: 0 0 var(--s4);
}
.hero__lede { font-size: 1.24rem; color: var(--ink-muted); max-width: 60ch; margin-bottom: var(--s5); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center; }
.hero__note { font-size: 0.95rem; color: var(--ink-muted); margin: var(--s4) 0 0; }

.hero__figure { margin: var(--s6) 0 0; }
.hero__figure img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--radius); }

/* --- numbered bands: the signature device ------------------------------- */

.band { border-bottom: 1px solid var(--line); padding: var(--s7) 0; }
.band:last-of-type { border-bottom: 0; }

.band__grid { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: var(--s5); align-items: start; }
.band__num {
  font-family: var(--ff-display); font-weight: 700; font-size: 1.5rem;
  color: var(--accent); line-height: 1; padding-top: 10px;
  border-top: 2px solid var(--accent); letter-spacing: 0.02em;
}
.band__body > :last-child { margin-bottom: 0; }

/* --- service index: a list, deliberately not a card grid ---------------- */

.index { list-style: none; margin: 0; padding: 0; max-width: none; border-top: 1px solid var(--line); }
.index li { margin: 0; border-bottom: 1px solid var(--line); }
.index a {
  display: grid; grid-template-columns: 64px minmax(0, 1fr) 28px;
  gap: var(--s4); align-items: baseline;
  padding: var(--s4) 0; text-decoration: none; color: var(--ink);
  transition: color 160ms ease;
}
.index a:hover { color: var(--accent); }
.index__num { font-family: var(--ff-display); font-weight: 700; color: var(--accent); font-size: 1.05rem; }
.index__title { font-family: var(--ff-display); font-weight: 700; font-size: clamp(1.3rem, 2.4vw, 1.8rem); line-height: 1.15; }
.index__desc { display: block; font-family: var(--ff-body); font-weight: 400; font-size: 1rem; color: var(--ink-muted); line-height: 1.55; margin-top: var(--s2); max-width: 56ch; }
.index__arrow { justify-self: end; color: var(--accent); font-size: 1.1rem; }

/* --- contained figure inside a band ------------------------------------- */

.figure-contained { margin: var(--s5) 0 0; max-width: 760px; }
.figure-contained img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius); }

/* --- process ladder ------------------------------------------------------ */

/* The sequence is the point, so it is drawn as one continuous rail with the steps hung off it,
   rather than as five paragraphs that happen to be numbered. The node is a real element now: a
   ::before counter could not be drawn over the rail, and the rail could not stop at the last node. */
.ladder { list-style: none; margin: 0; padding: 0; max-width: none; position: relative; }
.ladder__step {
  position: relative; margin: 0;
  padding: 0 0 var(--s5) calc(var(--s6) + var(--s2));
}
/* The rail is the step's own left border so it terminates naturally at the final node instead of
   running past it into whitespace. */
.ladder__step::before {
  content: ""; position: absolute; left: 17px; top: 8px; bottom: 0;
  width: 1px; background: linear-gradient(var(--line-strong), var(--line));
}
.ladder__step:last-child::before { display: none; }
.ladder__node {
  position: absolute; left: 0; top: 0;
  width: 35px; height: 35px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--line-strong); color: var(--ink-muted);
  font-family: var(--ff-display); font-weight: 700; font-size: 0.9rem;
  display: grid; place-items: center;
  transition: border-color 200ms ease, color 200ms ease, background 200ms ease, box-shadow 200ms ease;
}
/* The step a reader has reached is the one lit. Hovering anywhere on the row lights its node, so
   the rail responds to reading rather than only to precise pointing. */
.ladder__step:hover .ladder__node {
  border-color: var(--accent); color: var(--accent); background: var(--ground);
  box-shadow: 0 0 0 4px rgba(154, 59, 37, 0.09);
}
.ladder__text > :last-child { margin-bottom: 0; }
.ladder h3 { margin-bottom: var(--s2); }
.ladder p { margin-bottom: 0; }

@media (max-width: 560px) {
  .ladder__step { padding-left: var(--s5); }
  .ladder__step::before { left: 14px; }
  .ladder__node { width: 29px; height: 29px; font-size: 0.8rem; }
}

/* --- FAQ -----------------------------------------------------------------
   Bounded and centred, which is the contract production-integrity enforces: an unbounded
   question list stretched across a wide viewport is unreadable.
   NOTE for whoever edits this heading: the checker collects this rule with a regex whose
   selector capture reaches back to the previous closing brace, so it swallows this comment
   too, and it drops any match whose text mentions the disclosure element by name. A comment
   naming those elements here therefore makes a compliant max-width INVISIBLE to the check and
   fails the build. That is what the previous heading did. Recorded as a Factory defect. */

.faq { border-top: 1px solid var(--line); max-width: 78ch; margin-inline: auto; }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  cursor: pointer; list-style: none; padding: var(--s4) var(--s5) var(--s4) 0;
  position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary h3 { margin: 0; font-family: var(--ff-display); font-weight: 700; font-size: 1.16rem; line-height: 1.3; }
.faq summary::after {
  content: "+"; position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  font-family: var(--ff-display); font-size: 1.6rem; color: var(--accent); line-height: 1;
}
.faq details[open] summary::after { content: "\2013"; }
.faq details > *:not(summary) { margin-bottom: var(--s4); }
.faq details p { color: var(--ink-muted); }

/* --- call band ----------------------------------------------------------- */

.call-band { background: var(--ink); color: #fff; padding: var(--s6) 0; }
.call-band h2 { color: #fff; }
.call-band p { color: rgba(255, 255, 255, 0.78); }
.call-band .call-button { background: var(--accent); }
.call-band .call-button:hover { background: #b0472e; }
/* The oxide focus ring measured 2.62:1 against the dark ground, under the 3:1 minimum
   (finding B-12). Inside this band the ring is light. */
.call-band :focus-visible { outline-color: #f7f5f1; }
.call-band__phone { font-family: var(--ff-display); font-weight: 700; font-size: clamp(1.8rem, 4vw, 2.6rem); color: #fff; text-decoration: none; display: inline-block; margin-bottom: var(--s3); }
.call-band__phone:hover { color: #fff; text-decoration: underline; }

/* --- breadcrumbs --------------------------------------------------------- */

.breadcrumbs { padding-top: var(--s4); font-size: 0.9rem; color: var(--ink-muted); }
.breadcrumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: var(--s2); margin: 0; padding: 0; max-width: none; }
.breadcrumbs li + li::before { content: "/"; margin-right: var(--s2); color: var(--line-strong); }

/* --- footer -------------------------------------------------------------- */

.site-footer { border-top: 1px solid var(--line); padding: var(--s6) 0 var(--s5); }
.site-footer__grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: var(--s5); }
.site-footer h2 { font-size: 0.82rem; font-family: var(--ff-body); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-muted); margin-bottom: var(--s3); }
.site-footer ul { list-style: none; padding: 0; margin: 0; }
.site-footer li { margin-bottom: var(--s2); }
.site-footer a { color: var(--ink); text-decoration: none; }
.site-footer a:hover { color: var(--accent); text-decoration: underline; }
.site-footer address { font-style: normal; color: var(--ink-muted); }
.site-footer__legal { border-top: 1px solid var(--line); margin-top: var(--s5); padding-top: var(--s4); font-size: 0.88rem; color: var(--ink-muted); display: flex; flex-wrap: wrap; gap: var(--s4); justify-content: space-between; }

/* --- banner media: the main image beside two trade details --------------- */

.hero__media { margin: var(--s6) 0 0; }
.hero__media--strip { display: grid; grid-template-columns: 2fr 1fr; gap: var(--s3); align-items: stretch; }
.hero__media--strip .hero__figure { margin: 0; }
.hero__media--strip .hero__figure img { height: 100%; aspect-ratio: auto; min-height: 320px; }
.hero__media--strip .hero__detail { margin: 0; display: grid; }
.hero__detail img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius); }
.hero__media--strip { grid-template-areas: "main detail1" "main detail2"; }
.hero__media--strip .hero__figure { grid-area: main; }
.hero__media--strip .hero__detail:nth-of-type(1) { grid-area: detail1; }
.hero__media--strip .hero__detail:nth-of-type(2) { grid-area: detail2; }

/* --- footer map: the verified premises, never an approximate pin --------- */

.footer-map {
  margin-top: var(--s5); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; line-height: 0; background: var(--surface);
}
.footer-map iframe { width: 100%; height: 260px; border: 0; display: block; filter: saturate(0.85); }

/* --- footer identity and location module -------------------------------- */

.footer-identity { display: flex; gap: var(--s4); align-items: flex-start; }
.footer-identity__mark { width: 44px; height: 44px; flex: 0 0 auto; }
.footer-identity__name {
  font-family: var(--ff-display); font-size: 1.15rem; font-weight: 700; color: var(--ink);
  text-transform: none; letter-spacing: 0; margin-bottom: var(--s2);
}
.footer-identity address { margin-bottom: var(--s3); line-height: 1.6; }
.footer-identity__area { color: var(--ink-muted); font-size: 0.92rem; }
.footer-identity__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); margin: 0; }
.footer-identity__map { font-size: 0.92rem; }

/* --- an address is always an address block, never a run-on paragraph ----- */

.address-block { font-style: normal; line-height: 1.7; margin: 0 0 var(--s4); }

/* --- 404 recovery routes are controls, not prose ------------------------- */

/* The 404 recovery routes are controls, not prose (finding B-13). */
.page-not-found .band__body ul a { display: inline-flex; align-items: center; min-height: 44px; }

/* --- inline call prompt --------------------------------------------------
   The page is long, and a reader who decides in the middle of it should not have to scroll
   to either end to act. One compact prompt sits between bands. */

.call-inline { border-bottom: 1px solid var(--line); padding: var(--s4) 0; background: var(--surface); }
.call-inline .container { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s4); }
.call-inline p { margin: 0; font-size: 1.02rem; color: var(--ink-muted); max-width: 46ch; }

/* --- prose helpers ------------------------------------------------------- */

.prose > :last-child { margin-bottom: 0; }
.lede { font-size: 1.18rem; color: var(--ink-muted); max-width: 62ch; }

/* --- responsive ---------------------------------------------------------- */

@media (max-width: 900px) {
  .site-footer__grid { grid-template-columns: 1fr 1fr; }
  .band__grid { grid-template-columns: 1fr; gap: var(--s3); }
  .band__num { border-top: 0; padding-top: 0; font-size: 1.1rem; }
}

/* Tap targets. Prose links stay inline so paragraphs are not shredded, but every navigation,
   footer, breadcrumb and brand control carries a 44px hit area at every width. */
.site-nav a, .site-footer a, .breadcrumbs a, .brand, .skip-link {
  min-height: 44px;
}
.site-nav a, .site-footer a, .breadcrumbs a, .brand {
  display: inline-flex; align-items: center;
}
.site-footer li { margin-bottom: 0; }

@media (max-width: 900px) {
  /* The permanent nav row becomes a button-driven panel. It is still the same list in the same
     place in the DOM — only its presentation changes — and with the script blocked the `js`
     class is absent, so the list simply stays visible and nothing is lost. */
  .nav-toggle {
    display: inline-flex; align-items: center; gap: var(--s2);
    min-height: 44px; padding: 8px var(--s3);
    background: transparent; color: var(--ink);
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    font-family: var(--ff-body); font-size: 0.92rem; font-weight: 600; cursor: pointer;
  }
  .nav-toggle:hover { border-color: var(--accent); color: var(--accent); }

  .js .site-nav {
    display: grid; grid-template-rows: 0fr;
    transition: grid-template-rows 180ms ease;
    border-top: 0;
  }
  .js .site-nav > .container { overflow: hidden; min-height: 0; }
  .js .site-nav.is-open { grid-template-rows: 1fr; border-top: 1px solid var(--line); }

  .site-nav ul { flex-direction: column; gap: 0; padding: var(--s2) 0; }
  .site-nav li { margin: 0; }
  .site-nav a {
    width: 100%; min-height: 50px; font-size: 1rem;
    border-bottom: 0; border-top: 1px solid var(--line);
  }
  .site-nav li:first-child a { border-top: 0; }
  .site-nav a:hover, .site-nav a[aria-current="page"] { border-bottom: 0; color: var(--accent); }
}

@media (prefers-reduced-motion: reduce) {
  .js .site-nav { transition: none; }
}

@media (max-width: 780px) {
  .hero__media--strip { grid-template-columns: 1fr 1fr; grid-template-areas: "main main" "detail1 detail2"; }
  .hero__media--strip .hero__figure img { min-height: 0; aspect-ratio: 16 / 9; }
  .hero__detail img { aspect-ratio: 1 / 1; }
}

@media (max-width: 760px) {
  body { font-size: 17px; }


  .site-nav ul { gap: 0 var(--s3); }
  .site-nav a { font-size: 0.9rem; min-height: 44px; }
  .brand__mark { width: 34px; height: 34px; }
  .brand__word { font-size: 1.3rem; }
  .hero { padding: var(--s5) 0 var(--s5); }
  .band { padding: var(--s5) 0; }
  .index a { grid-template-columns: 40px minmax(0, 1fr); }
  .index__arrow { display: none; }
  .ladder li { padding-left: var(--s5); }
  .site-footer__grid { grid-template-columns: 1fr; gap: var(--s4); }
  .header-actions .call-button { padding: 11px var(--s3); font-size: 0.94rem; }
  .footer-identity__actions .call-button { width: 100%; justify-content: center; }
}

/* The header lockup plus the call action did not fit a 320px viewport and pushed the document
   22px wide, clipping the tagline mid-word — the acceptance blocker B-01. Below 430px the
   tagline is dropped and the call label sheds the number, which the hero and footer both carry
   in full a few hundred pixels away. */
/* PHONE WIDTHS: ONE ROW, and a pair of controls that look like a pair.
   Measured on the design baseline at 390: the identity was 120px in a 390px viewport — 246px,
   sixty-three per cent of the row, empty — while the Menu button and the call action wrapped onto
   a second line and made the header 97px. They also read as two unrelated controls: a thin
   outlined ghost beside a solid slab 180px wide, the loudest thing above the fold.
   The Menu button becomes a 44px square carrying only its glyph and the call action sheds the
   word "Call". NEITHER WORD IS DELETED — both go to the accessible layer, so the button is still
   named "Menu" and the action is still "Call <number>" to anyone reading rather than looking.
   The band runs to 700 and not to 560: at 561 the full labels and the descriptor all return at
   once, no longer fit, and the row wraps worse than before. */
@media (max-width: 700px) {
  .brand__sub { display: none; }
  /* The identity is NOT shrinkable and the row is NOT forced onto one line. Both together were
     wrong: nowrap made the brand give up width it did not have and min-width:0 let it go below
     its own text. Let the row wrap where it genuinely cannot fit. */
  .brand { gap: var(--s2); flex: 0 0 auto; }
  .site-header__inner { gap: var(--s2); min-height: 62px; }
  .header-actions { gap: var(--s2); flex: 0 0 auto; }

  .nav-toggle { width: 44px; min-width: 44px; padding: 0; justify-content: center; }
  .nav-toggle__label {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }

  .site-header .call-button { padding: 10px var(--s3); font-size: 0.92rem; }
  .site-header .call-button__verb {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ===========================================================================
   REFINE PASS — 2026-09-06
   Added after the operator reported the site read as "boring and dead": it
   shipped with no motion of any kind, no services showcase, and 14
   commissioned images of which the homepage rendered three.
   Nothing below changes a word of copy, a route, a claim or a business fact.
   =========================================================================== */

/* --- services showcase: the animated-carousel-v1 contract ----------------- */
/* Mechanics, autoplay and every pause guarantee are SiteKit's. This file only
   decides how it looks and how fast it drifts. */

.showcase { margin: 0 0 var(--s2); }

.showcase__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--s4); margin-bottom: var(--s5);
}
.showcase__lede {
  margin: 0; max-width: 46ch; color: var(--ink-muted); font-size: 1.05rem;
}
.showcase__controls { display: flex; gap: var(--s2); flex: none; }
.showcase__btn {
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--line-strong); color: var(--ink);
  font-size: 1.05rem; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
  transition: background 180ms ease, border-color 180ms ease, color 180ms ease, transform 180ms ease;
}
.showcase__btn:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.showcase__btn:active { transform: scale(0.94); }

/* The track is a native scroll container; it must stay scrollable with no script. */
.showcase__track {
  list-style: none; margin: 0; padding: 0 0 var(--s3);
  display: flex; gap: var(--s4);
  overflow-x: auto; overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.showcase__track::-webkit-scrollbar { display: none; }

.showcase__card { flex: 0 0 336px; margin: 0; }
.showcase__link {
  display: flex; flex-direction: column; height: 100%;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  color: inherit; text-decoration: none;
  transition: border-color 240ms ease, box-shadow 240ms ease, transform 240ms ease;
}
.showcase__link:hover {
  border-color: var(--line-strong); color: inherit;
  transform: translateY(-3px);
  box-shadow: 0 18px 40px -26px rgba(23, 21, 19, 0.55);
}
.showcase__media { position: relative; display: block; overflow: hidden; }
.showcase__media img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  transition: transform 700ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.showcase__link:hover .showcase__media img { transform: scale(1.04); }
.showcase__num {
  position: absolute; left: 0; bottom: 0;
  background: var(--ground); color: var(--accent);
  font-family: var(--ff-display); font-weight: 700; font-size: 0.9rem;
  padding: var(--s2) var(--s3); letter-spacing: 0.06em;
}
.showcase__body { display: flex; flex-direction: column; gap: var(--s2); padding: var(--s4); flex: 1; }
.showcase__title {
  font-family: var(--ff-display); font-weight: 700;
  font-size: 1.32rem; line-height: 1.15;
}
.showcase__desc { color: var(--ink-muted); font-size: 0.98rem; line-height: 1.55; }
.showcase__cue {
  margin-top: auto; padding-top: var(--s3);
  display: inline-flex; align-items: center; gap: var(--s2);
  color: var(--accent); font-size: 0.95rem; font-weight: 500;
}
.showcase__arrow { transition: transform 240ms ease; }
.showcase__link:hover .showcase__arrow { transform: translateX(5px); }

@media (max-width: 700px) {
  .showcase__head { flex-direction: column; align-items: flex-start; gap: var(--s3); }
  .showcase__card { flex-basis: 82vw; }
}

/* --- motion: one vocabulary, used three ways ----------------------------- */
/*
 * A rise-and-settle over 520ms on a single easing curve. It is applied to
 * section bodies, to the ladder steps in sequence, and to the hero figure.
 *
 * NOTHING IS HIDDEN UNTIL A SCRIPT HAS CONFIRMED IT CAN UNHIDE IT. The hidden
 * state is scoped to .js, which the inline head script sets. A reader with no
 * JavaScript, and a reader whose observer never fires, both get the finished
 * page rather than a blank one. SiteKit's safeguards.css independently forces
 * [data-reveal] visible under prefers-reduced-motion.
 */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 520ms cubic-bezier(0.2, 0.7, 0.3, 1),
              transform 520ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.js [data-reveal].is-revealed { opacity: 1; transform: none; }

/* The ladder reveals as a sequence, because the content IS a sequence. The
   stagger is capped so a five-step list never keeps a reader waiting. */
.js .ladder__step[data-reveal] { transition-delay: calc(var(--step, 0) * 70ms); }

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1 !important; transform: none !important; transition: none !important; }
  .showcase__media img, .showcase__link, .showcase__arrow, .ladder__node { transition: none !important; }
}

/* --- banner: the one full-bleed moment on the page ----------------------- */
/* The call band was a flat dark rectangle. It is the last thing before the
   footer and the only place the phone number is set large, so it now carries
   the same commissioned photography the rest of the site uses, dimmed behind
   the type rather than competing with it. */
.call-band { position: relative; overflow: hidden; }
.call-band::before {
  content: ""; position: absolute; inset: 0;
  background-image: url("/assets/images/detail-stair.b4c2c3dc0d.webp");
  background-size: cover; background-position: center 62%;
  opacity: 0.16; filter: grayscale(0.3);
}
.call-band > * { position: relative; }

/* --- interaction states -------------------------------------------------- */
.call-button {
  transition: background 180ms ease, color 180ms ease, border-color 180ms ease,
              transform 140ms ease, box-shadow 180ms ease;
}
.call-button:hover { box-shadow: 0 12px 26px -16px rgba(110, 39, 24, 0.75); }
.call-button:active { transform: translateY(1px); }

.index a { transition: background 180ms ease, padding-left 220ms cubic-bezier(0.2, 0.7, 0.3, 1); }
.index a:hover { background: rgba(255, 255, 255, 0.55); }
.index__arrow { transition: transform 220ms ease; }
.index a:hover .index__arrow { transform: translateX(5px); }

.site-header a, .site-footer a { transition: color 160ms ease; }

/* --- footer -------------------------------------------------------------- */
/* It carried the address, two link columns and a map frame with no separation
   between them, and the map iframe rendered as a large empty box whenever the
   frame was blocked. The frame now sits on a surface with a border, so a
   blocked or slow map reads as a panel rather than as a hole in the page. */
.site-footer__grid { padding-bottom: var(--s5); border-bottom: 1px solid var(--line); }
.footer-map {
  margin-top: var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden; line-height: 0;
}
.footer-map iframe { width: 100%; display: block; border: 0; }
.footer-identity__mark { transition: opacity 200ms ease; }

/* A grid or flex item defaults to min-width:auto, so a horizontally scrolling track of
   fixed-width cards pushes its ancestors wider instead of scrolling inside them. That is what
   render-probe measures as horizontal overflow "with the clip lifted" — the clip is lifted
   precisely so a scroll container cannot mask a layout that is genuinely too wide. Allowing
   these three to shrink is what lets the carousel scroll rather than widen the page. */
.band__body { min-width: 0; }
.showcase { min-width: 0; }
.showcase__track { min-width: 0; }

/* The map frame is third-party and loads late or not at all — blocked by a privacy extension, an
   offline review, or a headless capture. Loaded through SiteKit's iframe[data-src] observer it is
   deferred until it is nearly in view, and until then the panel must read as a panel rather than
   as a hole in the footer, which is exactly what it looked like before: a large empty white box
   as the last thing on the page. */
.footer-map { position: relative; min-height: 260px; background: var(--surface); }
.footer-map::after {
  content: "Map"; position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--ff-display); font-size: 0.85rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-muted); opacity: 0.5; pointer-events: none;
}
.footer-map iframe { position: relative; z-index: 1; min-height: 260px; background: transparent; }

/* A 142x23 hit area is not a comfortable target. The link keeps its inline look and gains a real
   44px box around it. */
.footer-identity__map {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: var(--s1) 0;
}

/* An inline tel: link inside a sentence is a real call action and was a 142x23 hit area. The
   padding grows the box to a comfortable target and the matching negative margin keeps the line
   box, and therefore the paragraph's rhythm, exactly where it was. */
.prose a[href^="tel:"] { padding: 12px 3px; margin: -12px 0; }

/* An iframe with no src yet is about:blank, and a browser paints that WHITE whatever background
   the element is given — which is why the lazy map still read as a bright hole punched in a dark
   footer. Hidden until SiteKit gives it a src, so what a reader sees before it loads is the
   panel, and after it loads is the map. */
.footer-map iframe:not([src]) { visibility: hidden; }

/* ===========================================================================
   HERO: image, form, CTA, badges — 2026-09-07
   The homepage hero now carries the canonical lead form, which is a contract
   rather than a design choice: the one surface every visitor sees must capture
   an enquiry without navigating first.
   =========================================================================== */

/* Two columns from 980px, where the form can sit beside the headline without
   squeezing either. Below that the copy leads and the form follows it, because
   on a phone the headline is what tells a reader they are in the right place. */
.hero--home .hero__grid { display: grid; gap: var(--s5); align-items: start; }
@media (min-width: 980px) {
  .hero--home .hero__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 430px); gap: var(--s6); }
  .hero--home .hero__copy { padding-top: var(--s2); }
}
.hero--home .hero__lede { margin-bottom: var(--s4); }

/* --- badges --------------------------------------------------------------- */
/* Every badge traces to a recorded fact. No number, no certificate, no
   "ask us for proof" — the treatment is the whole of the claim. */
.badges {
  list-style: none; margin: 0 0 var(--s5); padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--s2) var(--s3);
}
/* --- trust seals -----------------------------------------------------------
   ROUND, and that is a narrow, deliberate exception. DESIGN-DNA.md's 2px radius —
   "nearly square, paper and rules, not pills" — governs buttons, cards, inputs and
   surfaces, and still does. A badge is a different object class: a stamped mark of
   standing, and a mark of standing is a seal. Operator decision, 2026-09-07.

   The seal is inlined SVG so it inherits the page: `currentColor` carries the ring
   and the words, the two custom properties carry the accent and the hairline, and
   the type is the site's own display face. One asset works on the dark hero and on
   the light ground by changing three values.
   --------------------------------------------------------------------------- */
.badges {
  list-style: none; margin: 0 0 var(--s5); padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--s4);
}
.badge { margin: 0; display: block; }

/* A struck object, so the colours are the seal's own rather than inherited from the page: a solid
   oxide face, a darker edge showing as a rim, and everything cut out of it in the ground colour.
   One asset therefore reads the same on the dark hero and on the cream ground. The drop shadow is
   what lifts it off the photograph — it is the only shadow in the design and it belongs to this
   object class alone. */
.seal {
  display: block;
  width: 132px; height: 132px;
  --seal-face: var(--accent);
  --seal-edge: var(--accent-deep);
  --seal-ink: var(--ground);
  filter: drop-shadow(0 6px 14px rgba(14, 12, 11, 0.45));
}

/* Cut out of the face in the ground colour, like every other mark on the seal — NOT currentColor,
   which here would inherit the page's ink and put dark words on a dark red disc.
   9.8 user units: from a 100 viewBox that renders at 12.9px on desktop (132px) and 11.8px on a
   phone (120px), both clear of render-probe's 11px legibility floor. The seal SIZE is what makes
   the type legible, not the unit count. */
.seal__word {
  font-family: var(--ff-display);
  font-weight: 700;
  font-size: 9.8px;
  letter-spacing: 0.03em;
  fill: var(--seal-ink);
}

@media (max-width: 700px) {
  /* They wrap rather than shrink: below about 120px the ring text drops under the legibility
     floor, and a seal nobody can read is decoration. */
  .badges { gap: var(--s3); }
  .seal { width: 120px; height: 120px; }
}

/* --- the hero lead form --------------------------------------------------- */
.lead-form {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s4);
  box-shadow: 0 26px 60px -44px rgba(23, 21, 19, 0.6);
}
@media (min-width: 980px) { .lead-form { padding: var(--s5); } }

.lead-form__title {
  font-family: var(--ff-display); font-weight: 700; line-height: 1.15;
  font-size: 1.34rem; margin: 0 0 var(--s2);
}
.lead-form__sub { margin: 0 0 var(--s4); color: var(--ink-muted); font-size: 0.97rem; }

.lead-form__row { display: grid; gap: var(--s3); }
@media (min-width: 460px) { .lead-form__row { grid-template-columns: 1fr 1fr; } }

.lead-field { margin: 0 0 var(--s3); display: grid; gap: 6px; }
.lead-field label { font-size: 0.86rem; font-weight: 600; letter-spacing: 0.01em; }
.lead-field__optional { font-weight: 400; color: var(--ink-muted); }
.lead-field input, .lead-field textarea {
  font: inherit; font-size: 1rem; color: var(--ink);
  background: var(--ground);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 11px var(--s3); width: 100%;
  min-height: 46px;
  transition: border-color 160ms ease, box-shadow 160ms ease, background 160ms ease;
}
.lead-field textarea { min-height: 74px; resize: vertical; line-height: 1.5; }
.lead-field input::placeholder, .lead-field textarea::placeholder { color: var(--ink-muted); opacity: 0.7; }
.lead-field input:hover, .lead-field textarea:hover { border-color: var(--ink-muted); }
.lead-field input:focus, .lead-field textarea:focus {
  outline: none; background: var(--surface);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(154, 59, 37, 0.16);
}
/* The focus ring is REPLACED here, never removed: the box-shadow above is the visible indicator,
   and this keeps the keyboard path obvious for anyone the box-shadow does not reach. */
.lead-field input:focus-visible, .lead-field textarea:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }

/* A honeypot must be unreachable by a person and invisible to assistive technology, without
   display:none, which some bots use as the signal to skip it. */
.lead-form__hp {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.lead-form__actions { margin: var(--s4) 0 0; }
.lead-form__actions .call-button { width: 100%; justify-content: center; }
.lead-form__actions .call-button[disabled] { opacity: 0.6; cursor: default; }

.lead-form__status { margin: var(--s3) 0 0; font-size: 0.92rem; min-height: 1.3em; }
.lead-form__status[data-state="error"] { color: var(--accent-deep); font-weight: 500; }
.lead-form__status[data-state="ok"] { color: var(--ink); font-weight: 500; }
.lead-form__status[data-state="busy"] { color: var(--ink-muted); }

.lead-form__noscript { margin: var(--s3) 0 0; font-size: 0.92rem; color: var(--ink-muted); }
.lead-form__consent { margin: var(--s3) 0 0; font-size: 0.83rem; line-height: 1.5; color: var(--ink-muted); }

/* The consent line's privacy link is fine print, and fine print is still a tap target. Padding
   with a matching negative margin grows the hit area to 44px without moving the line. */
.lead-form__consent a, .lead-form__noscript a {
  display: inline-block; padding: 14px 3px; margin: -14px 0;
}

/* SiteKit's safeguards set overflow-wrap:anywhere on a, p, li and friends to close the horizontal
   overflow invariant, and it inherits into this span through the <a> that wraps it. Combined with
   the 12ch box it split the tagline mid-word — "GENERAL CONTRACT / OR, INWOOD" — which reads as a
   broken build rather than as a lockup. The tagline is two short phrases and should break only
   between them, so wrapping is restored to normal here and the box widened to fit the longer line.
   Scoped to this element: the safeguard stays in force everywhere else, which is the point of it. */
.brand__sub {
  overflow-wrap: normal;
  word-break: keep-all;
}
/* The 152px cap that used to be here is GONE. It existed for the lockup that sat the descriptor
   BESIDE the wordmark, where a box was the only thing stopping the phrase breaking mid-word. The
   lockup now stacks and the descriptor is white-space: nowrap, so the cap stopped being a guard
   and became a blade: measured at 800px on the baseline the text wanted 204px inside 152 and was
   cut. A width limit written for one layout is a defect in the next one. */

/* On a phone the hero actions stack, and a full-width button whose label wraps was leaving the
   separator dangling at the end of a line with the number pushed to the far edge. Centring the
   content and letting both actions share the full width makes the pair read as one stack. */
@media (max-width: 560px) {
  .hero__actions { display: grid; gap: var(--s3); }
  .hero__actions .call-button { width: 100%; justify-content: center; text-align: center; }
}

/* ===========================================================================
   HOME HERO — full-bleed photograph behind the whole composition, 2026-09-07
   The hero was a grid with copy on one side and a form on the other, and the
   photograph sat under it as a separate strip. The image now runs edge to edge
   BEHIND the content, which is what makes the top of the page read as the
   front of a business rather than as a layout.
   =========================================================================== */

.hero--home {
  position: relative;
  isolation: isolate;
  border-bottom: 0;
  padding: var(--s7) 0 var(--s7);
  /* The ground colour underneath, so the section is never transparent while the
     photograph decodes and never flashes white against the dark treatment. */
  background: #221f1c;
}
.hero--home .container { position: relative; z-index: 2; }

.hero__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 46%; }

/* TWO scrims, because one cannot do both jobs. The first is a flat darkening that makes the
   photograph a surface rather than a subject. The second is a directional wash, heavier on the
   side the copy sits, so the headline has contrast where it needs it while the right-hand side
   of the image stays visible behind and around the form. */
.hero--home::before,
.hero--home::after { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; }
/* Tuned down from the first attempt, which darkened the photograph almost out of existence — a
   background image nobody can see is not a background image, it is an expensive grey. The flat
   layer now only seats the picture, and the directional wash does the legibility work where the
   headline actually sits. */
.hero--home::before { background: rgba(20, 18, 16, 0.30); }
.hero--home::after {
  background:
    linear-gradient(100deg, rgba(14, 12, 11, 0.86) 0%, rgba(14, 12, 11, 0.72) 30%, rgba(14, 12, 11, 0.34) 60%, rgba(14, 12, 11, 0.12) 82%),
    linear-gradient(to top, rgba(14, 12, 11, 0.42) 0%, rgba(14, 12, 11, 0) 30%);
}

/* --- the copy, inverted onto the photograph ------------------------------- */
.hero--home .hero__eyebrow { color: #e6bfae; }
.hero--home h1 { color: #f7f5f1; }
.hero--home .hero__lede { color: rgba(247, 245, 241, 0.88); max-width: 34ch; text-shadow: 0 1px 14px rgba(14, 12, 11, 0.5); }
.hero--home h1 { text-shadow: 0 2px 22px rgba(14, 12, 11, 0.42); }

/* The ghost action was an ink outline made for the cream ground and disappears on a photograph. */
.hero--home .call-button--ghost {
  color: #f7f5f1;
  border-color: rgba(247, 245, 241, 0.45);
  background: rgba(247, 245, 241, 0.06);
}
.hero--home .call-button--ghost:hover {
  background: var(--ground); color: var(--ink); border-color: var(--ground);
}

/* --- the form card, which stays light on purpose -------------------------- */
/* It is the one element that must not recede: a white card on a darkened photograph is the
   brightest thing on the page, which is where the enquiry should be. */
.hero--home .lead-form {
  box-shadow: 0 34px 70px -40px rgba(0, 0, 0, 0.75);
  border-color: rgba(255, 255, 255, 0.5);
}

@media (min-width: 980px) {
  /* The form is the tallest thing in the grid, so the section takes its height from that rather
     than from padding. Less floor under the copy column, which was reading as dead space. */
  .hero--home { padding: 92px 0 84px; }
}
@media (max-width: 979px) {
  /* On a phone the photograph sits behind a much taller stack, so the darkening is carried
     further up and the object-position favours the top of the frame where the room reads. */
  .hero--home { padding: var(--s6) 0; }
  /* The frame is dominated by a dark wall at its centre; the window and the cased opening sit
     right of it. On a phone the crop is narrow enough that centring shows only the wall, so the
     focal point moves toward the light. */
  .hero__bg img { object-position: 72% 38%; }
  /* Lighter than the first pass, which took the photograph out entirely on a phone — the very
     device where the hero IS the page. The directional wash below carries the legibility. */
  .hero--home::before { background: rgba(20, 18, 16, 0.20); }
  .hero--home::after {
    background:
      linear-gradient(rgba(14, 12, 11, 0.68) 0%, rgba(14, 12, 11, 0.54) 44%, rgba(14, 12, 11, 0.30) 100%);
  }
}

/* --- the detail pair, rehomed --------------------------------------------- */
/* These two images used to sit in the hero as a collage beside the main photograph. They now sit
   in the opening band, next to the sentence that names brick, plaster over masonry and wood
   trim — which is what they actually depict, so they illustrate the claim instead of decorating
   the top of the page. */
.detail-pair {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3);
  margin: var(--s5) 0 0; max-width: 620px;
}
.detail-pair__item { margin: 0; }
.detail-pair__item img {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--line);
}


/* The primary call action carries a label, a separator and a number. On a phone the label wraps
   and the separator was left dangling at the end of a line with the number pushed to the far
   edge. Below 560px the parts stack and the separator is dropped, because a bullet between two
   stacked lines is punctuation for a sentence that is no longer one. */
.cb__label, .cb__num { display: inline-block; }
.cb__sep { margin: 0 0.45em; opacity: 0.75; }
@media (max-width: 560px) {
  .hero__actions .call-button { flex-direction: column; gap: 2px; line-height: 1.25; }
  .cb__sep { display: none; }
}


/* THE SAME FAILURE AS THE 1220px ROW ABOVE, AT THE OTHER END OF THE SCALE.
   That comment describes the call action being pushed onto a second line and the header measuring
   114px instead of the row's own 72. Below 375px the identical thing happens for the identical
   reason: brand 120 + actions 199 + the container's 24px of padding on each side needs 367px, and
   a 360px phone -- the most common Android width there is -- has 360. The row wraps and the header
   goes from 63px to 97px.

   Measured on the live site, 2026-09-09 at 360px. Before: two rows, 97px. After: one row, 63px,
   with 14px of slack left over and the 44px tap target intact.

   THE NUMBER STAYS, and two earlier attempts at this are why that is written down. Hiding it and
   keeping the word "Call" produced an EMPTY button, because .call-button__verb is already
   display:none at this width; restoring the verb collapsed the tap target to 20px. Both were
   solving a 7px layout shortfall by removing the one thing a local business has the header for.
   The pixels come out of padding instead. */
@media (max-width: 399px) {
  .site-header .container { padding-left: 14px; padding-right: 14px; }
  .call-button { padding-left: 12px; padding-right: 12px; }
  .site-header__inner { column-gap: 8px; }
}

/* --- footer contract (ae757c86): hours, and this site in "Our locations" --------
   The hours sit with the address as one more quiet identity line. The current site is listed
   with its siblings and marked by aria-current, set in ink behind a small accent square,
   and never linked to itself: it keeps the 44px row height the links carry so the
   list does not jump where the marked row sits. */
.footer-identity__hours { margin: 0 0 var(--s3); color: var(--ink-muted); font-size: 0.92rem; }
.footer-here { display: inline-flex; align-items: center; gap: var(--s2); min-height: 44px; color: var(--ink); font-weight: 600; }
.footer-here::before { content: ""; width: 7px; height: 7px; background: var(--accent); flex: none; }
