

:root {
  /* Surfaces climb in perceptual lightness so stacked sections separate:
     L* 3.04 -> 6.05 -> 11.04. Contrast ratio is a poor guide this close to
     black; the L* step is what the eye actually reads. */
  --bg:        #0B0B0C;   /* page ground, alternating band A */
  --surface-1: #131318;   /* alternating band B */
  --surface-2: #1D1D24;   /* cards, form, CTA band -- lifts off either band */
  /* warmed to sit with the gold/clay/warm-white palette rather than
     reading as a stray cool gray */
  --line:      #2B2925;

  /* Accent roles are strict. Gold = actionable, and a solid gold fill is a
     primary CTA and nothing else. Bronze = structure. Slate = emphasis that
     is not a link. Terracotta rather than a cool tone -- it picks up the brick
     and clay pavers in the photography. Tightest pair is clay on surface-2 at
     5.18:1. */
  --bronze:    #8A6D31;
  --gold:      #C6A15B;
  --gold-hi:   #E0C285;
  --clay:      #C67D5E;

  --text:      #F5F3EF;
  --muted:     #A5A199;

  --ease:      cubic-bezier(0.22, 0.61, 0.36, 1);

  --display: 'Barlow Semi Condensed', system-ui, sans-serif;
  --body:    'IBM Plex Sans', system-ui, sans-serif;

  --gutter:  clamp(18px, 4vw, 44px);

  /* Two heading tiers, not six. Section-opening heads take --h2; the CTA band
     and the two-column prose take the smaller one. */
  --h2:      clamp(32px, 4.4vw, 54px);
  --h2-sm:   clamp(28px, 3.6vw, 44px);

  /* Band rhythm. Bottom padding runs ~1.1x the top: symmetric padding reads
     top-heavy once a section head sits at the top of the band. */
  --section-y:      clamp(72px, 9vw, 132px);
  --section-y-lg:   clamp(84px, 10vw, 160px);
  --section-y-b:    clamp(80px, 9.9vw, 146px);
  --section-y-lg-b: clamp(92px, 11vw, 176px);

  /* Inner elements stay sharp; containers are the only soft thing on the page. */
  --r-inner: 3px;
  --r-card:  8px;

  /* One light source, one hue. The warm second layer is what keeps a panel
     from looking like a hole punched in the page. */
  --shadow-lift:       0 18px 34px -26px rgba(0, 0, 0, 0.95),
                       0 2px 8px -4px rgba(40, 28, 10, 0.5);
  --shadow-lift-hover: 0 26px 44px -28px rgba(0, 0, 0, 0.98),
                       0 4px 12px -6px rgba(40, 28, 10, 0.55);
  --shadow-panel:      0 24px 44px -30px rgba(0, 0, 0, 0.95),
                       0 3px 10px -6px rgba(40, 28, 10, 0.45);

  /* z-index ladder, so nothing has to guess */
  --z-header:   80;
  --z-to-top:   90;
  --z-call-bar: 95;
  --z-lightbox: 200;
  --z-grain:    999;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; background: var(--bg); }

body {
  -webkit-font-smoothing: antialiased;
  color: var(--text);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.62;
  overflow-x: hidden;
}

/* --- grain ---------------------------------------------------------------
   Three near-black bands with nothing on them but type read as flat vector.
   A fixed feTurbulence overlay (no network request) puts a little tooth back
   into them. Sits above everything and takes no pointer events. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

a { color: var(--gold); text-decoration: none; }
a:hover { color: var(--gold-hi); }

/* Everything that changes state does so over ~180ms instead of snapping. */
a, button, .service-card, .tile figcaption, input, select, textarea {
  transition:
    color 180ms ease,
    background-color 180ms ease,
    border-color 180ms ease,
    box-shadow 180ms ease,
    opacity 180ms ease,
    transform 200ms var(--ease);
}

input, select, textarea { font-family: var(--body); }
select option { background: var(--surface-2); color: var(--text); }

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

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

/* the sticky header is ~74px tall; keep anchored headings clear of it */
[id] { scroll-margin-top: 92px; }

/* ---------------------------------------------------------------- shared -- */

.wrap {
  max-width: 1280px;
  margin: 0 auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

.eyebrow {
  font-size: 12.5px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--clay);
  font-weight: 600;
}

/* Section-head eyebrows carry a short clay rule underneath. --rule defaults
   to 1 so the no-JS and reduced-motion states are complete; GSAP draws it
   from 0 as each head scrolls in. */
.section-head .eyebrow,
.work-head .eyebrow,
.process-head .eyebrow,
.band-head .eyebrow { display: inline-block; }
.section-head .eyebrow::after,
.work-head .eyebrow::after,
.process-head .eyebrow::after,
.band-head .eyebrow::after {
  content: "";
  display: block;
  width: 44px;
  height: 1px;
  margin-top: 10px;
  background: var(--clay);
  transform: scaleX(var(--rule, 1));
  transform-origin: left center;
}
.band-head .eyebrow::after { margin-left: auto; margin-right: auto; transform-origin: center; }

.diamond {
  width: 11px; height: 11px;
  border: 1px solid var(--bronze);
  transform: rotate(45deg);
  display: block;
}

.h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--h2);
  line-height: 1.06;
  letter-spacing: -0.02em;
  margin: 0;
}

/* One word alone on the last line of a 54px head is the most visible typo-
   graphic defect on a page like this. Applied to every display heading. */
.h2,
.process-head h2,
.band-head h2,
.quote h2,
.prose h2,
.cta-inner h2,
.hero h1 { text-wrap: balance; }

.lede { color: var(--muted); margin: 0; text-wrap: pretty; }

