/* Base styles — Exterior Services LLC */
@import url('tokens.css');

/* ── Reset ─────────────────────────────────────────────────────────────────── */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

img, video {
  display: block;
  max-width: 100%;
}

/* In-page anchors (the skip link's #main, and any future #id) must not land
   underneath the fixed bar (Brief 18). */
html { scroll-padding-top: var(--nav-h); }

/* ── Body defaults ──────────────────────────────────────────────────────────── */
body {
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-3);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* HERO SPACING TREATMENT (Brief 18): the solid bar OCCUPIES space — every
     page starts below it. The rejected alternative was letting photographs run
     behind an opaque bar, which silently ate the top 64px of every hero: 29% of
     the 16:9 homepage hero band at 390px wide, undoing the ratio work of Brief
     16 pt 1d and the sharpness work of Brief 17. Padding the body instead keeps
     every photograph whole and makes hero text behind the nav structurally
     impossible rather than a spacing value that has to be re-tuned per page. */
  padding-top: var(--nav-h);
}

/* ── Focus visible ──────────────────────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
}

/* ── Reduced motion ─────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── MOBILE HERO LAW ────────────────────────────────────────────────────────
   At ≤880px every hero image is UNCROPPED at its natural aspect ratio.
   object-fit is unset, height is auto, layout stacks image-then-text.
   Enforcement for the homepage crossfade hero: home.css.
   Enforcement for the About hero: service.css .svc-hero mobile rules.
   Service pages (Brief 15): text band then framed plate — the plate photo
   stays natural-ratio/height-auto via service.css .svc-plate mobile rules.
   ─────────────────────────────────────────────────────────────────────────── */
.hero__img {
  width: 100%;
}

@media (max-width: 880px) {
  .hero__img {
    width: 100%;
    height: auto;
    object-fit: unset;
    display: block;
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   SHARED COMPONENTS — used across homepage and service pages
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── Display voice ──────────────────────────────────────────────────────────── */
.d {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: 0;
}

/* ── Skip link ──────────────────────────────────────────────────────────────── */
.skip {
  position: absolute; left: -999px; top: var(--sp-2); z-index: 99;
  background: var(--green); color: var(--paper);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-pill);
  text-decoration: none; font-size: var(--fs-2); font-weight: 700;
}
.skip:focus-visible { left: var(--sp-2); }

/* ── Eyebrow: flanking sand rules ───────────────────────────────────────────── */
.eyebrow {
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-4);
  color: var(--green);
  font-size: var(--fs-1); font-weight: 700;
  letter-spacing: 0.28em; text-transform: uppercase;
}
.eyebrow::before, .eyebrow::after {
  content: ""; height: 1px; flex: 0 1 clamp(2rem, 8vw, 5.5rem);
  background: var(--sand);
}
.dk .eyebrow { color: var(--green-lt); }
.dk .eyebrow::before, .dk .eyebrow::after {
  background: color-mix(in srgb, var(--sand) 55%, transparent);
}

/* The placeholder panel (.ph) that lived here is REMOVED (Brief D14). Its
   last user was the design3d "Preview" frame — the slider panels it survived
   for were filled in D10 — so the whole component (.ph, .ph::before, .ph__tag,
   .ph__cap and the .ba-s .ph sizing) is gone. Placeholders no longer exist on
   this site; every slot carries a real photograph or the slot itself is gone. */

/* ── Wired photograph (.shot) ───────────────────────────────────────────────
   Brief 16 pt 2: every slot carrying a real photograph uses <img class="shot">.
   The per-slot aspect-ratio rules that used to hang off .ph now hang off .shot,
   so the ratio settled in Brief 16 pt 1d is what the photograph is cropped to.
   width/height attributes in the markup mirror the same ratio, so nothing
   shifts on load. */
.shot {
  display: block;
  width: 100%; height: auto;
  object-fit: cover;
  border-radius: var(--r);
}
/* Deliberately NO background-color on .shot. The hero crossfade stacks three
   slides and slides 2-3 are lazy; an opaque placeholder colour on a not-yet-
   decoded slide paints a solid block over the slide beneath it mid-fade.
   Undecoded = transparent is the correct behaviour here. */