.btn-gold {
  background: var(--gold);
  color: var(--bg);
  font-family: var(--body);
  font-weight: 600;
  letter-spacing: 0.03em;
  border-radius: var(--r-inner);
  /* a bronze rim on a light fill muddies the edge at header size -- let the
     shadow do the separating instead */
  border: 1px solid var(--gold);
  display: inline-block;
}
.btn-gold:hover {
  background: var(--gold-hi);
  color: var(--bg);
  border-color: var(--gold-hi);
  transform: translateY(-2px);
  box-shadow: 0 10px 22px -12px rgba(198, 161, 91, 0.4);
}
.btn-gold:active { transform: translateY(1px); box-shadow: none; }

.btn-ghost {
  color: var(--text);
  font-weight: 600;
  letter-spacing: 0.02em;
  border-radius: var(--r-inner);
  border: 1px solid var(--line);
  background: rgba(23, 24, 27, 0.6);
  display: inline-block;
}
.btn-ghost:hover {
  border-color: var(--bronze);
  color: var(--text);
  background: rgba(198, 161, 91, 0.1);
  transform: translateY(-2px);
}
.btn-ghost:active { transform: translateY(1px); }
.btn-gold:focus-visible, .btn-ghost:focus-visible { transform: translateY(-2px); }

.link-arrow {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.03em;
  border-bottom: 1px solid var(--bronze);
  padding-bottom: 2px;
  align-self: flex-start;
}
.link-arrow::after {
  content: '\2192';
  display: inline-block;
  margin-left: 0.4em;
  transition: transform 200ms var(--ease);
}
.link-arrow:hover::after { transform: translateX(4px); }

/* --- icons ---------------------------------------------------------------
   One hidden <svg> sprite per page; every use site inherits colour from its
   context via stroke:currentColor. Decorative -- adjacent text carries meaning. */
.icon-sprite { display: none; }

.icon {
  width: 1.15em;
  height: 1.15em;
  flex: 0 0 auto;
  vertical-align: -0.18em;
}

.svc-icon { width: 30px; height: 30px; color: var(--clay); display: block; margin-bottom: 2px; }
.stat-icon { width: 19px; height: 19px; color: var(--clay); display: block; margin-bottom: 11px; }
.why-icon { width: 21px; height: 21px; color: var(--clay); margin-top: 3px; }

/* footer contact rows become icon + label */
.footer-col a,
.footer-col > span:not(.footer-heading) { display: flex; align-items: center; gap: 10px; }
.footer-col .icon { width: 15px; height: 15px; color: var(--clay); }

/* photo frames: <image-slot fit="cover"> became a plain cover-fitted <img> */
.frame { position: relative; overflow: hidden; background: var(--surface-2); }
.frame img { width: 100%; height: 100%; object-fit: cover; }
/* <picture> is inline by default and would collapse its sized frame */
.pic { display: block; width: 100%; height: 100%; }

/* --- blur-up -------------------------------------------------------------
   A ~20px WebP is inlined as the frame's background; the real photo fades in
   over it. The image is opaque by default -- script.js opts into the fade, so
   with JS off nothing is ever hidden. */
[data-lqip] {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.js-lqip [data-lqip] > .pic > img,
.js-lqip [data-lqip] > img { opacity: 0; transition: opacity 500ms ease; }
.js-lqip [data-lqip].is-loaded > .pic > img,
.js-lqip [data-lqip].is-loaded > img { opacity: 1; }

/* five source photos carry a 4-5px magenta/green strip down their RIGHT edge from
   whatever exported them; a hair of overscan pushes it outside the clipping frame */
.edge-fix { transform: scale(1.02); }

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

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: rgba(11, 11, 12, 0.93);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}

.header-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 14px var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 28px;
}

.brand { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.brand-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: 21px;
  letter-spacing: 0.06em;
  color: var(--text);
  text-transform: uppercase;
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px 26px;
  font-size: 14.5px;
  letter-spacing: 0.02em;
  flex: 1 1 auto;
  min-width: 0;
}
.site-nav a { color: var(--muted); }
.site-nav a:hover { color: var(--text); }

.header-actions {
  display: flex;
  align-items: center;
  gap: 10px 20px;
  flex-wrap: wrap;
  order: 2;
}

.header-cta { font-size: 14.5px; padding: 11px 20px; font-variant-numeric: tabular-nums; }

/* --- mobile menu ---------------------------------------------------------
   On desktop the wrapper is inert: display:contents keeps .site-nav and
   .header-actions as direct flex items of .header-inner, so the desktop
   header layout and ordering are untouched. */
.header-collapse { display: contents; }

.nav-toggle {
  display: none;
  position: relative;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-inner);
  background: rgba(23, 24, 27, 0.6);
  cursor: pointer;
}
.nav-toggle:hover { border-color: var(--bronze); }
.nav-toggle:active { transform: translateY(1px); }

.nav-toggle-bar {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 2px;
  margin: -1px 0 0 -10px;
  background: var(--text);
  border-radius: 2px;
  transition: background-color 140ms ease;
}
.nav-toggle-bar::before,
.nav-toggle-bar::after {
  content: '';
  position: absolute;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--text);
  border-radius: 2px;
  transition: transform 240ms var(--ease);
}
.nav-toggle-bar::before { top: -6px; }
.nav-toggle-bar::after  { top: 6px; }

/* bars fold into an X */
.site-header.is-open .nav-toggle-bar { background: transparent; }
.site-header.is-open .nav-toggle-bar::before { transform: translateY(6px) rotate(45deg); }
.site-header.is-open .nav-toggle-bar::after  { transform: translateY(-6px) rotate(-45deg); }

/* ------------------------------------------------------------------ hero -- */

.hero {
  position: relative;
  /* dvh, not vh -- vh is the tall viewport on iOS and the hero jumps by the
     height of the toolbar as it collapses */
  min-height: clamp(540px, 80dvh, 860px);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}

.hero-media { position: absolute; inset: 0; }
.hero-media picture { display: block; width: 100%; height: 100%; }
.hero-media img { width: 100%; height: 100%; object-fit: cover; }

/* Slow enough to read as life rather than movement. */
@keyframes heroDrift {
  /* the drift is the delta, not the absolute scale -- keeping the range low
     avoids upscaling a 1290px source any further than it already is */
  from { transform: scale(1.01); }
  to   { transform: scale(1.045); }
}
.hero-media img {
  transform-origin: 50% 55%;
  animation: heroDrift 24s ease-in-out infinite alternate;
}

.hero-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    to top,
    #0B0B0C 0%,
    rgba(11, 11, 12, 0.94) 20%,
    rgba(11, 11, 12, 0.55) 52%,
    rgba(11, 11, 12, 0.12) 100%
  );
}

.hero-body {
  position: relative;
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: clamp(56px, 9vw, 110px) var(--gutter) clamp(44px, 6vw, 80px);
  pointer-events: none;
}
.hero-body .eyebrow {
  margin-bottom: 22px;
  /* small mid-tone type over a photo: the scrim alone is not enough this high up */
  text-shadow: 0 1px 8px rgba(11, 11, 12, 0.9);
}

.hero h1 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(40px, 7vw, 86px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  margin: 0 0 22px;
  /* 16em at the 86px cap is wider than the 1280px container, so the headline
     never actually stacked -- it just ran the full width in two thin lines */
  max-width: 13em;
  text-wrap: balance;
}

.hero p {
  color: var(--muted);
  font-size: clamp(16px, 1.6vw, 20px);
  line-height: 1.6;
  margin: 0 0 34px;
  max-width: 34em;
}

.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px clamp(16px, 2.4vw, 30px); pointer-events: auto; }
.hero-actions .btn-gold,
.hero-actions .btn-ghost { font-size: 16px; padding: 15px 30px; }
/* .link-arrow pins itself to flex-start for column layouts; in these rows it
   needs to sit on the buttons' centre line */
.hero-actions .link-arrow,
.cta-actions .link-arrow,
.notfound-links .link-arrow { align-self: center; }

/* ----------------------------------------------------------------- stats -- */

/* Sits on surface-1 so the band alternation starts right after the hero --
   on --bg the stats fused with the hero above and read as one long block. */
.stats {
  border-top: 1px solid var(--line);
  background: var(--surface-1);
}
.stats-inner { max-width: 1280px; margin: 0 auto; padding: 0 var(--gutter); }
/* A minmax() floor is a hard minimum -- an auto-fit track will not shrink
   below it, so on a viewport narrower than the floor the row overflowed the
   page rather than stacking (body's overflow-x:hidden was clipping the right
   edge of the copy off-screen on 320-360px phones). min(Npx, 100%) keeps the
   wide-screen column behaviour and lets the track collapse when it has to.
   Every auto-fit grid on the site is written this way. */
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr)); }

.stat { padding: 26px 28px; border-left: 1px solid var(--bronze); }
.stat:first-child { padding: 26px 28px 26px 0; border-left: 0; }
.stat:last-child { padding: 26px 0 26px 28px; }

.stat-num {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(34px, 3.4vw, 46px);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.1;
}
.stat-label {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 6px;
}

/* -------------------------------------------------------------- services -- */

/* A full-width band with .wrap inside it -- the same shape as .work, .process
   and .area. It used to carry .wrap itself, which capped the surface-1 fill at
   1280px: on any screen wider than that the band read as a lighter rectangle
   floating on the page ground with the darker bg showing either side of it. */
.services {
  padding: var(--section-y) 0 var(--section-y-b);
  background: var(--surface-1);
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: clamp(36px, 4vw, 58px);
}
.section-head .eyebrow { margin-bottom: 18px; }
.section-head-copy { max-width: 30em; }
.section-head .lede { max-width: 26em; }

.service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: clamp(18px, 2vw, 28px);
}

/* Four identical columns is the most generic row on the page. A 12-column bed
   lets the pair widths alternate 7/5 then 5/7, so the row shape changes down
   the block and driveways -- the highest-value service -- leads on the widest
   card. A 4-column bed with only the first two cards spanning left the whole
   right half of the second row empty.

   The frame ratios are paired to the spans so both photos in a row come out
   the same height and the headings under them share a baseline: a span-5 card
   is 0.702x the width of a span-7 one, and 16/9 x 0.702 is 5/4 to within a
   pixel. Getting that wrong is visible -- the two h3s sit at different heights
   and the row reads as broken rather than asymmetric. */
@media (min-width: 1000px) {
  .service-grid { grid-template-columns: repeat(12, 1fr); }
  .service-card:nth-child(1),
  .service-card:nth-child(4) { grid-column: span 7; }
  .service-card:nth-child(2),
  .service-card:nth-child(3) { grid-column: span 5; }
  .service-card:nth-child(1) .frame,
  .service-card:nth-child(4) .frame { aspect-ratio: 16 / 9; }
  .service-card:nth-child(2) .frame,
  .service-card:nth-child(3) .frame { aspect-ratio: 5 / 4; }
}

.service-card {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: var(--shadow-lift);
  display: flex;
  flex-direction: column;
  /* the pointer's position within the card, written by script.js */
  --mx: 50%;
  --my: 0%;
}

/* The lit edge tracks the cursor instead of sitting statically at the top.
   A masked ring painted on a pseudo-element, so the card's own border stays
   put and nothing reflows. Fades in with the hover, out with the leave. */