/* ── Frame: sand border plate ───────────────────────────────────────────────── */
.frame {
  padding: var(--sp-2);
  border: 1px solid var(--sand);
  border-radius: var(--r-frame);
}
.dk .frame { border-color: color-mix(in srgb, var(--sand) 45%, transparent); }

/* ── Figcaptions: italic slab plates ───────────────────────────────────────── */
figure { display: flex; flex-direction: column; }
figcaption {
  margin-top: var(--sp-3);
  color: var(--mut);
  font-family: var(--font-display); font-style: italic;
  font-size: var(--fs-2); text-align: center;
}
figcaption b { color: var(--green); font-style: normal; font-weight: 600; }
.dk figcaption { color: var(--mut-d); }
.dk figcaption b { color: var(--green-lt); }

/* ── Buttons ────────────────────────────────────────────────────────────────── */
.btn {
  display: inline-block;
  padding: var(--sp-3) var(--sp-6);
  background: var(--green); color: var(--paper);
  border: 1px solid var(--green); border-radius: var(--r-pill);
  font-size: var(--fs-2); font-weight: 700; letter-spacing: 0.06em;
  text-decoration: none;
  transition: background 0.2s, border-color 0.2s, color 0.2s, translate 0.2s;
}
.btn:hover { background: var(--green-lt); border-color: var(--green-lt); color: var(--ink); translate: 0 -2px; }
.btn--ghost { background: transparent; border-color: color-mix(in srgb, var(--paper) 50%, transparent); color: var(--paper); }
.btn--ghost:hover { background: transparent; border-color: var(--green-lt); color: var(--green-lt); }
.btn--sm { padding: var(--sp-2) var(--sp-5); }
.textlink {
  color: var(--green); font-weight: 700;
  text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px;
  transition: color 0.2s;
}
.textlink:hover { color: var(--green-lt); }

/* ══════════════════════════════════════════════════════════════════════════════
   NAV — SOLID PAPER BAR, every page, every scroll position (Brief 18)
   The transparent over-hero state is RETIRED. With real photographs in every
   hero, white nav text had nowhere to hide on bright daylight frames, and on
   /about/ the hero H1 scrolled straight through the lockup because the nav
   stayed transparent for the whole height of the hero image.
   The bar OCCUPIES space (body is padded by --nav-h) rather than floating.
   .nav--menu-open survives — the overlay bar still drops its paper chrome
   (the 2020 lockup image self-adapts on dark; see Brief D13).
   ══════════════════════════════════════════════════════════════════════════════ */
.nav {
  position: fixed; inset-inline: 0; top: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  /* sp-2 block padding (was sp-3): the D15 whole-badge lockup is 44px tall,
     so 44 + 16 keeps the bar at the same rendered 60px as 36 + 24 did. */
  padding: var(--sp-2) var(--gutter);
  background: var(--paper);
  /* Hairline seated on a restrained shadow. The hairline alone vanishes where
     the page below is also paper (contact, thank-you, 404); the soft shadow
     alone reads as a smudge on paper. Together the edge holds over both a
     bright photograph and a paper page. */
  box-shadow: 0 1px 0 var(--hair),
              0 6px 16px color-mix(in srgb, var(--ink) 6%, transparent);
}

/* 2020 original lockup (Brief D13) — one image carries leaf + wordmark + LLC.
   The Option 2 CSS-text wordmark (Manrope 800 b/i/em grammar, Briefs 10/10b)
   is RETIRED: the 2020 face is a display typeface this project does not have,
   so the name cannot be set in live text. Its rules are gone from here; the
   interlock margin and navlock leaf went with them. The 2020 artwork is
   background-adaptive (dark fills on paper, white keylines on dark), so the
   same image serves the paper bar and the open --char menu with no swap. */
.lockup {
  display: flex; align-items: center;
  text-decoration: none; white-space: nowrap; flex-shrink: 0;
}
/* Height only — width follows the badge's natural 2.023 ratio (89px at 44).
   44px inside sp-2 block padding keeps the bar at its familiar 60px; the
   whole-badge lockup needs the height for a legible wordmark (Brief D15). */
.lockup__img { display: block; height: 44px; width: auto; }