.service-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  border-radius: inherit;
  padding: 1px;
  opacity: 0;
  transition: opacity 220ms ease;
  background: radial-gradient(
    240px circle at var(--mx) var(--my),
    rgba(224, 194, 133, 0.75),
    rgba(198, 161, 91, 0.12) 45%,
    transparent 70%
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}
.service-card { position: relative; }
.service-card:hover::after,
.service-card:focus-within::after { opacity: 1; }

.service-card:hover {
  border-color: var(--bronze);
  transform: translateY(-3px);
  /* the inset hairline is a lit top edge -- same light source as the shadow */
  box-shadow: var(--shadow-lift-hover), inset 0 1px 0 rgba(198, 161, 91, 0.18);
}

.service-card .frame { aspect-ratio: 4 / 3; background: var(--bg); }

.service-body {
  padding: 24px 24px 26px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1 1 auto;
}
.service-body h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 25px;
  letter-spacing: -0.005em;
  margin: 0;
  color: var(--text);
}
.service-body p {
  color: var(--muted);
  font-size: 15.5px;
  line-height: 1.65;
  margin: 0;
  flex: 1 1 auto;
}

/* ------------------------------------------------------------------ work -- */

.work { padding: var(--section-y) 0 var(--section-y-b); background: var(--bg); }

.work-head {
  max-width: 1280px;
  margin: 0 auto clamp(32px, 4vw, 52px);
  padding: 0 var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
}
.work-head .eyebrow { margin-bottom: 18px; }
.work-head .link-arrow { padding-bottom: 3px; }

.gallery {
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 clamp(10px, 2vw, 20px);
  display: flex;
  flex-wrap: wrap;
  /* tiles stretch to a common row height (the design's own behaviour); each
     tile's aspect-ratio still sets the row rhythm and governs it when it wraps alone */
  gap: clamp(10px, 1.2vw, 16px);
}

.tile {
  min-width: 0;
  margin: 0;
  position: relative;
  border-radius: var(--r-inner);
  overflow: hidden;
  background: var(--surface-2);
}
.tile[hidden] { display: none; }

.tile-btn {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.tile-btn img { width: 100%; height: 100%; object-fit: cover; transition: transform 400ms ease; }
.tile-btn:hover img { transform: scale(1.035); }
.tile-btn:hover img.edge-fix { transform: scale(1.05); }

.tile figcaption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 30px 14px 12px;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text);
  text-shadow: 0 1px 6px rgba(11, 11, 12, 0.9);
  /* same bottom scrim the design uses on the service-area tile — the
     text-shadow alone loses the caption over pale pavers */
  background: linear-gradient(to top, rgba(11, 11, 12, 0.9), rgba(11, 11, 12, 0));
  pointer-events: none;
  /* six permanent labels sit on top of the work they are labelling; on a
     pointer device they wait to be asked for */
  opacity: 0;
  transform: translateY(6px);
}
.tile:hover figcaption,
.tile:focus-within figcaption {
  opacity: 1;
  transform: none;
}

/* touch has no hover, so the captions simply stay */
@media (hover: none) {
  .tile figcaption { opacity: 1; transform: none; }
}

/* aspect ratios and flex weights carried over from the design's masonry row */
.t-16x9 { aspect-ratio: 16 / 9;  flex: 2 1 520px; }
.t-4x5  { aspect-ratio: 4 / 5;   flex: 1 1 300px; }
.t-1x1  { aspect-ratio: 1 / 1;   flex: 1 1 300px; }
.t-3x2  { aspect-ratio: 3 / 2;   flex: 1 1 340px; }
.t-21x9 { aspect-ratio: 21 / 9;  flex: 2 1 480px; }

.gallery-links {
  max-width: 1440px;
  margin: clamp(26px, 3vw, 40px) auto 0;
  padding: 0 var(--gutter);
  display: flex;
  flex-wrap: wrap;
  gap: 14px clamp(24px, 3vw, 44px);
}

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

.process { background: var(--surface-1); }
.process-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--section-y-lg) var(--gutter) var(--section-y-lg-b);
}

.process-head { max-width: 34em; margin-bottom: clamp(44px, 5vw, 72px); }
.process-head .eyebrow { margin-bottom: 18px; }
.process-head h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--h2);
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0 0 22px;
}

/* The section lost its photo this round: the four steps now carry the band by
   themselves -- stacked on narrow screens, a 4-up row on wide ones. Each step's
   top rule is a ::before (not a border) so GSAP can draw it in via --draw;
   the CSS default of 1 keeps the no-JS state complete. */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 0 clamp(28px, 3.2vw, 48px); }
.steps li {
  position: relative;
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 20px;
  padding: 26px 0;
}
.steps li::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
  transform: scaleX(var(--draw, 1));
  transform-origin: left center;
}
.steps li:last-child { border-bottom: 1px solid var(--line); }
.step-num {
  font-family: var(--display);
  font-weight: 700;
  font-size: 34px;
  line-height: 1;
  color: var(--clay);
  letter-spacing: -0.01em;
}
.steps h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 23px;
  margin: 0 0 8px;
  color: var(--text);
}
.steps p { color: var(--muted); font-size: 15.5px; line-height: 1.65; margin: 0; }

@media (min-width: 1000px) {
  .steps { grid-template-columns: repeat(4, 1fr); }
  .steps li {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
    align-content: start;
    gap: 18px;
    padding: 30px 0 6px;
  }
  .steps li:last-child { border-bottom: 0; }
  .step-num { font-size: 46px; }
}

/* ------------------------------------------------------------ why / area -- */
/* Both sections lost their photos this round: each is now a full-width band
   with a centred head and the content spread across the whole column. */

.band { padding-top: var(--section-y); padding-bottom: var(--section-y-b); }

.band-head { max-width: 42em; margin: 0 auto clamp(38px, 4.5vw, 64px); text-align: center; }
.band-head .eyebrow { margin-bottom: 18px; }
.band-head h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--h2);
  line-height: 1.06;
  letter-spacing: -0.02em;
  margin: 0;
}
.band-head .lede { margin: 18px auto 0; max-width: 34em; }

/* --- ambient ------------------------------------------------------------
   #why is a tall band on --bg with nothing on it but type -- the flattest
   stretch on the page. A single very low radial, keyed to clay so it belongs
   to the palette, gives the band a centre to sit on.
   It is deliberately below the threshold of "gradient": you should not be
   able to point at it, only notice that the band has a middle. */
.ambient { position: relative; isolation: isolate; }
.ambient::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    62% 52% at 50% 34%,
    rgba(198, 125, 94, 0.055) 0%,
    rgba(198, 125, 94, 0.022) 42%,
    rgba(198, 125, 94, 0) 72%
  );
}

.why { background: var(--bg); }
.why-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  gap: clamp(24px, 3vw, 40px);
}
/* Five items in a three-column bed leave the last cell empty. On a six-column
   bed the block splits 3 + 2, the closing pair sitting on wider columns --
   a deliberate step down rather than a hole in the grid. */
@media (min-width: 1000px) {
  .why-list { grid-template-columns: repeat(6, 1fr); }
  .why-list li:nth-child(-n+3) { grid-column: span 2; }
  .why-list li:nth-child(n+4)  { grid-column: span 3; }
}
.why-list li { display: grid; grid-template-columns: 26px 1fr; gap: 16px; align-items: start; }
.why-list .diamond { width: 12px; height: 12px; margin-top: 7px; border-color: var(--clay); }
.why-list strong { font-weight: 600; color: var(--text); display: block; margin-bottom: 5px; }
.why-list span:last-child { color: var(--muted); font-size: 15.5px; line-height: 1.65; }

.area { background: var(--surface-1); }
/* map beside the places; stacks with the map first on narrow screens */
.area-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(26px, 3vw, 40px);
  align-items: start;
}
@media (min-width: 900px) {
  .area-grid { grid-template-columns: 1.35fr 1fr; }
}

.area-map-panel { margin: 0; display: flex; flex-direction: column; gap: 12px; }

.area-map {
  height: clamp(320px, 46dvh, 460px);
  /* Leaflet's own panes and controls climb to z-index 1000, which is well over
     the sticky header. Making the container a stacking context keeps that whole
     ladder local to the map, so the header (z-index 80) still wins. */
  position: relative;
  z-index: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
  /* the panel colour shows through wherever tiles have not (or cannot) load,
     so a blocked basemap still reads as a deliberate dark schematic */
  background: var(--surface-2);
  box-shadow: var(--shadow-panel);
}

/* what stands in when there is no JS, no Leaflet, or no connection */
.area-map-fallback {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 28px clamp(20px, 4vw, 40px);
  text-align: center;
}
.area-map-fallback .icon { width: 26px; height: 26px; color: var(--clay); }
.area-map-fallback p { margin: 0; color: var(--muted); font-size: 15px; max-width: 32em; }

.area-map-note {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- location chips ------------------------------------------------------ */

.area-chips {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
}

.area-chip {
  font-family: var(--body);
  font-size: 14.5px;
  line-height: 1.2;
  color: var(--text);
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-inner);
  background: var(--surface-2);
  cursor: pointer;
}
.area-chip:hover,
.area-chip.is-active {
  border-color: var(--bronze);
  color: var(--gold-hi);
  transform: translateY(-1px);
}
.area-chip:active { transform: translateY(1px); }

.area-note { color: var(--muted); font-size: 14.5px; margin: 0; max-width: 34em; }

/* --- leaflet, themed ----------------------------------------------------- */

.leaflet-container {
  background: var(--surface-2);
  font-family: var(--body);
  outline: none;
}
.leaflet-container a { color: var(--gold); }

/* zoom control as a pair of small dark buttons */
.leaflet-bar,
.leaflet-bar a {
  border: 0;
  box-shadow: none;
  background: rgba(29, 29, 36, 0.92);
  color: var(--text);
}
.leaflet-bar { border: 1px solid var(--line); border-radius: var(--r-inner); overflow: hidden; }
.leaflet-bar a { border-bottom: 1px solid var(--line); width: 32px; height: 32px; line-height: 32px; }
.leaflet-bar a:last-child { border-bottom: 0; }
.leaflet-bar a:hover { background: rgba(198, 161, 91, 0.16); color: var(--gold-hi); }

/* attribution -- required by OpenStreetMap and CARTO, kept legible but quiet */
.leaflet-control-attribution {
  background: rgba(11, 11, 12, 0.78) !important;
  color: var(--muted);
  font-size: 10.5px;
  padding: 3px 7px;
}
.leaflet-control-attribution a { color: var(--muted); text-decoration: underline; }
.leaflet-control-attribution a:hover { color: var(--gold-hi); }

/* markers are divIcons, so Leaflet's default marker PNG is never requested */
.area-marker { display: block; }
.area-marker-dot {
  display: block;
  width: 13px;
  height: 13px;
  margin: 0 auto;
  border-radius: 50%;
  background: var(--clay);
  border: 2px solid rgba(11, 11, 12, 0.85);
  box-shadow: 0 0 0 1px rgba(198, 125, 94, 0.55);
  transition: transform 200ms var(--ease), background-color 200ms ease, box-shadow 200ms ease,
              opacity 200ms ease;
}
.area-marker--major .area-marker-dot {
  width: 19px;
  height: 19px;
  background: var(--gold);
  box-shadow: 0 0 0 1px rgba(198, 161, 91, 0.6), 0 0 18px -2px rgba(198, 161, 91, 0.55);
}
.area-marker.is-active .area-marker-dot,
.area-marker:hover .area-marker-dot {
  background: var(--gold-hi);
  transform: scale(1.45);
  box-shadow: 0 0 0 1px rgba(224, 194, 133, 0.8), 0 0 20px -2px rgba(224, 194, 133, 0.7);
}