.nav__links {
  display: flex; align-items: center; list-style: none; gap: var(--sp-5);
}
.nav__links a {
  color: var(--ink);
  background: linear-gradient(var(--green), var(--green)) bottom left / 0% 2px no-repeat;
}
.nav__links a {
  text-decoration: none; font-size: var(--fs-2); font-weight: 600;
  letter-spacing: 0.06em; padding-bottom: var(--sp-1);
  /* nowrap so a crowded row fails loudly (overflow) instead of quietly
     breaking a link across two lines — see the density tiers below */
  white-space: nowrap;
  transition: background-size 0.25s, color 0.25s;
}
.nav__links a:hover,
.nav__links a[aria-current="page"] { background-size: 100% 2px; color: var(--green); }

.nav__burger {
  display: none;
  background: none; border: none; cursor: pointer;
  padding: var(--sp-2); margin-right: calc(-1 * var(--sp-2));
  color: var(--ink);
  transition: color 0.25s;
}
.nav__burger svg { display: block; width: 1.5rem; height: 1.5rem; }

/* Icon toggle — X hidden by default; aria-expanded="true" swaps them.
   .nav__burger .nav__icon--x specificity (0-2-0) beats .nav__burger svg (0-1-1). */
.nav__burger .nav__icon--x { display: none; }
.nav__burger[aria-expanded="true"] .nav__icon--lines { display: none; }
.nav__burger[aria-expanded="true"] .nav__icon--x    { display: block; }

.nav__cta { flex-shrink: 0; }

.nav__menu {
  display: none;
  position: fixed; inset: 0; z-index: 49;
  background: var(--char);
  flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-5);
  padding: var(--sp-8) var(--gutter);
}
.nav__menu--open { display: flex; }
.nav__menu a {
  color: var(--paper); text-decoration: none;
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--fs-5); letter-spacing: 0.04em;
  transition: color 0.2s;
}
.nav__menu a:hover { color: var(--green-lt); }
.nav__menu .btn { margin-top: var(--sp-4); }

/* Menu-open: the ONE surviving nav state (Brief 18). The full-screen overlay is
   --char, so the bar drops its paper background and chrome and the burger goes
   light for the duration. The lockup b/i recolour rules that lived here died
   with the CSS-text wordmark (Brief D13) — the 2020 lockup image self-adapts
   on the dark overlay (white keylines carry it), so no swap is needed. */
.nav.nav--menu-open { background: transparent; box-shadow: none; }
.nav.nav--menu-open .nav__burger { color: var(--paper); }

/* ── Nav density tiers (Brief 14) ───────────────────────────────────────────
   The row is lockup (273.7px, fixed) + links + CTA inside two --gutter pads.
   Seven links overrun it below ~1260px; six links already overran at 1024
   (measured −54.9px, "Our Work" silently breaking to two lines). Resolved by
   tightening gap, tracking, and — in the tightest tier only — link size. No
   structural change: same lockup, same link set, no dropdown, no wrap.
   Below 1024 the row is not recoverable at any tracking; the burger takes
   over there instead (trigger block at the foot of this file).
   ─────────────────────────────────────────────────────────────────────────── */