.leaflet-tooltip.area-tip {
  background: var(--surface-2);
  border: 1px solid var(--bronze);
  border-radius: var(--r-inner);
  color: var(--text);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 9px;
  box-shadow: 0 12px 24px -14px rgba(0, 0, 0, 0.95);
}
.leaflet-tooltip.area-tip::before { display: none; }

/* ----------------------------------------------------------------- quote -- */

/* The band is call-first: one centred column, the number as the hero of the
   section. The phone link stays text-coloured (gold fill remains reserved for
   the one solid button below it). */
.quote { background: var(--bg); }
.quote-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--section-y-lg) var(--gutter) var(--section-y-lg-b);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.quote-head { margin-bottom: clamp(20px, 3vw, 34px); }

.quote-phone {
  font-family: var(--display);
  font-weight: 700;
  /* 44px floor: at 320px viewport the number is 274px wide and still clears
     the gutters; a 52px floor overflowed small phones */
  font-size: clamp(44px, 9.5vw, 132px);
  line-height: 1;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  margin-bottom: clamp(28px, 4vw, 44px);
}
.quote-phone:hover { color: var(--gold-hi); }

.quote-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 16px;
  padding: 16px 32px;
}
.quote-cta .icon { width: 18px; height: 18px; }

.quote-hours {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muted);
  font-size: 15px;
  margin: 24px 0 0;
}
.quote-hours .icon { width: 16px; height: 16px; flex: none; }

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

.site-footer { background: var(--surface-1); }
.footer-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: clamp(52px, 6vw, 84px) var(--gutter) 34px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: clamp(28px, 3vw, 48px);
}
.footer-col { display: flex; flex-direction: column; gap: 10px; }
.footer-brand { display: flex; flex-direction: column; gap: 14px; }
.footer-brand-row { display: flex; align-items: center; gap: 10px; }
.footer-brand-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.footer-brand p { color: var(--muted); font-size: 15px; margin: 0; max-width: 22em; }

.footer-heading { font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--clay); font-weight: 600; }
.footer-col a { color: var(--text); font-size: 15.5px; }
.footer-col a:hover { color: var(--gold-hi); }
.footer-col span:not(.footer-heading) { color: var(--muted); font-size: 15px; }

.footer-legal {
  max-width: 1280px;
  margin: 0 auto;
  padding: 22px var(--gutter) 40px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  color: var(--muted);
  font-size: 13.5px;
}
.footer-legal-links { display: flex; flex-wrap: wrap; gap: 6px 22px; }
.footer-legal-links a { color: var(--muted); }
.footer-legal-links a:hover { color: var(--gold-hi); }

/* ---------------------------------------------------------- back to top -- */

.to-top {
  position: fixed;
  right: clamp(16px, 3vw, 32px);
  bottom: clamp(16px, 3vw, 32px);
  z-index: var(--z-to-top);
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: rgba(29, 29, 36, 0.9);
  backdrop-filter: blur(8px);
  color: var(--text);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity 220ms ease, transform 220ms var(--ease), visibility 0s linear 220ms,
              border-color 180ms ease, color 180ms ease;
}
.to-top.is-in {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 220ms ease, transform 220ms var(--ease), visibility 0s linear 0s,
              border-color 180ms ease, color 180ms ease;
}
.to-top:hover { border-color: var(--bronze); color: var(--gold-hi); }
.to-top:active { transform: translateY(1px); }
.to-top svg { width: 18px; height: 18px; }

/* ------------------------------------------------------------- scrollspy -- */
/* same treatment the project sub-nav uses for its current page */
.site-nav a[aria-current="true"] { color: var(--gold); }

/* ----------------------------------------------------------------- video -- */

.frame video,
.tile video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The hero keeps its photo underneath and the clip fades in over it only once
   it is actually playing -- if the video never loads, the photo simply stays. */
.hero-media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 800ms ease;
  pointer-events: none;
}
.hero-media video.is-playing { opacity: 1; }
.video-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border-radius: var(--r-inner);
  background: rgba(11, 11, 12, 0.7);
  border: 1px solid rgba(245, 243, 239, 0.18);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text);
  pointer-events: none;
}
.video-badge::before {
  content: '';
  width: 0;
  height: 0;
  border-left: 7px solid var(--clay);
  border-top: 4.5px solid transparent;
  border-bottom: 4.5px solid transparent;
}

/* -------------------------------------------------------------- lightbox -- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-lightbox);
  background: rgba(11, 11, 12, 0.96);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 4vw, 48px);
  opacity: 0;
  transition: opacity 200ms ease;
}
.lightbox.is-open { opacity: 1; }
.lightbox[hidden] { display: none; }

.lb-figure {
  margin: 0;
  max-width: min(1280px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: center;
  opacity: 0;
  transform: scale(0.98);
  transition: opacity 240ms ease, transform 240ms var(--ease);
}
.lightbox.is-open .lb-figure { opacity: 1; transform: none; }
.lb-figure img {
  max-width: 100%;
  max-height: calc(100dvh - 170px);
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--r-inner);
  border: 1px solid var(--line);
  /* script.js paints the tile's own ~20px placeholder here while the full-size
     photo is in flight; the width/height attributes it copies over give the
     frame its final box, so nothing resizes when the photo lands. */
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  transition: filter 420ms var(--ease);
}
/* Blurring the placeholder is what makes it read as "loading" instead of as a
   badly compressed photo. It clears the moment the real image decodes. */
.lb-figure.is-loading img { filter: blur(12px); }
.lb-figure figcaption {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
}