@media (min-width: 1024px) and (max-width: 1260px) {
  .nav { gap: var(--sp-3); }
  .nav__links { gap: var(--sp-4); }
  .nav__links a { letter-spacing: 0.04em; }
  .nav__cta.btn--sm { padding-inline: var(--sp-4); }
}
@media (min-width: 1024px) and (max-width: 1120px) {
  .nav__links { gap: var(--sp-3); }
  .nav__links a { font-size: var(--fs-1); letter-spacing: 0.03em; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   SECTIONS — shared structure
   ══════════════════════════════════════════════════════════════════════════════ */
.sec { padding: var(--sp-8) var(--gutter); }
.sec__head { text-align: center; width: min(46rem, 100%); margin-inline: auto; }
.sec__title { margin-top: var(--sp-4); font-size: clamp(2.2rem, 5vw, 3.6rem); }
.sec__lede  { margin-top: var(--sp-4); color: var(--mut); }
.dk { background: var(--char); color: var(--paper); }
.dk .sec__lede { color: var(--mut-d); }

.sec--cta { text-align: center; }
.sec--cta .sec__title { font-size: clamp(2.4rem, 5.5vw, 4rem); }
.cta__row {
  margin-top: var(--sp-6);
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: center; gap: var(--sp-4);
}
.sec--cta .textlink { color: var(--green-lt); }

/* ══════════════════════════════════════════════════════════════════════════════
   STATS — 3-column numeric band; shared by homepage + About
   ══════════════════════════════════════════════════════════════════════════════ */
.stats {
  margin-top: var(--sp-7);
  display: grid; grid-template-columns: repeat(3, 1fr);
  border-block: 1px solid var(--sand);
  text-align: center;
}
.stats div { padding: var(--sp-5) var(--sp-3); }
.stats div + div { border-left: 1px solid var(--sand); }
.stats b {
  display: block;
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(2.2rem, 4.5vw, 3.4rem); line-height: 1;
  color: var(--ink);
}
.stats span {
  display: block; margin-top: var(--sp-2);
  color: var(--mut);
  font-size: var(--fs-1); font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
}
.dk .stats { border-color: color-mix(in srgb, var(--sand) 55%, transparent); }
.dk .stats div + div { border-color: color-mix(in srgb, var(--sand) 55%, transparent); }
.dk .stats b { color: var(--paper); }
.dk .stats span { color: var(--mut-d); }

/* ══════════════════════════════════════════════════════════════════════════════
   BEFORE/AFTER SLIDER (F1) — shared component, homepage + Our Work
   Structure: .ba-slider > .ba-s__before + .ba-s__after + .ba-s__handle + tags + input
   The <input type="range"> is the interactive control (opacity:0, covers everything).
   After panel clips via clip-path; JS sets left for the handle and clip for after.
   ══════════════════════════════════════════════════════════════════════════════ */
.ba-slider {
  position: relative;
  overflow: hidden;
  border-radius: var(--r);
  aspect-ratio: 4 / 3;
  user-select: none;
}
.ba-s__before,
.ba-s__after {
  position: absolute; inset: 0;
}
.ba-s__after { z-index: 2; /* clip-path set by ba-slider.js */ }

/* Real photographs in the slider panels (Brief 32 — the first shipped pair).
   Both frames are produced at the slot's exact 4:3, so cover crops nothing at
   any width. (The .ph sizing rules that sat here died with the placeholder
   component — Brief D14.) */
.ba-s__before .shot,
.ba-s__after  .shot {
  width: 100%; height: 100%;
  object-fit: cover; border-radius: 0;
  display: block;
}
/* (The green-tinted .ba-s__after .ph::before "improved state" gradient died
   with the placeholder component — Brief D14. Real photographs carry the
   before/after read now.) */

/* Handle: vertical line + circular knob; positioned by JS */
.ba-s__handle {
  position: absolute; inset-block: 0;
  width: 0; /* zero-width; knob and line hang off it */
  z-index: 4; pointer-events: none;
  /* left is set by ba-slider.js */
}
.ba-s__line {
  position: absolute; inset-block: 0;
  left: 0; width: 2px; margin-left: -1px;
  background: var(--green-lt); border-radius: 2px;
}
.ba-s__knob {
  position: absolute; top: 50%; left: 0;
  translate: -50% -50%;
  width: 3.5rem; height: 3.5rem; border-radius: 50%;
  border: 2px solid var(--green-lt);
  outline: 4px solid color-mix(in srgb, var(--sand) 30%, transparent);
  background: var(--char); color: var(--green-lt);
  display: grid; place-items: center;
  font-weight: 700; letter-spacing: 0.2em; text-indent: 0.2em;
}

/* BEFORE / AFTER corner labels */
.ba-s__tag {
  position: absolute; bottom: var(--sp-4); z-index: 6;
  font-size: var(--fs-1); font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--ink) 68%, transparent);
  border: 1px solid var(--sand); color: var(--sand);
  pointer-events: none;
}
.ba-s__tag--b { left:  var(--sp-4); }
.ba-s__tag--a { right: var(--sp-4); border-color: var(--green-lt); color: var(--green-lt); }

/* The native range input: invisible overlay spanning full slider area */
.ba-s__range {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  cursor: ew-resize;
  z-index: 10;
  -webkit-appearance: none; appearance: none;
  margin: 0; padding: 0;
}

/* ══════════════════════════════════════════════════════════════════════════════
   MOSAIC — 6-tile homepage (g1–g6) + 8-tile service modifier (mosaic--8)
   ══════════════════════════════════════════════════════════════════════════════ */
.mosaic {
  margin-top: var(--sp-7);
  width: min(76rem, 100%); margin-inline: auto;
  display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--sp-4);
}
.mosaic figure .shot { aspect-ratio: 4 / 3; transition: translate 0.25s, box-shadow 0.25s; }
.mosaic figure:hover .shot {
  translate: 0 -4px;
  box-shadow: 0 16px 32px color-mix(in srgb, var(--ink) 16%, transparent);
}

/* 6-tile homepage layout — g1/g2 and g3/g4/g5 inherit 4/3 from .mosaic figure .shot;
   only g6 sets its own ratio. 21/7 became 16/9 for the same reason as the service
   panorama tile: no archive frame is natively wider than 1.778:1 (Brief 16 pt 1d). */
.g1, .g2    { grid-column: span 3; }
.g3, .g4, .g5 { grid-column: span 2; }
.g6         { grid-column: 1 / -1; }
.g6 .shot   { aspect-ratio: 16 / 9; }

/* ══════════════════════════════════════════════════════════════════════════════
   PROCESS STRIP — 3 steps, shared partial
   Promoted from service.css (Brief 18 Part C). {{partial:process}} renders on
   seven pages — about, our-work and the five service pages — but our-work loads
   only fonts/tokens/base/work.css, so while these rules lived in service.css
   that page rendered a bare <ol> with double numbering. A shared partial belongs
   in the shared stylesheet; the alternative (loading the whole service-page
   stylesheet on a page that is not a service page) would have pulled in
   .svc-band, .svc-plate, .svc-hero, .build-grid, .mosaic--8, .design3d and
   .xlink for one component.
   ══════════════════════════════════════════════════════════════════════════════ */
.process {
  margin-top: var(--sp-7);
  width: min(72rem, 100%); margin-inline: auto;
  list-style: none;
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-5);
}
.process__step {
  padding: var(--sp-5) var(--sp-5) var(--sp-5) var(--sp-4);
  border-left: 3px solid var(--sand);
}
.process__num {
  display: block;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(3rem, 5vw, 4.5rem); line-height: 1;
  color: var(--line);
}
.process__title {
  margin-top: var(--sp-3);
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--fs-4); color: var(--ink);
  line-height: 1.2;
}
.process__desc {
  margin-top: var(--sp-3);
  color: var(--mut); font-size: var(--fs-2); line-height: 1.7;
}

/* ══════════════════════════════════════════════════════════════════════════════
   FOOTER
   ══════════════════════════════════════════════════════════════════════════════ */
.foot {
  background: var(--ink); color: var(--mut-d);
  padding: var(--sp-7) var(--gutter) var(--sp-5);
  text-align: center;
}
/* Footer brand moment — interlocked hero, dark colorway (Brief 10) */
.foot__brand { display: inline-block; }
.foot__brand img { display: block; width: 200px; height: auto; }
.foot__nap { margin-top: var(--sp-4); font-size: var(--fs-2); line-height: 2; }
/* Service-line links (D9: Landscape Design, Snow Removal). These sit inline in
   a plain-text line, so they inherit its colour rather than announcing
   themselves — a dotted underline marks them without breaking the run of
   text. Without this rule they would paint as default browser blue on --ink. */