.lb-btn {
  position: absolute;
  background: rgba(23, 24, 27, 0.82);
  border: 1px solid var(--line);
  border-radius: var(--r-inner);
  color: var(--text);
  font-family: var(--body);
  font-size: 20px;
  line-height: 1;
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.lb-btn:hover { border-color: var(--bronze); color: var(--gold-hi); }
.lb-close { top: clamp(14px, 3vw, 28px); right: clamp(14px, 3vw, 28px); }
.lb-prev  { left: clamp(10px, 2vw, 24px);  top: 50%; transform: translateY(-50%); }
.lb-next  { right: clamp(10px, 2vw, 24px); top: 50%; transform: translateY(-50%); }

body.lb-open { overflow: hidden; }

/* ---------------------------------------------------------- project pages -- */

.page-hero { min-height: clamp(360px, 52dvh, 560px); }
/* the homepage gradient is tuned for an 860px hero; over a shorter one it runs
   out of room and the eyebrow/lede land on bright sky, so tighten the ramp */
.page-hero .hero-scrim {
  background: linear-gradient(
    to top,
    #0B0B0C 0%,
    rgba(11, 11, 12, 0.95) 28%,
    rgba(11, 11, 12, 0.74) 60%,
    rgba(11, 11, 12, 0.38) 100%
  );
}
.page-hero h1 { font-size: clamp(34px, 5.2vw, 64px); max-width: 14em; }

.subnav { border-bottom: 1px solid var(--line); background: var(--surface-1); }
.subnav-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  flex-wrap: wrap;
  gap: 0 clamp(18px, 3vw, 38px);
}
.subnav a {
  color: var(--muted);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  padding: 17px 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.subnav a:hover { color: var(--text); }
.subnav a[aria-current="page"] { color: var(--gold); border-bottom-color: var(--gold); }

.prose { background: var(--bg); }
.prose--raised { background: var(--surface-1); }
.prose-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--section-y) var(--gutter) var(--section-y-b);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: clamp(30px, 4vw, 72px);
  align-items: start;
}
.prose .eyebrow { margin-bottom: 18px; }
.prose h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--h2-sm);
  line-height: 1.07;
  letter-spacing: -0.02em;
  margin: 0 0 20px;
}
.prose p { color: var(--muted); margin: 0 0 16px; }
.prose p:last-child { margin-bottom: 0; }

.prose-points { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 20px; }
.prose-points li { display: grid; grid-template-columns: 26px 1fr; gap: 16px; align-items: start; }
.prose-points .diamond { width: 12px; height: 12px; margin-top: 7px; border-color: var(--clay); }
.prose-points strong { font-weight: 600; color: var(--text); display: block; margin-bottom: 5px; }
.prose-points span:last-child { color: var(--muted); font-size: 15.5px; line-height: 1.65; }

.cta-band { background: var(--surface-2); }
.cta-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: clamp(56px, 7vw, 100px) var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
}
.cta-inner h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--h2-sm);
  line-height: 1.07;
  letter-spacing: -0.02em;
  margin: 0;
}
.cta-inner .lede { max-width: 34em; }
.cta-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px clamp(16px, 2.4vw, 30px);
  margin-top: 8px;
}
.cta-actions .btn-gold,
.cta-actions .btn-ghost { font-size: 16px; padding: 15px 30px; }

/* ----------------------------------------------------------- long copy -- */
/* .prose is a two-column grid; legal and error pages want one measured column. */

.prose--single .prose-inner { display: block; }
.prose--single .prose-body { max-width: 68ch; }
.prose--single h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 23px;
  letter-spacing: -0.005em;
  color: var(--text);
  margin: 40px 0 12px;
}
.prose--single h3:first-of-type { margin-top: 32px; }
.prose--single ul { margin: 0 0 16px; padding-left: 20px; color: var(--muted); }
.prose--single li { margin-bottom: 8px; }
.prose--single .updated {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 28px;
}

/* --------------------------------------------------------------- 404 ---- */

.notfound { background: var(--bg); }
.notfound-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: clamp(90px, 13vw, 190px) var(--gutter) clamp(100px, 14vw, 210px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
}
.notfound-code {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(76px, 15vw, 190px);
  line-height: 0.86;
  letter-spacing: -0.03em;
  color: var(--surface-2);
  margin: 0;
  /* structural, not informational -- the heading below carries the meaning */
  user-select: none;
}
.notfound h1 {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--h2);
  line-height: 1.06;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: balance;
}
.notfound .lede { max-width: 34em; }
.notfound-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px clamp(18px, 2.6vw, 34px);
  margin-top: 14px;
}

/* ------------------------------------------------------------ skip link -- */
/* Off-canvas until focused, then it lands as an ordinary gold button in the
   top-left. First stop for anyone arriving on the keyboard. */

.skip-link {
  position: absolute;
  top: 10px;
  left: var(--gutter);
  z-index: calc(var(--z-header) + 1);
  padding: 11px 18px;
  font-size: 14.5px;
  transform: translateY(-160%);
  transition: transform 180ms var(--ease);
}
.skip-link:focus-visible { transform: none; }

/* ---------------------------------------------------------------- motion -- */

html { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .tile-btn:hover img { transform: none; }
  .tile:hover figcaption, .tile:focus-within figcaption { transform: none; }
  .hero-media img { animation: none; transform: none; }
  .btn-gold:hover, .btn-gold:active, .btn-ghost:hover,
  .btn-ghost:active, .service-card:hover { transform: none; }
  .link-arrow:hover::after { transform: none; }
  .lightbox, .lb-figure, .header-collapse, .to-top { transition: none; }
  /* the loading blur stays -- it is a state, not an animation */
  .lb-figure img { transition: none; }
  .js-lqip [data-lqip] > .pic > img,
  .js-lqip [data-lqip] > img { opacity: 1; transition: none; }
  .to-top:active { transform: none; }
  .area-chip:hover, .area-chip.is-active, .area-chip:active { transform: none; }
  .area-marker-dot { transition: none; }
  .area-marker.is-active .area-marker-dot,
  .area-marker:hover .area-marker-dot { transform: none; }
  .nav-toggle-bar, .nav-toggle-bar::before, .nav-toggle-bar::after { transition: none; }
  .nav-toggle:active { transform: none; }
  /* captions must never be stuck at opacity 0 when hover cannot be relied on */
  .tile figcaption { opacity: 1; transform: none; transition: none; }
  .skip-link { transition: none; }
  .service-card::after { transition: none; }
  .lightbox { opacity: 1; }
  .lb-figure { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------- narrow -- */

@media (max-width: 720px) {
  /* the bar carries the logo and the toggle; everything else drops into the
     panel below it (.site-header is sticky, so it anchors the absolute panel) */
  .header-inner { flex-wrap: nowrap; justify-content: space-between; gap: 12px; }

  /* Hidden only when JS is alive to open it again -- with JS off the panel
     simply stays stacked under the bar so the nav is never unreachable. */
  .js .header-collapse {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    padding: 6px var(--gutter) 22px;
    background: var(--surface-1);
    border-bottom: 1px solid var(--line);
    max-height: calc(100dvh - 68px);
    overflow-y: auto;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: opacity 200ms ease, transform 220ms var(--ease), visibility 0s linear 220ms;
  }
  .js .site-header.is-open .header-collapse {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: opacity 200ms ease, transform 220ms var(--ease), visibility 0s linear 0s;
  }

  .header-collapse {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    padding-bottom: 8px;
  }
  .js .nav-toggle { display: block; }

  .site-nav {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    font-size: 16px;
    letter-spacing: 0.01em;
  }
  .site-nav a {
    color: var(--text);
    padding: 14px 2px;
    border-bottom: 1px solid var(--line);
  }
  .site-nav a:last-child { border-bottom: 0; }

  .header-actions {
    order: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    margin-top: 16px;
  }
  .header-cta { text-align: center; font-size: 16px; padding: 14px 20px; }
  /* auto-fit was landing these in two columns on most phones while the rules
     below assumed one, so the top-right cell carried a hairline the top-left
     did not and the two columns ran together with nothing between them. Pin
     the count instead: one column where 34px numerals will not fit beside each
     other, a proper 2x2 with both dividers everywhere else. */
  .stats-grid { grid-template-columns: 1fr; }
  .stat,
  .stat:first-child,
  .stat:last-child { padding: 22px 0; border-left: 0; border-top: 1px solid var(--line); }
  .stats-grid > .stat:first-child { border-top: 0; }
  .lb-prev, .lb-next { top: auto; bottom: clamp(14px, 3vw, 28px); transform: none; }
}

@media (min-width: 400px) and (max-width: 720px) {
  .stats-grid { grid-template-columns: 1fr 1fr; }
  .stat,
  .stat:first-child,
  .stat:last-child { padding: 22px 20px 22px 0; }
  /* the right-hand column sits across a hairline */
  .stat:nth-child(even),
  .stat:last-child { border-left: 1px solid var(--line); padding: 22px 0 22px 20px; }
  /* both cells of the first row open the band, so neither is capped */
  .stats-grid > .stat:nth-child(-n+2) { border-top: 0; }
}


/* ------------------------------------------------------ sticky call bar -- */
/* Phones only. Sits below the back-to-top button's corner, and only appears
   once the hero (which already carries a call button) has scrolled away. */

.call-bar { display: none; }

@media (max-width: 720px) {
  .call-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-call-bar);
    padding: 11px var(--gutter);
    padding-bottom: calc(11px + env(safe-area-inset-bottom, 0px));
    background: rgba(19, 19, 24, 0.94);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--bronze);
    color: var(--text);
    transform: translateY(102%);
    transition: transform 260ms var(--ease);
  }
  .call-bar.is-in { transform: none; }
  .call-bar:hover, .call-bar:active { color: var(--text); }
  .call-bar .icon {
    width: 20px;
    height: 20px;
    flex: none;
    color: var(--gold);
  }
  .call-bar-text { display: flex; flex-direction: column; line-height: 1.2; }
  .call-bar-num {
    font-family: var(--display);
    font-weight: 700;
    font-size: 19px;
    letter-spacing: 0.01em;
    font-variant-numeric: tabular-nums;
  }
  .call-bar-sub {
    font-size: 12px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    margin-top: 2px;
  }

  /* keep the bar off the footer's last line and clear of back-to-top */
  body.has-call-bar .site-footer { padding-bottom: 78px; }
  body.has-call-bar .to-top { bottom: calc(66px + env(safe-area-inset-bottom, 0px)); }
}

/* --------------------------------------------------------- map entrance -- */
/* The boundary draws itself once, then the towns drop in around it. Both are
   driven from script.js so a failed map load never leaves anything hidden. */

.area-ring {
  transition: stroke-dashoffset 1400ms cubic-bezier(0.33, 0.1, 0.2, 1),
              fill-opacity 700ms ease 700ms;
}
.area-ring.is-drawing { fill-opacity: 0; }

.area-marker.is-drop .area-marker-dot {
  opacity: 0;
  transform: translateY(-14px) scale(0.35);
}
.area-marker .area-marker-dot { transition-duration: 420ms; }

@media (prefers-reduced-motion: reduce) {
  .call-bar { transition: none; }
  .area-ring { transition: none; }
  .area-marker.is-drop .area-marker-dot { opacity: 1; transform: none; }
}