.foot__nap a {
  color: inherit; text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 0.25em;
  text-decoration-color: color-mix(in srgb, var(--paper) 45%, transparent);
}
.foot__nap a:hover { color: var(--green-lt); text-decoration-color: var(--green-lt); }
.foot__links {
  margin-top: var(--sp-5); list-style: none;
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-5);
}
.foot__links a { color: var(--mut-d); text-decoration: none; font-size: var(--fs-2); font-weight: 600; }
.foot__links a:hover { color: var(--green-lt); }
/* County framing leads; towns sit beneath it as search language */
.foot__area {
  margin-top: var(--sp-5);
  font-size: var(--fs-2); font-weight: 600;
  color: color-mix(in srgb, var(--paper) 72%, transparent);
}
.foot__towns {
  margin-top: var(--sp-3); list-style: none;
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2);
  font-size: var(--fs-1); color: color-mix(in srgb, var(--paper) 45%, transparent);
}
.foot__towns li + li::before { content: "·"; margin-right: var(--sp-2); }
.foot__towns .ny { color: color-mix(in srgb, var(--green-lt) 70%, transparent); }
.foot__towns .ny::before { color: color-mix(in srgb, var(--paper) 45%, transparent); }
.foot__base {
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--hair-d);
  font-size: var(--fs-1); letter-spacing: 0.1em;
  color: color-mix(in srgb, var(--paper) 40%, transparent);
  display: flex; flex-wrap: wrap;
  justify-content: center; gap: var(--sp-3) var(--sp-5);
}
/* Socials ride the meta row as plain text links — no icon set */
.foot__social { display: inline-flex; gap: var(--sp-4); }
.foot__social a { color: inherit; text-decoration: none; }
.foot__social a:hover { color: var(--green-lt); }

/* Sites by Bob signature — canonical spec; do not modify */
.foot__sig {
  margin-top: 1.4rem; padding-top: 1.4rem;
  border-top: 1px solid rgba(246,243,236,.14);
  display: flex; justify-content: center;
}
.foot__sig-link {
  display: inline-flex; align-items: center; gap: .75rem;
  text-decoration: none; color: rgba(246,243,236,.72);
  transition: color .3s;
}
.foot__sig-label {
  font-size: .7rem; letter-spacing: .16em;
  text-transform: uppercase; font-weight: 600;
}
.foot__sig-logo {
  display: inline-flex; background: #1D2030;
  border: 1px solid rgba(246,243,236,.12); border-radius: 8px;
  padding: .5rem .7rem; line-height: 0;
}
.foot__sig-logo img { width: 140px; height: auto; display: block; }
.foot__sig-link:hover { color: #fff; }
.foot__sig-link:hover .foot__sig-label { text-decoration: underline; text-underline-offset: 3px; }
.foot__sig-arrow {
  display: inline-flex; color: #FFD84D;
  font-size: .95rem; line-height: 1;
  transition: transform .35s ease;
}
.foot__sig-link:hover .foot__sig-arrow { transform: translateX(4px); }

/* ── Scroll-reveal (motion allowed) ─────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .sec__head, .mosaic figure, .stats {
      animation: soften 1s both;
      animation-timeline: view();
      animation-range: entry 0% entry 35%;
    }
    @keyframes soften { from { opacity: 0; } }
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   MOBILE — ≤880px shared rules
   ══════════════════════════════════════════════════════════════════════════════ */
/* Nav state trigger — 1023px, NOT the 880px layout breakpoint (Brief 14).
   The desktop row is a fixed 273.7px lockup + seven links + the CTA; below
   1024 it cannot hold them at any tracking, and the measured failure was the
   Free Estimate button clipping off the right edge at 900px (that clipping
   pre-dates Brief 14 — six links already overran 1024 by 54.9px). Same
   two-state nav, same link set, same lockup: only the state trigger moves,
   and the full-screen menu below carries every link. */
@media (max-width: 1023px) {
  .nav__links, .nav__cta { display: none; }
  .nav__burger { display: block; }
}

@media (max-width: 880px) {
  .mosaic { grid-template-columns: 1fr; }
  .g1,.g2,.g3,.g4,.g5,.g6 { grid-column: 1 / -1; }
  /* g6's photo (HRD-016) is natively 1.333, so 4/3 here is zero-crop — verified
     against the real frame in the Brief 16 pt 2 mobile-ratio audit. */
  .g6 .shot { aspect-ratio: 4 / 3; }

  .stats { grid-template-columns: 1fr; }
  .stats div + div { border-left: 0; border-top: 1px solid var(--sand); }

  /* Moved with the component from service.css (Brief 18 pt C) */
  .process { grid-template-columns: 1fr; }
  .process__step { border-left: none; border-top: 3px solid var(--sand); padding-left: 0; }
}
