/* ==========================================================================
   BN Builders — Homepage Redesign (light theme)
   Clean rebuild. No WordPress / Elementor dependencies.
   Brand palette preserved from the live site.

   Theme: light page overall; hero, CTA band and footer stay dark
   as deliberate contrast anchors.
   ========================================================================== */

:root {
  /* Brand colors — carried over unchanged from the live site */
  --ink:        #2E2725;  /* near-black brown */
  --ink-2:      #3A312E;  /* raised dark surface */
  --ink-3:      #4A3F3A;  /* dark hairline */
  --brown:      #804E3A;  /* brand brown */
  --brown-dk:   #6A3F2E;
  --gold:       #DEA349;  /* brand gold */
  --gold-soft:  #DC9E41;
  --gold-dk:    #C98F3A;  /* gold, darkened for hover */
  --cream:      #F8F4F2;  /* brand cream */
  --white:      #FFFFFF;

  /* light-theme surfaces */
  --bg:         #FBF9F8;
  --surface:    #FFFFFF;
  --surface-2:  #F3EDE9;
  --line:       #E6DCD6;
  --line-2:     #D8CAC1;

  --text:       #2E2725;
  --text-mut:   #6B5E58;
  --text-soft:  #8A7C74;

  /* dark-section text */
  --on-dark:     #F8F4F2;
  --on-dark-mut: #B5A9A2;

  --maxw: 1280px;
  --gutter: clamp(20px, 5vw, 64px);
  --r-sm: 12px;
  --r-md: 20px;
  --r-lg: 28px;
  --r-xl: 36px;
  --r-pill: 999px;

  --ease: cubic-bezier(.22,.61,.36,1);
  --dur: .55s;
  --sect-y: clamp(68px, 9vw, 128px);

  --shadow-sm: 0 2px 10px rgba(46,39,37,.05);
  --shadow-md: 0 10px 34px rgba(46,39,37,.09);
  --shadow-lg: 0 26px 70px rgba(46,39,37,.14);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, video, iframe { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
h1,h2,h3,h4,h5,h6 { margin: 0; font-weight: 500; line-height: 1.12; letter-spacing: -.02em; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.sect { padding-block: var(--sect-y); position: relative; }

/* section tone variants — give each SEO block its own anchor */
.sect--tint  { background: var(--surface-2); }
.sect--white { background: var(--surface); }
.sect--dark  { background: var(--ink); color: var(--on-dark); }
.sect--dark .lede { color: var(--on-dark-mut); }

/* ---------- type ---------- */
.display {
  font-size: clamp(2.3rem, 4.4vw, 3.9rem);
  font-weight: 500; line-height: 1.06; letter-spacing: -.035em;
}
.h2 { font-size: clamp(1.9rem, 3.5vw, 3rem); font-weight: 500; letter-spacing: -.03em; line-height: 1.1; }
.h3 { font-size: clamp(1.2rem, 1.8vw, 1.55rem); font-weight: 500; }
.lede { font-size: clamp(1rem, 1.15vw, 1.1rem); color: var(--text-mut); line-height: 1.72; font-weight: 300; }

.eyebrow {
  display: inline-flex; align-items: center; gap: .55rem;
  font-size: .73rem; font-weight: 600; letter-spacing: .18em;
  text-transform: uppercase; color: var(--brown);
  margin-bottom: 1rem;
}
.eyebrow::before { content: ""; width: 26px; height: 1px; background: currentColor; opacity: .5; }
.sect--dark .eyebrow { color: var(--gold); }
.gold { color: var(--gold); }
.brownt { color: var(--brown); }

/* section head with an index number, so stacked SEO blocks stay distinct.
   Stacked (not a flex row) so headings stay flush-left with the body copy. */
.shead { display: block; }
.shead__no {
  display: inline-block;
  font-size: .74rem; font-weight: 600; letter-spacing: .14em;
  color: var(--brown); padding-top: .5rem; margin-bottom: .7rem;
  border-top: 2px solid var(--gold);
}
.sect--dark .shead__no { color: var(--gold); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .95rem 1.7rem; border-radius: var(--r-pill);
  font-size: .93rem; font-weight: 600; letter-spacing: .01em;
  border: 1px solid transparent; cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform .25s var(--ease),
              box-shadow .4s var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn--gold { background: var(--gold); color: var(--ink); box-shadow: 0 6px 20px rgba(222,163,73,.3); }
.btn--gold:hover { background: var(--gold-dk); color: var(--ink); box-shadow: 0 10px 28px rgba(201,143,58,.34); }
.btn--brown { background: var(--brown); color: var(--white); }
.btn--brown:hover { background: var(--ink); }
.btn--ghost { border-color: var(--line-2); color: var(--text); background: transparent; }
.btn--ghost:hover { background: var(--ink); color: var(--cream); border-color: var(--ink); }
.sect--dark .btn--ghost, .hero .btn--ghost, .cta .btn--ghost, .bt--dark .btn--ghost,
.shero .btn--ghost, .phero .btn--ghost, .chero .btn--ghost, .ribbon .btn--ghost, .acard--dark .btn--ghost,
.scard--cta .btn--ghost {
  border-color: rgba(248,244,242,.36); color: var(--on-dark);
}
.sect--dark .btn--ghost:hover, .hero .btn--ghost:hover,
.cta .btn--ghost:hover, .bt--dark .btn--ghost:hover,
.shero .btn--ghost:hover, .phero .btn--ghost:hover, .chero .btn--ghost:hover,
.ribbon .btn--ghost:hover, .acard--dark .btn--ghost:hover,
.scard--cta .btn--ghost:hover {
  background: var(--on-dark); color: var(--ink); border-color: var(--on-dark);
}
.btn .ico { transition: transform .4s var(--ease); }
.btn:hover .ico { transform: translateX(4px); }

/* ==========================================================================
   HEADER — logo left, centered floating nav pill, actions right
   ========================================================================== */
.hdr { position: fixed; inset: 14px 0 auto; z-index: 90; }
.hdr__in {
  max-width: calc(var(--maxw) + 60px); margin-inline: auto;
  padding-inline: var(--gutter);
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: 1rem;
}
.hdr__logo { justify-self: start; }
.hdr__logo img {
  height: 60px; width: auto;
  filter: drop-shadow(0 2px 10px rgba(0,0,0,.5));
  transition: height .4s var(--ease);
}
.hdr.is-stuck .hdr__logo img { height: 50px; }

/* the floating nav pill */
.nav {
  justify-self: center;
  display: flex; align-items: center; gap: .15rem;
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(46,39,37,.07);
  border-radius: var(--r-pill);
  padding: .38rem;
  box-shadow: 0 8px 30px rgba(46,39,37,.14);
  transition: background .4s var(--ease), box-shadow .4s var(--ease);
}
.nav a {
  padding: .58rem 1.05rem; border-radius: var(--r-pill);
  font-size: .87rem; font-weight: 500; color: var(--text-mut);
  white-space: nowrap;
  transition: color .3s var(--ease), background .3s var(--ease);
}
.nav a:hover { color: var(--text); background: var(--surface-2); }
.nav a.is-active { color: var(--white); background: var(--brown); }

.hdr__cta { justify-self: end; display: flex; align-items: center; gap: .55rem; }
/* tap-to-call icon button */
.hdr__call {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; flex: none; border-radius: 50%;
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(46,39,37,.07);
  box-shadow: 0 8px 30px rgba(46,39,37,.14);
  color: var(--brown);
  transition: transform .3s var(--ease), background .35s var(--ease), color .35s var(--ease);
}
.hdr__call:hover { transform: translateY(-2px); background: var(--gold-dk); color: var(--ink); }
.hdr__call svg { width: 18px; height: 18px; }
.hdr .btn--gold { padding: .8rem 1.5rem; font-size: .87rem; white-space: nowrap; }

.burger {
  display: none; width: 46px; height: 46px; flex: none;
  border-radius: 50%; cursor: pointer; padding: 0;
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(46,39,37,.07);
  box-shadow: 0 8px 30px rgba(46,39,37,.14);
  flex-direction: column; align-items: center; justify-content: center;
}
.burger span {
  display: block; width: 17px; height: 1.6px;
  background: var(--text); border-radius: 2px;
  transition: transform .35s var(--ease), opacity .25s var(--ease);
}
.burger span + span { margin-top: 4px; }
.burger.is-open span:nth-child(1) { transform: translateY(5.6px) rotate(45deg); }
.burger.is-open span:nth-child(2) { opacity: 0; }
.burger.is-open span:nth-child(3) { transform: translateY(-5.6px) rotate(-45deg); }

.drawer {
  position: fixed; inset: 0; z-index: 89;
  background: rgb(251,249,248);
  backdrop-filter: blur(22px); -webkit-backdrop-filter: blur(22px);
  padding: 104px var(--gutter) 40px;
  display: flex; flex-direction: column; gap: .1rem;
  opacity: 0; visibility: hidden; transform: translateY(-12px);
  transition: opacity .4s var(--ease), transform .4s var(--ease), visibility .4s;
  overflow-y: auto;
}
.drawer.is-open { opacity: 1; visibility: visible; transform: none; }
.drawer a {
  font-size: 1.35rem; font-weight: 500; padding: .8rem 0;
  border-bottom: 1px solid var(--line); color: var(--text);
}
.drawer a:hover { color: var(--brown); }
.drawer .btn { margin-top: 1.6rem; justify-content: center; }

/* ==========================================================================
   HERO — dark anchor, full-bleed media
   ========================================================================== */
.hero {
  position: relative;
  /* Full viewport height: the old clamp(620px, 94vh, 980px) left 18-101px of
     white below the video depending on screen (worst on a 1080p desktop and on
     mobile, where the 980px cap and the 94vh both bit). 100svh rather than
     100vh so mobile browser chrome does not push the bottom off-screen. */
  min-height: 100svh;
  display: flex; align-items: flex-end;
  padding: 150px 0 clamp(48px, 7vw, 92px);
  overflow: hidden; isolation: isolate;
  background: var(--ink);
}
@supports not (height: 100svh) {
  .hero { min-height: 100vh; }
}

.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__media img, .hero__media video {
  width: 100%; height: 100%; object-fit: cover; object-position: center 58%;
}
.hero__media img { animation: heroDrift 28s var(--ease) infinite alternate; }
@keyframes heroDrift {
  from { transform: scale(1.04); } to { transform: scale(1.13) translateY(-1.4%); }
}
.hero__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to top, rgba(46,39,37,.97) 0%, rgba(46,39,37,.74) 32%, rgba(46,39,37,.28) 62%, rgba(46,39,37,.52) 100%),
    linear-gradient(to right, rgba(46,39,37,.80) 0%, rgba(46,39,37,.10) 62%);
}
/* The clip is far brighter than the still it replaced (open sky, white
   concrete, sunlit siding), and it MOVES, so a bright frame can slide under
   the headline at any moment. Measured 3.13:1 desktop / 2.48:1 mobile against
   the old scrim; this darkens the left column where the copy sits. */
.hero:has(.hero__media video) .hero__scrim {
  /* Lightened now the form has moved out of the hero: the copy occupies the
     left third instead of the full width, so the scrim only has to protect
     that band and the footage reads far more clearly on the right.
     Re-measured across the loop after every change -- see the commit. */
  background:
    linear-gradient(to top, rgba(46,39,37,.94) 0%, rgba(46,39,37,.78) 40%, rgba(46,39,37,.50) 72%, rgba(46,39,37,.56) 100%),
    linear-gradient(to right, rgba(46,39,37,.88) 0%, rgba(46,39,37,.66) 38%, rgba(46,39,37,.18) 72%, rgba(46,39,37,0) 100%);
}
@media (max-width: 900px) {
  /* stacked, the copy spans the full width, so the scrim must too */
  .hero:has(.hero__media video) .hero__scrim {
    /* Full-height hero pushed the badges up into a brighter part of the frame
       (sky rather than siding), dropping them to 4.01:1. Darken the upper half
       where they now sit. */
    background: linear-gradient(to top, rgba(46,39,37,.94) 0%, rgba(46,39,37,.89) 40%, rgba(46,39,37,.88) 72%, rgba(46,39,37,.91) 100%);
  }
}
.hero__grid {
  display: grid; grid-template-columns: 1.35fr .95fr;
  gap: clamp(2rem, 5vw, 4.5rem); align-items: end; width: 100%;
}
.hero .display { max-width: 18ch; color: var(--on-dark); }
.hero__badges { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.4rem; }
.badge {
  display: inline-flex; align-items: center; gap: .45rem;
  background: rgba(248,244,242,.10);
  border: 1px solid rgba(248,244,242,.19);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border-radius: var(--r-pill); padding: .42rem .95rem;
  font-size: .76rem; font-weight: 500; color: var(--on-dark);
}
.badge .stars { color: var(--gold); letter-spacing: .06em; }
.hero__sub {
  margin-top: 1.4rem; max-width: 54ch;
  font-size: clamp(1rem, 1.2vw, 1.12rem);
  color: rgba(248,244,242,.87); font-weight: 300; line-height: 1.66;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2rem; }

.hero__card {
  background: rgba(255,255,255,.97);
  border: 1px solid rgba(255,255,255,.6);
  border-radius: var(--r-lg);
  padding: clamp(1.4rem, 2.4vw, 2rem);
  box-shadow: 0 30px 70px rgba(0,0,0,.4);
}
.hero__card h4 { font-size: 1.16rem; margin-bottom: .35rem; color: var(--text); }
.hero__card .fine { font-size: .84rem; color: var(--text-mut); margin-bottom: 1.1rem; }

/* ---------- forms ---------- */
.field { margin-bottom: .7rem; }
.field input, .field textarea, .field select {
  width: 100%; background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: .85rem 1rem;
  color: var(--text); font-family: inherit; font-size: .92rem;
  transition: border-color .3s var(--ease), background .3s var(--ease), box-shadow .3s var(--ease);
}
.field textarea { resize: vertical; min-height: 92px; }
.field input::placeholder, .field textarea::placeholder { color: var(--text-soft); }
.field input:focus, .field textarea:focus {
  outline: none; border-color: var(--gold); background: var(--white);
  box-shadow: 0 0 0 3px rgba(222,163,73,.16);
}
.field--row { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }
.hp { position: absolute !important; left: -9999px !important; opacity: 0; height: 0; }
.form-msg { margin-top: .8rem; font-size: .87rem; border-radius: var(--r-sm); padding: .7rem .9rem; display: none; }
.form-msg.success { display: block; background: #E7F4E9; border: 1px solid #A8D6B0; color: #24632F; }
.form-msg.error   { display: block; background: #FBE9E7; border: 1px solid #E4A9A2; color: #8C2B20; }
.hero__card .btn { width: 100%; justify-content: center; margin-top: .3rem; }

/* ==========================================================================
   WELCOME intro band (restored from the live site)
   ========================================================================== */
.welcome { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.6rem, 4vw, 4rem); align-items: center; }
.welcome__lead { font-size: clamp(1.25rem, 2vw, 1.7rem); font-weight: 400; line-height: 1.4; letter-spacing: -.02em; }
.welcome .btn { margin-top: 1.6rem; }

/* ==========================================================================
   TRUST STRIP
   ========================================================================== */
.strip {
  border-block: 1px solid var(--line);
  padding-block: 1.1rem; overflow: hidden; background: var(--surface);
}
.strip__track { display: flex; gap: 3.5rem; width: max-content; animation: slide 44s linear infinite; }
.strip:hover .strip__track { animation-play-state: paused; }
@keyframes slide { to { transform: translateX(-50%); } }
.strip__item {
  display: inline-flex; align-items: center; gap: .6rem;
  font-size: .82rem; font-weight: 500; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-soft); white-space: nowrap;
}
.strip__item .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--gold); }

/* ==========================================================================
   SERVICES — expanding accordion
   ========================================================================== */
.svc { display: flex; gap: .7rem; height: clamp(420px, 55vw, 530px); }
.svc__panel {
  position: relative; flex: 1 1 0; min-width: 62px;
  border-radius: var(--r-md); overflow: hidden; cursor: pointer;
  isolation: isolate; transition: flex-grow .75s var(--ease);
  background: var(--ink-2);
}
.svc__panel.is-open { flex-grow: 5.2; }
.svc__panel img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.1s var(--ease), filter .6s var(--ease);
  filter: saturate(.72) brightness(.6);
}
.svc__panel.is-open img { filter: saturate(1) brightness(.76); transform: scale(1.04); }
.svc__panel::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, rgba(46,39,37,.95) 6%, rgba(46,39,37,.34) 58%, rgba(46,39,37,.16) 100%);
}
.svc__spine { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; transition: opacity .4s var(--ease); }
.svc__spine span {
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-size: .95rem; font-weight: 500; color: var(--on-dark); white-space: nowrap;
}
.svc__panel.is-open .svc__spine { opacity: 0; pointer-events: none; }
.svc__body {
  position: absolute; inset: auto 0 0 0; padding: clamp(1.3rem, 2.2vw, 2rem);
  opacity: 0; transform: translateY(14px); pointer-events: none;
  transition: opacity .5s var(--ease) .18s, transform .5s var(--ease) .18s;
}
.svc__panel.is-open .svc__body { opacity: 1; transform: none; pointer-events: auto; }
.svc__body h3 { color: var(--on-dark); }
.svc__body p { color: rgba(248,244,242,.85); font-size: .93rem; font-weight: 300; max-width: 46ch; margin: .55rem 0 1.05rem; }
.svc__num { font-size: .74rem; font-weight: 600; color: var(--gold); letter-spacing: .14em; margin-bottom: .45rem; display: block; }
.svc__link { display: inline-flex; align-items: center; gap: .45rem; font-size: .87rem; font-weight: 600; color: var(--gold); }
.svc__link:hover { color: var(--white); }

.svc--stack { display: none; gap: .85rem; }
.svc-card {
  position: relative; overflow: hidden; border-radius: var(--r-md);
  min-height: 260px; display: flex; align-items: flex-end;
  padding: 1.3rem; isolation: isolate;
}
.svc-card img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; filter: brightness(.58); }
.svc-card::after { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgba(46,39,37,.95), rgba(46,39,37,.14)); }
.svc-card h3 { color: var(--on-dark); }
.svc-card p { font-size: .89rem; color: rgba(248,244,242,.84); margin: .4rem 0 .85rem; font-weight: 300; }

/* ==========================================================================
   PROCESS — sticky stacking
   ========================================================================== */
.proc__list { margin-top: clamp(2.5rem, 5vw, 4rem); }
.proc__step { position: sticky; top: clamp(96px, 13vh, 150px); margin-bottom: 1.1rem; }
.proc__card {
  border-radius: var(--r-lg); padding: clamp(1.6rem, 3.4vw, 3rem);
  display: grid; grid-template-columns: auto 1fr auto;
  gap: clamp(1.2rem, 3vw, 3rem); align-items: center;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: 0 -14px 40px rgba(46,39,37,.10);
}
.proc__step:nth-child(2) .proc__card { background: #FDFBFA; }
.proc__step:nth-child(3) .proc__card { background: var(--surface-2); }
.proc__step:nth-child(4) .proc__card {
  background: linear-gradient(140deg, var(--brown), var(--brown-dk));
  border-color: transparent; color: var(--on-dark);
}
.proc__step:nth-child(4) .proc__card p { color: rgba(248,244,242,.82); }
.proc__num {
  font-size: clamp(3rem, 7vw, 5.6rem); font-weight: 600; line-height: .82;
  color: transparent; -webkit-text-stroke: 1.4px var(--line-2); letter-spacing: -.05em;
}
.proc__step:nth-child(4) .proc__num { color: var(--gold); -webkit-text-stroke: 0; }
.proc__card h3 { margin-bottom: .4rem; }
.proc__card p { color: var(--text-mut); font-weight: 300; font-size: .97rem; }
.proc__thumb { width: clamp(120px, 15vw, 210px); aspect-ratio: 4/3; border-radius: var(--r-md); overflow: hidden; }
.proc__thumb img { width: 100%; height: 100%; object-fit: cover; }

/* ==========================================================================
   PROJECTS
   ========================================================================== */
.proj { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(.8rem, 1.5vw, 1.15rem); margin-top: clamp(2.2rem, 4vw, 3.4rem); }
.pcard {
  position: relative; overflow: hidden; border-radius: var(--r-md);
  isolation: isolate; min-height: 240px; display: flex; align-items: flex-end;
  padding: clamp(1.1rem, 2vw, 1.7rem);
  box-shadow: var(--shadow-sm);
  transition: box-shadow .5s var(--ease), transform .5s var(--ease);
}
.pcard:hover { box-shadow: var(--shadow-lg); transform: translateY(-3px); }
.pcard--hero  { grid-column: span 7; min-height: clamp(340px, 42vw, 470px); }
.pcard--tall  { grid-column: span 5; min-height: clamp(340px, 42vw, 470px); }
.pcard--third { grid-column: span 4; min-height: clamp(240px, 26vw, 320px); }
.pcard img {
  position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%;
  object-fit: cover; filter: brightness(.74) saturate(.94);
  transition: transform 1s var(--ease), filter .6s var(--ease);
}
.pcard::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, rgba(46,39,37,.94) 4%, rgba(46,39,37,.28) 55%, transparent 100%);
}
.pcard:hover img { transform: scale(1.06); filter: brightness(.84) saturate(1); }
.pcard__tag { display: inline-block; font-size: .68rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; color: var(--gold); margin-bottom: .4rem; }
.pcard h3 { font-size: clamp(1.05rem, 1.55vw, 1.4rem); color: var(--on-dark); }
.pcard p { color: rgba(248,244,242,.82); font-size: .88rem; font-weight: 300; margin-top: .35rem; max-width: 44ch; }
.pcard__go { margin-top: .8rem; display: inline-flex; align-items: center; gap: .4rem; font-size: .84rem; font-weight: 600; color: var(--gold); }
.pcard__inner { position: relative; z-index: 1; }

/* ==========================================================================
   BENTO — Why BN Builders
   ========================================================================== */
.bento { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(.8rem, 1.4vw, 1.1rem); margin-top: clamp(2.2rem, 4vw, 3.4rem); }
.bt {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.3rem, 2.3vw, 1.9rem);
  display: flex; flex-direction: column; gap: 1.1rem; min-height: 175px;
  box-shadow: var(--shadow-sm);
  transition: border-color .5s var(--ease), transform .5s var(--ease), box-shadow .5s var(--ease);
}
.bt:hover { border-color: var(--gold); transform: translateY(-3px); box-shadow: var(--shadow-md); }
.bt > div:last-child { margin-top: auto; }
.bt__ico {
  width: 42px; height: 42px; border-radius: 12px;
  background: rgba(222,163,73,.14); border: 1px solid rgba(222,163,73,.34);
  display: grid; place-items: center; color: var(--brown); flex: none;
}
.bt__ico svg { width: 20px; height: 20px; }
.bt h4 { font-size: 1.04rem; font-weight: 500; margin-bottom: .3rem; }
.bt p { font-size: .87rem; color: var(--text-mut); font-weight: 300; line-height: 1.6; }
/* six feature tiles fill the left 8 columns in two columns of three.
   Explicit placement — the media tile is first in the DOM, so nth-child
   counting would offset every tile after it. */
.bt--sm { grid-column: span 4; }
.bt--wide { grid-column: span 8; }
.bento > .bt--sm:nth-child(2) { grid-column: 1 / span 4; grid-row: 1; }
.bento > .bt--sm:nth-child(3) { grid-column: 5 / span 4; grid-row: 1; }
.bento > .bt--sm:nth-child(4) { grid-column: 1 / span 4; grid-row: 2; }
.bento > .bt--sm:nth-child(5) { grid-column: 5 / span 4; grid-row: 2; }
.bento > .bt--sm:nth-child(6) { grid-column: 1 / span 4; grid-row: 3; }
.bento > .bt--sm:nth-child(7) { grid-column: 5 / span 4; grid-row: 3; }
/* portrait media tile — pinned to the right column, spans all three rows */
.bt--media {
  grid-column: 9 / span 4; grid-row: 1 / span 3;
  padding: 0; overflow: hidden; position: relative;
  min-height: 250px; isolation: isolate; border-color: transparent;
}
.bt--media img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; object-position: center 22%;
  filter: brightness(.72); transition: transform 1s var(--ease);
}
.bt--media:hover img { transform: scale(1.05); }
.bt--media::after { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgba(46,39,37,.94), rgba(46,39,37,.18)); }
.bt--media .bt__cap { margin-top: auto; padding: clamp(1.2rem, 2vw, 1.7rem); }
.bt--media h4 { color: var(--on-dark); }
.bt--media p { color: rgba(248,244,242,.82); }
.bt--gold { background: linear-gradient(150deg, var(--gold), var(--gold-soft)); border-color: transparent; color: var(--ink); }
.bt--gold p { color: rgba(46,39,37,.8); }
.bt--gold .bt__ico { background: rgba(46,39,37,.13); border-color: rgba(46,39,37,.24); color: var(--ink); }
.bt--dark { background: var(--ink); border-color: transparent; color: var(--on-dark); }
.bt--dark p { color: var(--on-dark-mut); }
.bt--dark .bt__ico { background: rgba(222,163,73,.16); border-color: rgba(222,163,73,.34); color: var(--gold); }
.bt__stat { font-size: clamp(2.1rem, 3.6vw, 3rem); font-weight: 600; letter-spacing: -.04em; line-height: 1; color: var(--brown); }

/* ==========================================================================
   SPLIT feature blocks
   ========================================================================== */
/* align-items:stretch, not center: a fixed 4/3 media beside a tall text column
   left the photo floating with up to 400px of dead space next to it. The photo
   now grows to the row's height, with the ratio as a floor so a SHORT column
   cannot squash it. */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.6rem, 4.5vw, 4.5rem); align-items: stretch; }
/* Without min-width:0 a grid track's floor is its MIN-CONTENT width. The text
   column's widest unbreakable run (650px here) then overrode `1fr` and ate the
   photo's track: 226px at 1024, 7px at 768, 0px at 740. */
.split > * { min-width: 0; }
.split--flip .split__media { order: 2; }
.split__media {
  border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-md);
  /* The photo fills its grid column and stretches to the row height so it is
     symmetrical with the text beside it.
     NOTE: do NOT combine aspect-ratio with height:100% here. The browser then
     derives WIDTH from height, so a tall row produced an 891px image inside a
     576px column, overlapping the text. Width comes from the grid column;
     min-height keeps a short row from collapsing the photo into a letterbox. */
  width: 100%;
  min-height: min(24vw, 340px);
}
/* Between 720 and 1200 the text column (spec rows + heading + button) drives the
   row to ~640px. Stretching a 4:3 landscape photo to that height inside a ~330px
   column cropped 60% of it away. Below 1200 the photo keeps its own aspect ratio
   and sits at the top instead of matching the text height. */
@media (max-width: 1200px) {
  .split { align-items: start; }
  .split__media { aspect-ratio: 4 / 3; height: auto; min-height: 0; }
}
.split__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease); }
/* Two photos sharing the single media column, stacked. The pair has to end up
   exactly as tall as the copy beside it, so the stack is a 2-row grid of equal
   FRACTIONS rather than two aspect-ratio boxes: fractions divide whatever
   height the row ends up at, while aspect ratios would derive their own height
   from the column width and leave the stack taller or shorter than the text. */
.split__media--stack {
  display: grid; grid-template-rows: 1fr 1fr;
  gap: clamp(.7rem, 1.4vw, 1.1rem);
  border-radius: 0; overflow: visible; box-shadow: none;
}
.split__media--stack > figure {
  margin: 0; min-height: 0; overflow: hidden;
  border-radius: var(--r-lg); box-shadow: var(--shadow-md);
}
.split__media--stack > figure > img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.1s var(--ease);
}
.split__media--stack > figure:hover > img { transform: scale(1.05); }
/* The parent's 1200px rule stops matching the text height, because ONE 4:3
   photo stretched to a ~640px row lost 60% of its frame. Two stacked photos
   each take about half that height, so they never hit that crop and can keep
   matching the copy the whole way down; below 900 the split is a single
   column and there is no text height left to match. */
@media (max-width: 1200px) and (min-width: 721px) {
  .split:has(.split__media--stack) { align-items: stretch; }
  .split__media--stack {
    aspect-ratio: auto; height: auto; min-height: 0;
    grid-template-rows: 1fr 1fr;
  }
}
/* 720 is where .split itself drops to one column (see RESPONSIVE). Matching
   that exactly matters: an earlier 900px cut-off fired while the split was
   still side by side, which let the second figure collapse to nothing. */
@media (max-width: 720px) {
  /* aspect-ratio must be cleared here too, not just the row template. The
     parent .split__media takes a 4:3 box below 1200; leaving that on the stack
     pinned it to one photo's height while `auto auto` asked for two, so the
     second figure overflowed and sat 231px on top of the first. */
  .split__media--stack {
    aspect-ratio: auto; height: auto; min-height: 0;
    grid-template-rows: auto auto;
  }
  .split__media--stack > figure { aspect-ratio: 4 / 3; }
}

.split__media:hover img { transform: scale(1.05); }
/* A before/after collage carries its own labels and framing, so it has to be
   seen whole. object-fit:cover sliced the wordmark off both edges of the
   square Saint Paul one when it was stretched into a tall column. `contain`
   plus a matching backdrop keeps the whole graphic and fills the leftover
   space with the collage's own paper colour rather than a hard letterbox. */
/* Sampled from each collage's own border ring: one is cream, the other grey,
   so a single shared colour would show a seam on whichever it did not match. */
/* A square collage cannot fill an 849px text column, so `contain` alone left
   deep empty bands above and below it. Dropping the stretch and centring the
   graphic at its own size removes them: the tile is now as tall as the picture
   rather than as tall as the copy. */
.split__media--whole {
  background: none; box-shadow: none; overflow: visible;
  align-self: center; min-height: 0; height: auto;
}
/* Below 1200 the parent caps every media box at 4:3. A square collage inside
   that box shrank to the box's HEIGHT (289px against 1059px of copy at 900),
   so it read as a thumbnail rather than as the section's image. Clearing the
   ratio lets it take the full column width and its own square height. */
@media (max-width: 1200px) {
  .split__media--whole { aspect-ratio: auto; }
}
.split__media--whole img {
  object-fit: contain; height: auto; max-height: 100%;
  border-radius: var(--r-lg); box-shadow: var(--shadow-md);
}
.split__media--whole:hover img { transform: none; }
/* Investment: a centred intro spanning the wrap, with the image/text split
   below it. The measure is capped so the opening paragraph does not run the
   full 1200px, which is unreadable as centred text. */
.ginvhead { text-align: center; max-width: 72ch; margin-inline: auto; }
.ginvhead > .eyebrow { justify-content: center; }
.ginvhead > .h2 { margin-top: .55rem; }
.ginvhead > p { margin-top: 1.1rem; }
.ginvhead + .split { margin-top: clamp(2rem, 4vw, 3.2rem); }


.split__body p + p { margin-top: 1rem; }
.split__body .lede { margin-top: 1rem; }
.split__body .btn { margin-top: 1.7rem; }

.drivers { margin-top: 1.3rem; display: grid; gap: .55rem; }
.drivers li { display: flex; gap: .8rem; align-items: flex-start; font-size: .93rem; font-weight: 300; color: var(--text-mut); line-height: 1.6; }
.drivers li::before { content: ""; flex: none; width: 6px; height: 6px; margin-top: .55rem; border-radius: 50%; background: var(--gold); }

/* ==========================================================================
   CATALOG
   ========================================================================== */
.cat__frame {
  margin-top: clamp(2rem, 3.5vw, 3rem); border-radius: var(--r-lg);
  overflow: hidden; border: 1px solid var(--line);
  background: var(--surface); box-shadow: var(--shadow-lg);
}
.cat__frame iframe { width: 100%; height: clamp(460px, 62vw, 800px); border: 0; display: block; }

/* ==========================================================================
   REVIEWS — symmetrical grid + read-more
   ========================================================================== */
/* horizontal slider — keeps the homepage short; the grid lives on /reviews/ */
.revwrap { position: relative; margin-top: clamp(2rem, 4vw, 3rem); }
.rev {
  display: flex; gap: clamp(.9rem, 1.6vw, 1.2rem);
  overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding: 4px;
  /* scrollbar hidden — navigation is via the prev/next buttons */
  scrollbar-width: none; -ms-overflow-style: none;
}
.rev::-webkit-scrollbar { display: none; }
.rcard {
  flex: 0 0 clamp(280px, 31%, 400px);
  scroll-snap-align: start;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.3rem, 2.1vw, 1.7rem);
  display: flex; flex-direction: column; gap: .85rem;
  box-shadow: var(--shadow-sm);
  transition: border-color .5s var(--ease), transform .5s var(--ease), box-shadow .5s var(--ease);
}
.rcard:hover { border-color: var(--gold); transform: translateY(-3px); box-shadow: var(--shadow-md); }

/* slider controls */
.revnav { display: flex; align-items: center; gap: .55rem; margin-top: .2rem; }
.revbtn {
  width: 46px; height: 46px; flex: none; border-radius: 50%;
  border: 1px solid var(--line-2); background: var(--surface);
  color: var(--text); cursor: pointer;
  display: grid; place-items: center;
  transition: all .35s var(--ease);
}
.revbtn:hover:not(:disabled) { background: var(--brown); color: var(--white); border-color: var(--brown); transform: translateY(-2px); }
.revbtn:disabled { opacity: .35; cursor: default; }
.revbtn svg { width: 17px; height: 17px; }
.rcard__top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.rcard__stars { color: var(--gold); font-size: .95rem; letter-spacing: .1em; }
.rcard__g { width: 18px; height: 18px; flex: none; opacity: .85; }
/* clamped body, expands on toggle — keeps every card the same height */
.rcard__txt {
  font-size: .92rem; font-weight: 300; color: var(--text-mut); line-height: 1.68;
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
  overflow: hidden;
}
.rcard.is-open .rcard__txt { -webkit-line-clamp: unset; overflow: visible; }
.rmore {
  align-self: flex-start; background: none; border: 0; padding: 0; cursor: pointer;
  font-size: .84rem; font-weight: 600; color: var(--brown);
  display: inline-flex; align-items: center; gap: .35rem;
}
.rmore:hover { color: var(--gold); }
.rmore svg { width: 12px; height: 12px; transition: transform .35s var(--ease); }
.rcard.is-open .rmore svg { transform: rotate(180deg); }
.rcard__who { display: flex; align-items: center; gap: .7rem; margin-top: auto; padding-top: .7rem; border-top: 1px solid var(--line); }
.rcard__av { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; font-weight: 600; font-size: .9rem; color: #fff; flex: none; }
.rcard__nm { font-size: .9rem; font-weight: 500; color: var(--text); }
.rcard__src { font-size: .76rem; color: var(--text-soft); }

/* ==========================================================================
   SERVICE AREA MAP
   ========================================================================== */
.area__map { margin-top: clamp(1.8rem, 3vw, 2.6rem); border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--line); box-shadow: var(--shadow-md); }
.area__map #service-map { height: clamp(360px, 46vw, 500px); width: 100%; background: var(--surface-2); }
/* soften the OSM tiles so they sit inside the warm light palette */
.area__map .leaflet-tile-pane { filter: saturate(.52) brightness(1.04) contrast(.94); }
.area__map .leaflet-container { background: var(--surface-2); font-family: inherit; }
.area__map .leaflet-control-attribution { background: rgba(255,255,255,.86); color: var(--text-soft); font-size: 10px; }
.area__map .leaflet-control-attribution a { color: var(--brown); }
.area__map .leaflet-bar a { background: var(--surface); color: var(--text); border-color: var(--line); }
.area__map .leaflet-bar a:hover { background: var(--gold); color: var(--ink); }
.area__map .leaflet-popup-content-wrapper, .area__map .leaflet-popup-tip { background: var(--surface); color: var(--text); }
.area__map .leaflet-popup-content a { color: var(--brown); font-weight: 600; }

/* two-column intro copy */
.twocol {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(1.4rem, 3.5vw, 3.2rem);
  margin-top: 1rem;
}

.cities { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1.6rem; }
.cities a {
  font-size: .82rem; padding: .45rem .95rem;
  border: 1px solid var(--line-2); border-radius: var(--r-pill);
  color: var(--text-mut); background: var(--surface);
  transition: all .35s var(--ease);
}
.cities a:hover { border-color: var(--brown); background: var(--brown); color: var(--white); }

/* ==========================================================================
   FAQ
   ========================================================================== */
.faq { margin-top: clamp(2rem, 3.5vw, 3rem); max-width: 900px; margin-inline: auto; }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q {
  width: 100%; background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  padding: 1.35rem 0; text-align: left;
  font-size: clamp(1rem, 1.3vw, 1.12rem); font-weight: 500; color: var(--text);
}
.faq__q:hover { color: var(--brown); }
.faq__sign { flex: none; width: 26px; height: 26px; position: relative; }
.faq__sign::before, .faq__sign::after {
  content: ""; position: absolute; inset: 50% 0 auto; height: 1.6px;
  background: var(--brown); border-radius: 2px; transition: transform .4s var(--ease);
}
.faq__sign::after { transform: rotate(90deg); }
.faq__item.is-open .faq__sign::after { transform: rotate(0deg); }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .45s var(--ease); }
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { padding-bottom: 1.4rem; padding-right: 2.5rem; color: var(--text-mut); font-weight: 300; font-size: .96rem; line-height: 1.72; }

/* ==========================================================================
   CTA band — dark anchor, split layout with media panel
   ========================================================================== */
.cta {
  position: relative; overflow: hidden; border-radius: var(--r-xl);
  background: var(--ink); color: var(--on-dark);
  display: grid; grid-template-columns: 1.05fr .95fr;
  box-shadow: var(--shadow-lg);
}
/* equal padding on all four sides */
.cta__body {
  padding: clamp(2.4rem, 4.4vw, 3.6rem);
  display: flex; flex-direction: column; justify-content: center;
  position: relative; z-index: 2;
}
/* soft brand glow behind the copy */
.cta__body::before {
  content: ""; position: absolute; z-index: -1;
  width: 460px; height: 460px; left: -180px; top: -140px;
  background: radial-gradient(circle, rgba(222,163,73,.24), transparent 68%);
  pointer-events: none;
}
.cta h2 { color: var(--on-dark); max-width: 18ch; }
.cta p { margin-top: 1.1rem; color: rgba(248,244,242,.84); font-weight: 300; max-width: 46ch; }
.cta__acts { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 2rem; }
/* trust row inside the CTA */
.cta__trust { display: flex; flex-wrap: wrap; gap: 1.6rem; margin-top: 2.2rem; padding-top: 1.6rem; border-top: 1px solid rgba(248,244,242,.14); }
.cta__stat .n { font-size: 1.5rem; font-weight: 600; color: var(--gold); line-height: 1; }
.cta__stat .l { font-size: .78rem; color: var(--on-dark-mut); margin-top: .3rem; }
.cta__media { position: relative; overflow: hidden; min-height: 340px; }
.cta__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cta__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to right, var(--ink) 0%, rgba(46,39,37,.55) 34%, rgba(46,39,37,.12) 100%);
}

/* ---------- CTA with a video background ----------
   Scoped to .cta--video so the other CTA sections keep their photo panel.
   The clip fills the whole card rather than sitting in a side column, so the
   copy needs its own scrim to stay readable over moving footage. */
.cta--video { grid-template-columns: 1fr; min-height: clamp(380px, 42vw, 520px); }
/* The heading and paragraph switch to cream over the video, but the eyebrow
   kept the light-background brown: 1.01-1.49:1 against the scrim at every
   width and every point in the loop. Gold is the site's dark-context eyebrow
   colour (.sect--dark, .nf__in, .lvabout__body), and it takes the average
   background here to ~6.3:1. The brightest pixels bleeding through the scrim
   still measured 4.32:1, so this uses a lighter tint of the same hue to clear
   AA against the worst pixel rather than the average. */
.cta--video .eyebrow { color: #E8B968; }
.cta--video .cta__body {
  grid-area: 1 / 1; z-index: 2;
  max-width: 720px;
  justify-content: center;
}
.cta__video { grid-area: 1 / 1; position: relative; overflow: hidden; }
.cta__video video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}
/* readability scrim: strongest where the copy sits */
.cta__video::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgba(46,39,37,.95) 0%, rgba(46,39,37,.85) 42%, rgba(46,39,37,.45) 100%),
    linear-gradient(to bottom, rgba(46,39,37,.45) 0%, rgba(46,39,37,.20) 45%, rgba(46,39,37,.5) 100%);
}
@media (max-width: 760px) {
  .cta--video .cta__body { max-width: none; }
  .cta__video::after {
    background: linear-gradient(to bottom, rgba(46,39,37,.91) 0%, rgba(46,39,37,.93) 100%);
  }
}
/* a moving background is motion: respect the OS setting */
@media (prefers-reduced-motion: reduce) {
  .cta__video video { display: none; }
  .cta__video {
    background-image: var(--cta-poster);
    background-size: cover; background-position: center;
  }
}

/* ==========================================================================
   CONTACT — bento
   ========================================================================== */
.cbento { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(.8rem, 1.4vw, 1.1rem); margin-top: clamp(2rem, 3.6vw, 3rem); }
.cb {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.3rem, 2.2vw, 1.9rem);
  box-shadow: var(--shadow-sm);
  transition: border-color .45s var(--ease), transform .45s var(--ease), box-shadow .45s var(--ease);
}
.cb:hover { border-color: var(--gold); transform: translateY(-3px); box-shadow: var(--shadow-md); }
.cb__ico {
  width: 40px; height: 40px; border-radius: 11px; margin-bottom: .9rem;
  background: rgba(222,163,73,.14); border: 1px solid rgba(222,163,73,.32);
  display: grid; place-items: center; color: var(--brown);
}
.cb__ico svg { width: 18px; height: 18px; }
.cb h4 { font-size: .78rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text-soft); font-weight: 600; margin-bottom: .7rem; }
.cb__big { font-size: clamp(1.1rem, 1.7vw, 1.35rem); font-weight: 500; letter-spacing: -.02em; display: block; }
.cb__big:hover { color: var(--brown); }
.cb p, .cb a { font-size: .93rem; color: var(--text-mut); font-weight: 300; }
.cb li { font-size: .93rem; color: var(--text-mut); font-weight: 300; }
.cb a:hover { color: var(--brown); }
.cb--phone { grid-column: span 4; }
.cb--addr  { grid-column: span 4; }
.cb--hours { grid-column: span 4; }
.cb--form  { grid-column: span 5; }
.cb--cal   { grid-column: span 7; padding: 0; overflow: hidden; }
.cb--cal .calendly-inline-widget { border-radius: var(--r-md); }
.cb--form h3 { margin-bottom: .4rem; }
.cb--form .fine { font-size: .89rem; color: var(--text-mut); font-weight: 300; margin-bottom: 1.1rem; }
.cb--form .btn { width: 100%; justify-content: center; margin-top: .3rem; }
/* The map fills the space the form leaves inside its card. The Calendly
   widget beside it is much taller, so at desktop this card carried ~276px of
   empty white. flex:1 hands that leftover height to the map instead of
   adding any to the page. */
.cb--form { display: flex; flex-direction: column; }
.cb--form form { flex: none; }
.cbmap {
  flex: 1 1 auto; min-height: 220px; margin-top: 1.1rem;
  border-radius: var(--r-md); overflow: hidden; background: var(--cream);
}
.cbmap iframe { display: block; width: 100%; height: 100%; border: 0; }
/* Once the bento stacks there is no leftover height to fill, so the map
   takes a shape of its own rather than collapsing to min-height. */
@media (max-width: 900px) {
  .cbmap { flex: none; aspect-ratio: 16 / 10; min-height: 0; }
}


.socials { display: flex; flex-wrap: wrap; gap: .5rem; }
.socials a {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--line-2); display: grid; place-items: center;
  color: var(--text-mut); background: var(--surface);
  transition: all .35s var(--ease);
}
.socials a:hover { border-color: var(--brown); background: var(--brown); color: var(--white); transform: translateY(-2px); }
.socials svg { width: 16px; height: 16px; }

/* ==========================================================================
   FOOTER — dark anchor
   ========================================================================== */
.ftr { background: var(--ink); color: var(--on-dark); padding-block: clamp(3rem, 6vw, 5rem) 0; }
.ftr__grid { display: grid; grid-template-columns: 1.7fr 1fr 1fr 1.2fr; gap: clamp(1.8rem, 3.5vw, 3rem); }
.ftr__logo img { height: 48px; margin-bottom: 1.1rem; }
.ftr p, .ftr a, .ftr li { font-size: .89rem; color: var(--on-dark-mut); font-weight: 300; }
.ftr a:hover { color: var(--gold); }
.ftr h5 { font-size: .77rem; letter-spacing: .15em; text-transform: uppercase; color: var(--on-dark); margin-bottom: 1rem; font-weight: 600; }
.ftr__col ul { display: grid; gap: .55rem; }
.ftr .socials a { border-color: rgba(248,244,242,.2); background: transparent; color: var(--on-dark-mut); }
.ftr .socials a:hover { border-color: var(--gold); background: var(--gold); color: var(--ink); }
/* The icon row sat directly under the licence line with nothing between them.
   Scoped to the footer column so the socials used elsewhere keep their own
   spacing. */
.ftr .socials { padding-top: 20px; }

.ftr__bbb { display: inline-block; margin-top: 1.2rem; background: var(--white); padding: .55rem .8rem; border-radius: 10px; }
.ftr__bbb img { height: 46px; width: auto; }
.ftr__btm {
  margin-top: clamp(2.4rem, 4vw, 3.5rem); border-top: 1px solid rgba(248,244,242,.13);
  padding-block: 1.4rem; display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
}
.ftr__btm p { font-size: .82rem; }

/* ==========================================================================
   REVEAL
   ========================================================================== */
.rv { opacity: 0; transform: translateY(24px); transition: opacity .85s var(--ease), transform .85s var(--ease); }
.rv.in { opacity: 1; transform: none; }
.rv-d1 { transition-delay: .08s; } .rv-d2 { transition-delay: .16s; }
.rv-d3 { transition-delay: .24s; } .rv-d4 { transition-delay: .32s; }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */
/* the 7-item menu is wide — tighten spacing so the CTA never wraps */
@media (max-width: 1440px) {
  .nav > ul > li > a { padding: .55rem .78rem; font-size: .845rem; }
  .hdr .btn--gold { padding: .74rem 1.15rem; font-size: .84rem; }
  .hdr__in { gap: .6rem; }
}
@media (max-width: 1240px) {
  .nav > ul > li > a { padding: .52rem .62rem; font-size: .81rem; }
  .hdr__logo img { height: 50px; }
}
@media (max-width: 1080px) {
  .nav { display: none; }
  .burger { display: flex; }
  /* tablet + mobile header: logo, tap-to-call and menu only */
  .hdr .btn--gold { display: none; }
  .hdr__in { grid-template-columns: 1fr auto; }
  .hero__grid { grid-template-columns: 1fr; gap: 2.2rem; }
  .hero__card { max-width: 520px; }
  .welcome { grid-template-columns: 1fr; gap: 1.4rem; }
  .svc { display: none; }
  .svc--stack { display: grid; grid-template-columns: 1fr 1fr; }
  .proc__card { grid-template-columns: auto 1fr; }
  .proc__thumb { display: none; }
  .cta { grid-template-columns: 1fr; }
  .cta__media { min-height: 240px; order: -1; }
  .cta__media::after { background: linear-gradient(to top, var(--ink) 4%, rgba(46,39,37,.35) 70%); }
  .ftr__grid { grid-template-columns: 1fr 1fr; }
  .pcard--hero, .pcard--tall, .pcard--third { grid-column: span 12; }
  .bt--sm, .bt--wide { grid-column: span 6; }
  .bento > .bt--sm:nth-child(n) { grid-column: span 6; grid-row: auto; }
  .bt--media { grid-column: span 6; grid-row: span 2; }
  .cb--phone, .cb--addr, .cb--hours { grid-column: span 6; }
  .cb--form, .cb--cal { grid-column: span 12; }
}
@media (max-width: 720px) {
  .hdr { inset: 8px 0 auto; }
  .split, .split--flip .split__media { grid-template-columns: 1fr; order: 0; }
  .twocol { grid-template-columns: 1fr; gap: 1rem; }
  .svc--stack { grid-template-columns: 1fr; }
  .bt--sm, .bt--wide { grid-column: span 12; }
  .bento > .bt--sm:nth-child(n) { grid-column: span 12; grid-row: auto; }
  .bt--media { grid-column: span 12; grid-row: auto; min-height: 340px; }
  .cb--phone, .cb--addr, .cb--hours { grid-column: span 12; }
  .rcard { flex: 0 0 86%; }
  .field--row { grid-template-columns: 1fr; }
  .ftr__grid { grid-template-columns: 1fr; }
  .proc__step { top: 84px; }
  .hero { min-height: 100svh; padding-top: 118px; }
  .shead { flex-direction: column; gap: .6rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .rv { opacity: 1; transform: none; }
  .hero__media img { animation: none; }
  /* the hero clip is motion too: fall back to its poster frame */
  .hero__media video { display: none; }
  .hero__media {
    background-image: url(/videos/bn-builders-project-poster.jpg);
    background-size: cover; background-position: center 58%;
  }
}

/* ==========================================================================
   INTERIOR PAGES
   ========================================================================== */

/* page hero — compact dark banner */
.phero {
  position: relative; isolation: isolate;
  background: var(--ink); color: var(--on-dark);
  padding: clamp(150px, 20vh, 205px) 0 clamp(56px, 8vw, 92px);
  overflow: hidden;
}
.phero__media { position: absolute; inset: 0; z-index: -2; }
.phero__media img { width: 100%; height: 100%; object-fit: cover; }
.phero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to top, rgba(46,39,37,.96), rgba(46,39,37,.72) 46%, rgba(46,39,37,.55)),
    linear-gradient(to right, rgba(46,39,37,.82), rgba(46,39,37,.28));
}
.phero h1 { color: var(--on-dark); max-width: 22ch; }
.phero .lede { color: rgba(248,244,242,.86); margin-top: 1.1rem; max-width: 62ch; }
.phero .hero__badges { margin-bottom: 1.2rem; }
.phero__actions { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 2rem; }

/* breadcrumb */
.crumb { display: flex; flex-wrap: wrap; gap: .45rem; align-items: center; font-size: .82rem; margin-bottom: 1.1rem; }
.crumb a, .crumb span { color: rgba(248,244,242,.72); }
.crumb a:hover { color: var(--gold); }
.crumb i { opacity: .5; font-style: normal; }

/* prose (blog articles, guides) */
.prose { max-width: 74ch; }
.prose > * + * { margin-top: 1.15rem; }
.prose h2 {
  font-size: clamp(1.5rem, 2.4vw, 2.1rem); font-weight: 500;
  letter-spacing: -.025em; margin-top: 2.6rem; line-height: 1.18;
}
.prose h3 { font-size: clamp(1.15rem, 1.7vw, 1.4rem); font-weight: 500; margin-top: 1.9rem; }
.prose p, .prose li { color: var(--text-mut); font-weight: 300; line-height: 1.78; }
.prose strong { color: var(--text); font-weight: 600; }
.prose ul, .prose ol { display: grid; gap: .6rem; padding-left: 0; }
.prose ul li { display: flex; gap: .8rem; }
.prose ul li::before {
  content: ""; flex: none; width: 6px; height: 6px; margin-top: .62rem;
  border-radius: 50%; background: var(--gold);
}
.prose ol { counter-reset: n; }
.prose ol li { display: flex; gap: .8rem; counter-increment: n; }
.prose ol li::before {
  content: counter(n); flex: none; min-width: 22px; height: 22px; margin-top: .18rem;
  border-radius: 50%; background: var(--surface-2); color: var(--brown);
  font-size: .74rem; font-weight: 600; display: grid; place-items: center;
}
.prose img { border-radius: var(--r-md); margin-block: 1.8rem; box-shadow: var(--shadow-md); }
.prose blockquote {
  border-left: 3px solid var(--gold); padding: .2rem 0 .2rem 1.3rem;
  color: var(--text); font-weight: 400;
}
.prose a:not(.btn) { color: var(--brown); text-decoration: underline; text-underline-offset: 3px; }
.prose a:not(.btn):hover { color: var(--gold); }

/* article layout with sticky aside */
.artgrid { display: grid; grid-template-columns: minmax(0,1fr) 320px; gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
.aside { position: sticky; top: 110px; display: grid; gap: 1rem; }
.acard {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.2rem, 2vw, 1.6rem);
  box-shadow: var(--shadow-sm);
}
.acard h4 { font-size: .78rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text-soft); font-weight: 600; margin-bottom: .8rem; }
.acard h3 { margin-bottom: .6rem; }
.acard p { font-size: .9rem; color: var(--text-mut); font-weight: 300; }
.acard .btn { width: 100%; justify-content: center; margin-top: .9rem; }
.acard--dark { background: var(--ink); border-color: transparent; color: var(--on-dark); }
.acard--dark h3, .acard--dark h4 { color: var(--on-dark); }
.acard--dark p { color: var(--on-dark-mut); }
.toc { display: grid; gap: .5rem; }
.toc a { font-size: .89rem; color: var(--text-mut); font-weight: 300; line-height: 1.45; }
.toc a:hover { color: var(--brown); }

/* article meta */
.ameta { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; font-size: .84rem; color: rgba(248,244,242,.76); margin-top: 1.4rem; }
.ameta .pill {
  background: rgba(248,244,242,.1); border: 1px solid rgba(248,244,242,.18);
  border-radius: var(--r-pill); padding: .32rem .85rem; font-weight: 500;
}

/* blog card grid */
.posts { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 2vw, 1.6rem); margin-top: clamp(2rem, 4vw, 3rem); }
.post {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: var(--shadow-sm);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease), border-color .5s var(--ease);
}
.post:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--gold); }
.post__img { aspect-ratio: 16/10; overflow: hidden; }
.post__img img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease); }
.post:hover .post__img img { transform: scale(1.06); }
.post__body { padding: clamp(1.1rem, 2vw, 1.5rem); display: flex; flex-direction: column; gap: .6rem; flex: 1; }
.post__tag { font-size: .68rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; color: var(--brown); }
.post h3 { font-size: clamp(1.02rem, 1.4vw, 1.18rem); line-height: 1.28; }
.post p { font-size: .89rem; color: var(--text-mut); font-weight: 300; line-height: 1.6; }
.post__go { margin-top: auto; padding-top: .7rem; font-size: .85rem; font-weight: 600; color: var(--brown); display: inline-flex; align-items: center; gap: .4rem; }
.post:hover .post__go { color: var(--gold); }
.post--feat { grid-column: span 3; flex-direction: row; }
.post--feat .post__img { aspect-ratio: auto; flex: 0 0 52%; }
.post--feat .post__body { justify-content: center; padding: clamp(1.5rem, 3vw, 2.6rem); }
.post--feat h3 { font-size: clamp(1.3rem, 2.2vw, 1.9rem); }

/* gallery masonry */
.gal { columns: 3; column-gap: clamp(.8rem, 1.4vw, 1.1rem); margin-top: clamp(2rem, 4vw, 3rem); }
.gal figure {
  break-inside: avoid; margin: 0 0 clamp(.8rem, 1.4vw, 1.1rem);
  border-radius: var(--r-md); overflow: hidden; position: relative;
  box-shadow: var(--shadow-sm); cursor: zoom-in;
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}
.gal figure:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.gal img { width: 100%; height: auto; display: block; }
/* The captions are derived from image filenames ("Img 103", "Pictures of jobs
   641"), so surfacing them on hover exposed the file names rather than saying
   anything useful. Kept in the markup for screen readers and the alt/lightbox
   text; just not painted over the photo. */
.gal figcaption {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

/* gallery filter chips */
.gfilter { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; margin-top: 1.8rem; }
.gfilter button {
  font-size: .84rem; font-weight: 500; padding: .5rem 1.1rem;
  border: 1px solid var(--line-2); border-radius: var(--r-pill);
  background: var(--surface); color: var(--text-mut); cursor: pointer;
  transition: all .35s var(--ease);
}
.gfilter button:hover { border-color: var(--brown); color: var(--brown); }
.gfilter button.is-on { background: var(--brown); border-color: var(--brown); color: var(--white); }

/* lightbox */
.lbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(46,39,37,.94);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  display: grid; place-items: center; padding: 3.5rem 1.2rem;
  opacity: 0; visibility: hidden; transition: opacity .35s var(--ease), visibility .35s;
}
.lbox.is-open { opacity: 1; visibility: visible; }
.lbox img { max-width: 100%; max-height: 82vh; border-radius: var(--r-md); }
.lbox__cap { color: var(--on-dark); font-size: .9rem; margin-top: .9rem; text-align: center; }
.lbox__x, .lbox__p, .lbox__n {
  position: absolute; width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid rgba(248,244,242,.25); background: rgba(46,39,37,.6);
  color: var(--on-dark); cursor: pointer; display: grid; place-items: center;
  transition: all .3s var(--ease);
}
.lbox__x:hover, .lbox__p:hover, .lbox__n:hover { background: var(--gold); color: var(--ink); border-color: var(--gold); }
.lbox__x { top: 1.2rem; right: 1.2rem; }
.lbox__p { left: 1.2rem; top: 50%; transform: translateY(-50%); }
.lbox__n { right: 1.2rem; top: 50%; transform: translateY(-50%); }
.lbox svg { width: 20px; height: 20px; }

/* review grid (reviews page — masonry, unlike the homepage slider) */
.revgrid { columns: 3; column-gap: clamp(.9rem, 1.6vw, 1.2rem); margin-top: clamp(2rem, 4vw, 3rem); }
.revgrid .rcard { break-inside: avoid; margin: 0 0 clamp(.9rem, 1.6vw, 1.2rem); flex: none; width: auto; display: flex; }

/* stat band */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(.9rem, 1.6vw, 1.2rem); margin-top: clamp(2rem, 4vw, 3rem); }
.stat {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.2rem, 2.2vw, 1.8rem);
  box-shadow: var(--shadow-sm);
}
.stat .n { font-size: clamp(1.7rem, 3vw, 2.5rem); font-weight: 600; color: var(--brown); letter-spacing: -.03em; line-height: 1; }
.stat .l { font-size: .86rem; color: var(--text-mut); font-weight: 300; margin-top: .5rem; }

/* numbered process steps */
.steps { display: grid; gap: clamp(.9rem, 1.6vw, 1.2rem); margin-top: clamp(2rem, 4vw, 3rem); }
/* Short steps (a title and one sentence) stacked in a single column made the
   build process 1366px tall. Lay them out in a grid instead so the whole
   process is visible without a long scroll. Steps that carry a <ul> of
   sub-points stay full width, since they are far too tall to sit side by side. */
.steps--grid { grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); }
.step {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.3rem, 2.4vw, 2rem);
  display: grid; grid-template-columns: auto 1fr; gap: clamp(1rem, 2.4vw, 2rem);
  align-items: start; box-shadow: var(--shadow-sm);
  transition: border-color .45s var(--ease), transform .45s var(--ease);
}
.step:hover { border-color: var(--gold); transform: translateY(-2px); }
.step__n {
  width: 46px; height: 46px; flex: none; border-radius: 50%;
  background: var(--brown); color: var(--white);
  display: grid; place-items: center; font-weight: 600; font-size: .95rem;
}
.step h3 { margin-bottom: .5rem; }
.step ul { display: grid; gap: .5rem; margin-top: .7rem; }
.step li { display: flex; gap: .75rem; font-size: .93rem; color: var(--text-mut); font-weight: 300; line-height: 1.6; }
.step li::before { content: ""; flex: none; width: 5px; height: 5px; margin-top: .6rem; border-radius: 50%; background: var(--gold); }

/* range rows */
.ranges { display: grid; gap: .5rem; margin-top: clamp(1.6rem, 3vw, 2.4rem); }
.range {
  display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: center;
  padding: .95rem 1.3rem; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--line);
}
.range__k { font-weight: 500; font-size: .96rem; }
.range__v { font-size: .9rem; color: var(--brown); font-weight: 600; white-space: nowrap; }

/* two-up cards */
.duo { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1rem, 2vw, 1.6rem); margin-top: clamp(2rem, 4vw, 3rem); }
.duo h3 { margin-bottom: .8rem; }
.duo ul { display: grid; gap: .55rem; }
.duo li { display: flex; gap: .75rem; font-size: .93rem; color: var(--text-mut); font-weight: 300; line-height: 1.6; }
.duo li::before { content: ""; flex: none; width: 5px; height: 5px; margin-top: .6rem; border-radius: 50%; background: var(--gold); }
.acard--dark li { color: var(--on-dark-mut); }

/* service cards grid */
.scards { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 2vw, 1.5rem); margin-top: clamp(2rem, 4vw, 3rem); }
.scard {
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: var(--r-md); min-height: 250px;
  display: flex; align-items: flex-end; padding: clamp(1.2rem, 2vw, 1.6rem);
  box-shadow: var(--shadow-sm);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}
.scard:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.scard img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; filter: brightness(.68); transition: transform 1s var(--ease); }
.scard:hover img { transform: scale(1.06); }
.scard::after { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, rgba(46,39,37,.94), rgba(46,39,37,.16)); }
/* these cards carry a full paragraph over the photo, not just a label, so the
   bottom-weighted gradient alone leaves mid-card text low-contrast. Darken the
   whole tile and lean the photo back to a textured backdrop. */
.scard--copy::after { background: linear-gradient(to top, rgba(46,39,37,.96) 12%, rgba(46,39,37,.88) 55%, rgba(46,39,37,.78) 100%); }
.scard--copy img { filter: brightness(.5) saturate(.9); }
/* ---------- feature list: "Label - description" bullets as cards ----------
   Renders a long verbatim bullet list as a readable grid instead of a wall of
   text. The em-dash split is presentational only; the words are untouched. */
.flist { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: clamp(.8rem, 1.5vw, 1.1rem); margin-top: clamp(1.8rem, 3vw, 2.4rem); list-style: none; padding: 0; }
.flist li {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.1rem, 1.8vw, 1.4rem);
  display: flex; flex-direction: column; gap: .4rem;
  transition: border-color .45s var(--ease), transform .45s var(--ease), box-shadow .45s var(--ease);
}
.flist li:hover { border-color: var(--gold); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.flist b { font-size: .97rem; font-weight: 600; color: var(--ink); letter-spacing: -.01em; }
.flist span { font-size: .88rem; font-weight: 300; color: var(--text-mut); line-height: 1.6; }
/* compact variant for short credential bullets with no description */
.flist--tight li { flex-direction: row; align-items: center; gap: .7rem; }
/* the closing thought that follows a full-width card grid */
.flist__after { margin-top: clamp(1.4rem, 2.4vw, 2rem); max-width: 74ch; }
.flist--tight li::before {
  content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: var(--gold);
}
/* Credentials sitting in one column of a .split, not across the full wrap.
   .flist's auto-fit floor is 270px, which inside a ~540px column still only
   fits one card per row, so each bullet sat in a card with half its width
   empty. Stacked rows with tighter padding read as a list again rather than
   as five wide, mostly-empty tiles. */
.gwhy .flist { grid-template-columns: 1fr; gap: .5rem; margin-top: clamp(1.4rem, 2.4vw, 1.9rem); }
.gwhy .flist li { padding: .72rem 1rem; }
.gwhy .flist span { font-size: .9rem; }


/* copy cards align to the TOP so headings line up across the row; the plain
   image tiles keep their bottom-anchored label. Padding leaves room for the
   absolutely-positioned index number. */
.scard--copy { align-items: flex-start; padding-top: clamp(3.6rem, 5.4vw, 4.6rem); }
.scard h3 { color: var(--on-dark); }
.scard p { color: rgba(248,244,242,.84); font-size: .88rem; font-weight: 300; margin-top: .35rem; }
/* numbered index + body wrapper: these cards carry ~400 chars of verbatim copy,
   so they need more height than the short image tiles elsewhere on the site. */
.scard { min-height: clamp(300px, 26vw, 380px); }
.scard__body { position: relative; z-index: 1; }
.scard__n {
  position: absolute; top: clamp(1rem, 1.8vw, 1.4rem); left: clamp(1.2rem, 2vw, 1.6rem);
  z-index: 1; font-family: var(--font-d, inherit);
  font-size: clamp(1.5rem, 2.4vw, 2rem); font-weight: 600; line-height: 1;
  color: var(--gold); letter-spacing: -.02em;
}
.scard h3 { font-size: clamp(1.05rem, 1.5vw, 1.25rem); line-height: 1.25; }

@media (max-width: 1080px) {
  .artgrid { grid-template-columns: 1fr; }
  .aside { position: static; grid-template-columns: 1fr 1fr; }
  .posts { grid-template-columns: 1fr 1fr; }
  .post--feat { grid-column: span 2; flex-direction: column; }
  .post--feat .post__img { aspect-ratio: 16/10; flex: none; }
  .gal, .revgrid { columns: 2; }
  .stats { grid-template-columns: 1fr 1fr; }
  .scards { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
  .posts { grid-template-columns: 1fr; }
  .post--feat { grid-column: span 1; }
  .gal, .revgrid { columns: 1; }
  .stats { grid-template-columns: 1fr 1fr; }
  .aside { grid-template-columns: 1fr; }
  .duo { grid-template-columns: 1fr; }
  .scards { grid-template-columns: 1fr; }
  .step { grid-template-columns: 1fr; gap: .9rem; }
  /* stack range rows and let long values wrap instead of forcing width */
  .range { grid-template-columns: 1fr; gap: .3rem; }
  .range__v { white-space: normal; }
}

/* ==========================================================================
   SHOWCASE — project stories, service and location pages
   ========================================================================== */

/* ---------- editorial hero: copy left, framed photo right ---------- */
.shero {
  position: relative; background: var(--ink); color: var(--on-dark);
  padding: clamp(168px, 21vh, 220px) 0 clamp(56px, 8vw, 92px);
  overflow: hidden;
}
/* ---------- full-bleed hero background ----------
   A blurred, heavily-scrimmed project photo behind the hero. It is atmosphere,
   not subject matter -- the sharp framed photo beside the headline is still the
   thing you look at -- so a 1280px source is plenty at this blur. */
.shero__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.shero__bg img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* scale up so the blur has no soft edge at the viewport boundary */
  transform: scale(1.06);
  filter: blur(4px) saturate(.95) brightness(.82);
}
/* ink scrim: keeps body copy at full contrast over any photo, and fades the
   right-hand side so the framed image reads as the focal point */
.shero__bg::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgba(46,39,37,.90) 0%, rgba(46,39,37,.74) 42%, rgba(46,39,37,.42) 100%),
    linear-gradient(to bottom, rgba(46,39,37,.52) 0%, rgba(46,39,37,.20) 42%, rgba(46,39,37,.66) 100%);
}
@media (max-width: 900px) {
  /* single column: text sits over the whole width, so scrim evenly */
  .shero__bg::after { background: linear-gradient(to bottom, rgba(46,39,37,.86), rgba(46,39,37,.9)); }
}
/* long project titles need a smaller display size than the homepage hero */
.shero h1.display { font-size: clamp(2rem, 3.4vw, 3rem); }
.shero::before {
  content: ""; position: absolute; z-index: 0;
  width: 620px; height: 620px; right: -180px; top: -200px;
  background: radial-gradient(circle, rgba(222,163,73,.16), transparent 68%);
  pointer-events: none;
}
.shero__grid {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}
.shero h1 { color: var(--on-dark); }
.shero .lede { color: rgba(248,244,242,.86); margin-top: 1.2rem; max-width: 56ch; }
.shero__actions { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 2rem; }
.shero__frame {
  position: relative; border-radius: var(--r-lg); overflow: hidden;
  aspect-ratio: 5/4; box-shadow: 0 34px 80px rgba(0,0,0,.5);
}
.shero__frame img { width: 100%; height: 100%; object-fit: cover; }
/* A portrait photo in the 5:4 frame loses ~32% of its height. The Faribault
   garage sits low in its frame, so a centre crop cut through the doors and
   spent the space on sky. Measured against the real crops: 72% keeps all three
   bays, the roofline and the dusk sky. */
.shero__frame img.pos-low { object-position: 50% 72%; }
/* floating spec chip over the photo */
.shero__chip {
  position: absolute; left: 1.1rem; bottom: 1.1rem;
  background: rgba(46,39,37,.82);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(248,244,242,.18);
  border-radius: var(--r-pill); padding: .5rem 1.05rem;
  font-size: .78rem; font-weight: 500; color: var(--on-dark);
}

/* ---------- key facts strip ---------- */
.facts {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(.8rem, 1.5vw, 1.2rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}
/* The track count follows the item count. With the four-column track left in
   place, a three-item bar filled three quarters of the width and left an
   empty column on the right instead of spanning the wrap.
   Scoped above the 1080 breakpoint on purpose: :has() outweighs the plain
   .facts selector, so unscoped these beat the two-column mobile rule and a
   three-item bar stayed three across at 700. */
@media (min-width: 1081px) {
  .facts:has(> .fact:nth-child(3):last-child) { grid-template-columns: repeat(3, 1fr); }
  .facts:has(> .fact:nth-child(2):last-child) { grid-template-columns: repeat(2, 1fr); }
}
.fact {
  border-left: 2px solid var(--gold);
  padding: .35rem 0 .35rem 1.1rem;
}
.fact .k { font-size: .72rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; color: var(--text-soft); }
.fact .v { font-size: clamp(.98rem, 1.3vw, 1.12rem); font-weight: 500; margin-top: .35rem; line-height: 1.35; }
.sect--dark .fact .k { color: var(--on-dark-mut); }
.sect--dark .fact .v { color: var(--on-dark); }

/* ==========================================================================
   SHOWCASE GALLERY — rotating card stack
   The active photo sits front and centre; its neighbours are tucked BEHIND it,
   inset and overlapped, so the arrows rotate the stack rather than sliding a
   filmstrip. Cards are absolutely positioned and driven by --off (distance
   from the active card), so depth ordering is real z-index, not fake gaps.
   ========================================================================== */
.show {
  position: relative;
  margin-top: clamp(2rem, 4vw, 3.2rem);
  width: 100vw; max-width: 100vw;
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  overflow: hidden;
}
.show__vp {
  position: relative;
  height: clamp(230px, 34vw, 460px);
  perspective: 1600px;
}
.show__track { position: absolute; inset: 0; transform-style: preserve-3d; }

.show__i {
  position: absolute; top: 50%; left: 50%;
  width: clamp(280px, 52vw, 660px);
  aspect-ratio: 16 / 10;
  margin: 0;
  overflow: hidden; isolation: isolate;
  border-radius: var(--r-lg);
  background: var(--surface-2);
  cursor: pointer;
  /* --off is set by JS: 0 = front, ±1 = first card back, ±2 = further back.
     Each step back shifts sideways, shrinks, and dims. */
  --off: 0;
  --dir: 0;                       /* -1 left, 0 centre, 1 right */
  --dist: 0;                      /* abs(--off) */
  transform:
    translate(-50%, -50%)
    translateX(calc(var(--dir) * clamp(190px, 27vw, 350px)))
    scale(calc(1 - var(--dist) * 0.14));
  opacity: 1;
  z-index: calc(10 - var(--dist));
  box-shadow: 0 18px 50px rgba(46, 39, 37, .28);
  transition: transform .7s cubic-bezier(.22, .61, .36, 1),
              opacity .7s cubic-bezier(.22, .61, .36, 1),
              box-shadow .7s var(--ease);
}
/* cards deeper than the first neighbour are hidden so the stack stays clean */
.show__i[data-depth="hidden"] { opacity: 0; pointer-events: none; }
/* the stack positions itself entirely with transform, so the scroll-reveal
   helper (.rv.in { transform: none }) must never win here */
.show__i.rv, .show__i.rv.in { opacity: 1; }

.show__i.is-active {
  cursor: zoom-in;
  z-index: 10;
  box-shadow: 0 30px 70px rgba(46, 39, 37, .38);
}
.show__i img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 1.1s var(--ease);
}
.show__i.is-active:hover img { transform: scale(1.04); }

/* back cards are dimmed and slightly desaturated so the front one pops */
.show__i::before {
  content: ""; position: absolute; inset: 0; z-index: 3;
  background: rgba(46, 39, 37, .42);
  opacity: 1; transition: opacity .7s var(--ease);
  pointer-events: none;
}
.show__i.is-active::before { opacity: 0; }

/* caption gradient + text, front card only */
.show__i::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to top, rgba(46,39,37,.86) 0%, rgba(46,39,37,.12) 55%, transparent 100%);
  opacity: 0; transition: opacity .5s var(--ease);
}
.show__i.is-active::after { opacity: 1; }
.show__cap {
  position: absolute; inset: auto 0 0 0; z-index: 4;
  padding: clamp(1rem, 2vw, 1.6rem);
  color: var(--on-dark); font-size: clamp(.85rem, 1.4vw, 1rem);
  font-weight: 500; line-height: 1.35;
  opacity: 0; transform: translateY(10px);
  transition: opacity .5s var(--ease) .12s, transform .5s var(--ease) .12s;
}
.show__i.is-active .show__cap { opacity: 1; transform: none; }
.show__zoom {
  position: absolute; right: .9rem; top: .9rem; z-index: 4;
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(248,244,242,.92); color: var(--ink);
  display: grid; place-items: center;
  opacity: 0; transform: scale(.85);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.show__i.is-active:hover .show__zoom { opacity: 1; transform: none; }
.show__zoom svg { width: 16px; height: 16px; }

/* ---------- arrows: sit above the stack, over the back cards ---------- */
.show__nav {
  position: absolute; top: 50%; z-index: 20;
  transform: translateY(-50%);
  width: clamp(46px, 4.4vw, 62px); aspect-ratio: 1;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(248,244,242,.94); color: var(--ink);
  display: grid; place-items: center;
  box-shadow: 0 6px 24px rgba(46,39,37,.3);
  transition: background .3s var(--ease), transform .3s var(--ease);
}
.show__nav:hover { background: #fff; transform: translateY(-50%) scale(1.07); }
.show__nav:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }
.show__nav svg { width: 42%; height: 42%; }
/* pulled inward so they overlay the seam between front and back cards */
.show__nav--prev { left: calc(50% - clamp(160px, 23vw, 300px)); }
.show__nav--next { right: calc(50% - clamp(160px, 23vw, 300px)); }

@media (max-width: 720px) {
  .show__i {
    width: min(78vw, 420px);
    transform:
      translate(-50%, -50%)
      translateX(calc(var(--dir) * 42vw))
      scale(calc(1 - var(--dist) * 0.12));
  }
  .show__nav--prev { left: .5rem; }
  .show__nav--next { right: .5rem; }
}
@media (prefers-reduced-motion: reduce) {
  .show__i { transition-duration: .01ms; }
}

/* ==========================================================================
   CITY HERO — full-bleed photo, centred headline, local proof bar
   Deliberately different from .shero (two-column with a framed photo) so a
   location page never reads as a service page.
   ========================================================================== */
.chero { position: relative; color: var(--on-dark); overflow: hidden; isolation: isolate; }
.chero__media { position: absolute; inset: 0; z-index: -2; }
.chero__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.chero__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to bottom, rgba(46,39,37,.86) 0%, rgba(46,39,37,.55) 34%,
                    rgba(46,39,37,.66) 66%, rgba(46,39,37,.94) 100%),
    radial-gradient(ellipse at 50% 46%, rgba(46,39,37,.16) 0%, rgba(46,39,37,.72) 78%);
}
.chero__in {
  position: relative; text-align: center;
  /* widened from 900px: the longest intro here is 528 characters, which at
     the old width could not reach four lines without an unreadable measure */
  max-width: 1120px; margin-inline: auto;
  padding-block: clamp(190px, 25vh, 270px) clamp(52px, 7vw, 84px);
}
.chero .crumb { justify-content: center; }
/* The h1 held two lines at 1440 but dropped to one by 1200, so the hero
   changed shape across the range. Capping its measure keeps the break in the
   same place: the longest of these headings is 38 characters. */
/* Two lines for every heading, from 32 to 50 characters. A single max-width
   cannot do it: 22ch pushed the longest to three lines, 26ch let the shortest
   collapse to one. The break is placed in the markup instead, before the
   "in <City>, MN" phrase, and this just stops the box being wider than needed. */
.chero h1.display { font-size: clamp(2.1rem, 4vw, 3.4rem);
  max-width: 30ch; margin-inline: auto; }
.chero h1.display .brk { display: block; }
/* The lede was capped at 62ch inside a 900px container, so the longer intros
   stacked to 7-8 lines. Widening the measure to the container brings the
   longest (528 characters) down to four lines. */
.chero .lede {
  /* The longest intro here is 528 characters. Anything narrower than the
     container pushes it to five lines, so the measure is the container. */
  color: rgba(248,244,242,.9); margin: 1.2rem auto 0; max-width: none;
  /* a touch smaller than the body .lede so the long intros land on four
     lines without the line length becoming unreadable */
  font-size: clamp(.95rem, 1.05vw, 1.02rem);
}
@media (max-width: 900px) {
  .chero h1.display { max-width: none; }
  .chero .lede { max-width: 62ch; }
}
.chero__actions { display: flex; flex-wrap: wrap; gap: .7rem; justify-content: center; margin-top: 2rem; }
/* caption naming the real location of the hero photo */
/* sits just ABOVE the stat bar, not over it -- the bar is a separate block at
   the foot of the hero, so an absolutely-positioned caption would overlap it */
.chero__cap {
  position: relative; z-index: 1;
  text-align: right;
  padding: 0 clamp(1rem, 3vw, 2rem) clamp(.7rem, 1.4vw, 1rem);
  font-size: .76rem; letter-spacing: .04em;
  color: rgba(248,244,242,.62);
}
/* local proof bar */
.chero__bar {
  position: relative; border-top: 1px solid rgba(248,244,242,.16);
  background: rgba(46,39,37,.55);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.chero__bar .wrap {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(.8rem, 2vw, 1.6rem);
  padding-block: clamp(1rem, 2vw, 1.4rem);
}
.chero__stat { text-align: center; }
.chero__stat .k {
  display: block; font-size: clamp(1.05rem, 1.7vw, 1.4rem); font-weight: 600;
  color: var(--gold); line-height: 1.15;
}
.chero__stat .v {
  display: block; margin-top: .2rem; font-size: .76rem; font-weight: 300;
  letter-spacing: .05em; text-transform: uppercase;
  color: rgba(248,244,242,.7);
}
@media (max-width: 720px) {
  .chero__bar .wrap { grid-template-columns: repeat(2, 1fr); row-gap: 1.1rem; }
  .chero__cap { text-align: center; padding-inline: 1rem; }
}

/* ==========================================================================
   404 — centred message over the hero backdrop, then onward links
   ========================================================================== */
.nf { text-align: center; padding-block: clamp(180px, 24vh, 250px) clamp(64px, 9vw, 110px); }
.nf__in { position: relative; z-index: 1; max-width: 660px; margin-inline: auto; }
.nf__in .eyebrow { justify-content: center; }
.nf__in .eyebrow::before { display: none; }
/* the eyebrow sits on a photo here, not a flat surface, so it needs the
   brighter gold rather than the muted brown used on light sections */
.nf__in .eyebrow { color: var(--gold); }
.nf__in .lede { margin-inline: auto; color: rgba(248,244,242,.88); }
.nf .shero__actions { justify-content: center; }
.nf__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: clamp(.6rem, 1.2vw, .9rem); margin-top: clamp(2rem, 4vw, 3rem);
}
.nf__link {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: clamp(.95rem, 1.6vw, 1.15rem) clamp(1.1rem, 1.8vw, 1.35rem);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); color: var(--text);
  font-size: .93rem; font-weight: 500;
  transition: border-color .4s var(--ease), transform .4s var(--ease),
              box-shadow .4s var(--ease), color .4s var(--ease);
}
.nf__link .ico { color: var(--brown); flex: none; }
.nf__link:hover {
  border-color: var(--gold); color: var(--ink);
  transform: translateY(-2px); box-shadow: var(--shadow-md);
}

/* ---------- before / after slider ---------- */
.ba {
  position: relative; border-radius: var(--r-lg); overflow: hidden;
  aspect-ratio: 16/10; box-shadow: var(--shadow-lg);
  margin-top: clamp(1.6rem, 3vw, 2.4rem);
  user-select: none; touch-action: pan-y;
}
.ba img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ba__after { clip-path: inset(0 0 0 50%); }
.ba__line {
  position: absolute; top: 0; bottom: 0; left: 50%; width: 2px;
  background: var(--cream); transform: translateX(-1px); pointer-events: none;
}
.ba__grip {
  position: absolute; top: 50%; left: 50%; z-index: 3;
  width: 44px; height: 44px; margin: -22px 0 0 -22px;
  border-radius: 50%; background: var(--cream); color: var(--ink);
  display: grid; place-items: center; cursor: ew-resize;
  box-shadow: 0 6px 20px rgba(0,0,0,.35);
}
.ba__grip svg { width: 20px; height: 20px; }
.ba__tag {
  position: absolute; top: 1rem; z-index: 2;
  background: rgba(46,39,37,.78); color: var(--on-dark);
  border-radius: var(--r-pill); padding: .34rem .85rem;
  font-size: .72rem; font-weight: 600; letter-spacing: .11em; text-transform: uppercase;
  pointer-events: none;
}
.ba__tag--b { left: 1rem; }
.ba__tag--a { right: 1rem; }

/* ==========================================================================
   PROJECT TESTIMONIAL — photo panel beside the client's words
   These three project stories each carry ONE long verbatim review (up to 1,229
   characters). Set as a single wide slab it reads as a wall of text, so pair it
   with a project photo and drop the body to a comfortable reading size.
   ========================================================================== */
.tquote {
  /* <figure> and <blockquote> both carry a UA margin (40px each side); without
     resetting it the card is inset from its siblings and the text column is
     crushed on a phone. */
  margin: 0;
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--ink); color: var(--on-dark);
  display: grid;
  /* the photo is context, the words are the point -- but the photo still needs
     enough width to read as a photo rather than a stripe. */
  grid-template-columns: minmax(300px, .78fr) 1.22fr;
  box-shadow: var(--shadow-lg);
}
/* The source photos are landscape (4:3 and 16:9). Stretching one to match a
   1,250-character quote produced a 0.39-ratio letterbox that cropped away ~70%
   of the frame. Pin the panel to a portrait ratio instead and let it sit at the
   top of a taller card: the photo keeps its shape no matter how long the review. */
.tquote__media {
  position: relative;
  align-self: stretch;
  /* a floor, not a fixed height: a short review must not be padded out just to
     match the photo, and a long one must not stretch it into a stripe */
  min-height: min(78%, 420px);
  aspect-ratio: 4 / 5;
}
.tquote__media img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
/* Fade the photo into the quote panel so the two halves read as one card.
   The fade must finish INSIDE the media column: the text column starts where
   the photo ends, and type sitting over a half-lit photo is unreadable. */
.tquote__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to right,
    rgba(46,39,37,0) 0%, rgba(46,39,37,0) 55%, rgba(46,39,37,.55) 82%, var(--ink) 100%);
}
.tquote__body {
  margin: 0;
  position: relative; z-index: 1;
  padding: clamp(1.9rem, 3.2vw, 3rem);
  display: flex; flex-direction: column; justify-content: center;
}
/* warm glow behind the text, echoing the other dark blocks */
.tquote__body::before {
  content: ""; position: absolute; z-index: -1;
  width: 460px; height: 460px; right: -190px; top: -200px;
  background: radial-gradient(circle, rgba(222,163,73,.20), transparent 68%);
}
.tquote__top {
  display: flex; align-items: center; gap: .9rem;
  margin-bottom: 1rem;
}
.tquote__stars { color: var(--gold); letter-spacing: .12em; font-size: .95rem; }
.tquote__g { width: 18px; height: 18px; flex: none; opacity: .9; }
.tquote__mark {
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(2.6rem, 4.2vw, 3.6rem); line-height: .8; color: var(--gold);
  opacity: .5; margin-bottom: .15rem;
}
/* smaller again than the first pass: at ~15.5px a 1,250-character review still
   pushed the card past 700px and starved the photo of width */
.tquote p {
  font-size: clamp(.88rem, .95vw, .95rem); font-weight: 300;
  line-height: 1.72; color: rgba(248,244,242,.92); margin: 0;
}
/* Long reviews (Rick K's runs to ~1,250 chars) set in two columns so the card
   stays short and the photo keeps a generous share of the width. The threshold
   is 1000px rather than 1100 so the tablet range benefits too. */
.tquote--long .tquote__body { padding-block: clamp(1.8rem, 2.6vw, 2.4rem); }
@media (min-width: 1000px) {
  .tquote--long .tquote__body > p {
    /* column-count + a height cap silently CLIPS: multicol overflows sideways
       into a third column that overflow:hidden then hides. Never cap the
       height of a multicol box holding copy that must stay complete.
       column-width lets the browser choose the count and grow instead. */
    columns: 2;
    column-gap: clamp(1.3rem, 2.2vw, 2rem);
  }
}
.tquote__who {
  display: flex; align-items: center; gap: .85rem;
  margin-top: clamp(1.3rem, 2.2vw, 1.7rem);
  padding-top: clamp(1rem, 1.8vw, 1.4rem);
  border-top: 1px solid rgba(248,244,242,.16);
}
.tquote__av {
  width: 44px; height: 44px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-weight: 600; color: #fff;
  font-size: 1.02rem;
}
.tquote__nm { font-weight: 500; font-size: .94rem; }
.tquote__src { font-size: .76rem; color: var(--on-dark-mut); margin-top: .1rem; }
.tquote__verified {
  margin-left: auto; flex: none;
  font-size: .7rem; letter-spacing: .06em; text-transform: uppercase;
  color: rgba(248,244,242,.6);
  border: 1px solid rgba(248,244,242,.2);
  border-radius: var(--r-pill); padding: .32rem .68rem;
}
@media (max-width: 900px) {
  .tquote { grid-template-columns: 1fr; }
  /* stacked, the photo spans the full card width, so a landscape ratio suits it
     -- but 16:9 across 810px is 456px tall, which pushed the card past its
     two-column desktop height. 21:9 shows the same scene in less vertical space. */
  /* The page's own project photos are 900px wide, so a full-bleed 810px panel
     renders them at only 1.11x. Cap the panel and centre it: the photo renders
     nearer 2x and the card gets shorter too. */
  .tquote__media {
    aspect-ratio: 21 / 9; min-height: 0;
    width: min(100%, 560px); margin-inline: auto;
  }
  .tquote__media::after {
    background: linear-gradient(to bottom, rgba(46,39,37,0) 0%, rgba(46,39,37,.10) 55%, rgba(46,39,37,.9) 100%);
  }
  /* the row still fits at this width, so keep the pill on the right edge;
     only let it drop to its own line on a genuinely narrow card */
  .tquote__who { flex-wrap: wrap; }
}
@media (max-width: 560px) {
  /* the card is only ~350px wide here; the desktop padding would leave the
     text column under 200px, so tighten it and drop the type a touch */
  .tquote__body { padding: clamp(1.2rem, 5vw, 1.6rem); }
  .tquote p { font-size: .9rem; line-height: 1.68; }
  .tquote__mark { font-size: 2.4rem; }
  .tquote__media { aspect-ratio: 3 / 2; }
  .tquote__verified { margin-left: 0; }
}

/* ---------- pull quote / testimonial ---------- */
.pquote {
  background: var(--ink); color: var(--on-dark);
  border-radius: var(--r-lg); padding: clamp(1.8rem, 4vw, 3.4rem);
  position: relative; isolation: isolate; overflow: hidden;
}
.pquote::before {
  content: ""; position: absolute; z-index: -1;
  width: 420px; height: 420px; left: -150px; bottom: -180px;
  background: radial-gradient(circle, rgba(222,163,73,.2), transparent 68%);
}
.pquote__mark { font-size: 3.2rem; line-height: 1; color: var(--gold); font-weight: 600; }
.pquote p {
  font-size: clamp(1.05rem, 1.7vw, 1.42rem); font-weight: 300;
  line-height: 1.6; color: var(--on-dark); margin-top: .6rem; max-width: 62ch;
}
.pquote__who { display: flex; align-items: center; gap: .8rem; margin-top: 1.6rem; }
.pquote__av {
  width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; font-weight: 600; color: #fff; flex: none;
}
.pquote__nm { font-weight: 500; font-size: .95rem; }
.pquote__src { font-size: .78rem; color: var(--on-dark-mut); }
.pquote__stars { color: var(--gold); letter-spacing: .1em; font-size: .95rem; }

/* ---------- inline CTA banner (Habitate-style) ---------- */
.ribbon {
  background: var(--ink); color: var(--on-dark);
  border-radius: var(--r-lg);
  padding: clamp(1.5rem, 3vw, 2.4rem) clamp(1.5rem, 3.4vw, 3rem);
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
  margin-top: clamp(2rem, 4vw, 3rem);
}
.ribbon h3 { color: var(--on-dark); font-size: clamp(1.15rem, 2vw, 1.65rem); }
.ribbon p { color: var(--on-dark-mut); font-size: .92rem; font-weight: 300; margin-top: .35rem; }

/* ---------- service list (deck page process) ---------- */
.slist { display: grid; gap: clamp(.8rem, 1.4vw, 1.1rem); margin-top: clamp(2rem, 4vw, 3rem); }
.sitem {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.3rem, 2.4vw, 2rem);
  display: grid; grid-template-columns: auto 1fr; gap: clamp(1rem, 2.2vw, 1.8rem);
  align-items: start; box-shadow: var(--shadow-sm);
  transition: border-color .45s var(--ease), transform .45s var(--ease);
}
.sitem:hover { border-color: var(--gold); transform: translateY(-2px); }
.sitem__n {
  font-size: clamp(1.5rem, 2.6vw, 2.1rem); font-weight: 600; line-height: 1;
  color: transparent; -webkit-text-stroke: 1.3px var(--line-2); letter-spacing: -.04em;
}
.sitem:hover .sitem__n { -webkit-text-stroke-color: var(--gold); }
.sitem h3 { margin-bottom: .45rem; }
/* A card whose source copy carries no subheading (the deck/porch project story
   has none) starts with the paragraph, whose cap-height sits lower than an
   h3's. Nudge the numeral down so the two still align optically. */
.sitem > div > p:first-child { margin-top: .15rem; }
.sitem p { color: var(--text-mut); font-weight: 300; font-size: .95rem; line-height: 1.7; }

/* ---------- nearby city chips ---------- */
.nearby { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1.6rem; }
.nearby a {
  font-size: .82rem; padding: .45rem .95rem;
  border: 1px solid var(--line-2); border-radius: var(--r-pill);
  color: var(--text-mut); background: var(--surface);
  transition: all .35s var(--ease);
}
.nearby a:hover { border-color: var(--brown); background: var(--brown); color: var(--white); }

@media (max-width: 1080px) {
  .shero__grid { grid-template-columns: 1fr; gap: 2.2rem; }
  .facts { grid-template-columns: 1fr 1fr; }
  .ribbon { flex-direction: column; align-items: flex-start; }
  .sitem { grid-template-columns: 1fr; gap: .6rem; }
}

/* ==========================================================================
   NAV DROPDOWNS — mirrors the live site's menu structure
   About ▼ ( … Areas We Work In ▼ 22 cities … )  ·  Our Services ▼
   ========================================================================== */

.nav li { position: relative; list-style: none; }
.nav > ul { display: flex; align-items: center; gap: .15rem; margin: 0; padding: 0; }

/* parent item with a submenu */
.nav .has > a { display: inline-flex; align-items: center; gap: .38rem; }
.nav .has > a::after {
  content: ""; flex: none;
  width: 7px; height: 7px; margin-top: -2px;
  border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor;
  transform: rotate(45deg);
  transition: transform .3s var(--ease);
  opacity: .7;
}
.nav .has:hover > a::after,
.nav .has:focus-within > a::after { transform: rotate(225deg) translate(-2px, -2px); }

/* the panel */
.nav .sub {
  position: absolute; top: calc(100% + .55rem); left: 50%;
  transform: translateX(-50%) translateY(-6px);
  min-width: 246px; padding: .45rem; margin: 0;
  background: rgba(255,255,255,.97);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(46,39,37,.08);
  border-radius: 18px;
  box-shadow: 0 18px 46px rgba(46,39,37,.18);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .28s var(--ease), transform .28s var(--ease), visibility .28s;
  z-index: 20;
}
/* hover bridge so the pointer can cross the gap */
.nav .has::after {
  content: ""; position: absolute; left: 0; right: 0;
  top: 100%; height: .7rem;
}
.nav .has:hover > .sub,
.nav .has:focus-within > .sub,
.nav .has.is-open > .sub {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.nav .sub a {
  display: block; white-space: nowrap;
  padding: .58rem .95rem; border-radius: 12px;
  font-size: .875rem; font-weight: 500; color: var(--text-mut);
}
.nav .sub a:hover { background: var(--surface-2); color: var(--text); }
.nav .sub a.is-active { background: var(--brown); color: var(--white); }

/* third level: Areas We Work In — flies out to the side, 2 columns */
.nav .sub .has > a::after { transform: rotate(-45deg); margin-top: 0; }
.nav .sub .has:hover > a::after,
.nav .sub .has:focus-within > a::after { transform: rotate(135deg); }
.nav .sub .sub {
  top: -.45rem; left: calc(100% + .4rem);
  transform: translateX(0) translateY(-6px);
  columns: 2; column-gap: .2rem;
  min-width: 366px;
}
.nav .sub .has:hover > .sub,
.nav .sub .has:focus-within > .sub,
.nav .sub .has.is-open > .sub {
  transform: translateX(0) translateY(0);
}
.nav .sub .has::after { left: 100%; top: 0; bottom: 0; width: .5rem; height: auto; }
.nav .sub .sub li { break-inside: avoid; }

/* keep the flyout on-screen near the right edge */
.nav > ul > li:last-child .sub .sub,
.nav > ul > li:nth-last-child(2) .sub .sub {
  left: auto; right: calc(100% + .4rem);
}

/* ---------- mobile drawer: accordion groups ---------- */
.drawer .dgroup { border-bottom: 1px solid var(--line); }
.drawer .dtoggle {
  width: 100%; background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .8rem 0; text-align: left;
  font-size: 1.35rem; font-weight: 500; color: var(--text);
}
.drawer .dtoggle::after {
  content: ""; flex: none; width: 9px; height: 9px; margin-right: .3rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform .35s var(--ease); opacity: .55;
}
.drawer .dgroup.is-open > .dtoggle::after { transform: rotate(225deg) translate(-3px,-3px); }
/* Child combinators matter: ".is-open .dpanel" also matched the nested Areas
   panel and chevron, so opening About flipped Areas to "open" untouched.
   Plain display toggling replaces the 0fr/1fr grid trick, which WebKit (every
   iPhone browser) fails to re-measure when one panel sits inside another:
   Areas opened to 11px and the city list never appeared. */
.drawer .dpanel { display: none; }
.drawer .dgroup.is-open > .dpanel { display: block; animation: dpanelIn .3s var(--ease); }
@keyframes dpanelIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
/* Block, not inline: inline links ran side by side and their vertical padding
   did not take up line space, so wrapped rows (and the city columns) overlapped. */
.drawer .dpanel a {
  display: block;
  font-size: 1rem; font-weight: 400; color: var(--text-mut);
  padding: .5rem 0 .5rem 1rem; border-bottom: 0;
}
.drawer .dpanel a:hover { color: var(--brown); }
/* city list inside the drawer: two columns to keep it short */
.drawer .dcities { columns: 2; column-gap: 1rem; padding-bottom: .6rem; }
.drawer .dcities a { padding: .42rem 0 .42rem 1rem; font-size: .93rem; break-inside: avoid; }

@media (max-width: 1180px) {
  .nav .sub { min-width: 224px; }
  .nav .sub .sub { min-width: 330px; }
}


/* ==========================================================================
   REMODELING INVESTMENT GUIDE
   The article ran 376 words down one 3364px column with no photography.
   These pieces break it into sections and carry the before/after work.
   ========================================================================== */
.gsplit {
  display: grid; grid-template-columns: 1.02fr .98fr;
  gap: clamp(1.6rem, 3.6vw, 3.4rem);
  /* start, not center: the before/after strips are wide and short (up to
     3.5:1), so centring one against a tall text column left a big gap under
     the photo. */
  align-items: start;
  margin-top: clamp(1.8rem, 3vw, 2.6rem);
}

.gsplit--flip .gsplit__media { order: -1; }
.gsplit__body > * + * { margin-top: 1rem; }
/* a before/after panel is a wide strip: let it size to its own ratio rather
   than being cropped to a portrait frame */
.gsplit__media { margin: 0; }
.gsplit__media img {
  width: 100%; height: auto; display: block;
  border-radius: var(--r-lg); box-shadow: var(--shadow-md);
}
.gsplit__media figcaption {
  margin-top: .7rem; font-size: .82rem; line-height: 1.55;
  color: var(--text-mut); font-weight: 300;
}

/* A gsplit whose media should match the height of the copy beside it, rather
   than sizing to its own aspect ratio. Opt-in, so the captioned before/after
   strips on the guide page keep their natural proportions.
   NOTE: do not add aspect-ratio here -- combined with height:100% the browser
   derives width from height and the media overflows its column. */
.gsplit--even { align-items: stretch; }
.gsplit--even .gsplit__media { align-self: stretch; }
/* the copy is usually shorter than the media it is matched to; centre it so it
   does not hang from the top against a tall photo */
.gsplit--even .gsplit__body {
  display: flex; flex-direction: column; justify-content: center;
}
.gsplit--even .gsplit__media img,
.gsplit--even .gsplit__media video {
  width: 100%; height: 100%; object-fit: cover;
}
/* The TEXT sets the height, not the picture. Without a cap a tall source (the
   porch photo is portrait, 1506x2000) or a short paragraph (garage has one)
   stretched the row to the image's natural proportions and left up to 387px
   of dead space beside the copy. The row is still perfectly symmetrical --
   both columns match -- but it matched at the wrong height. */
/* Both columns end level, and the TEXT sets that height.
   With plain stretch a tall source (the porch photo is portrait, 1506x2000)
   or a short paragraph (garage has one) let the picture set the row instead,
   leaving up to 387px of dead space beside the copy. Capping the grid row and
   letting the photo crop to fill it keeps the two columns equal AND tight. */
/* Both columns end level, and the TEXT sets that height.
   The image is absolutely positioned inside its figure so its intrinsic size
   cannot inflate the grid row: a portrait source (the porch photo is
   1506x2000) or a short paragraph (garage has one) otherwise stretched the row
   to the picture's proportions and left up to 387px of dead space beside the
   copy. The figure keeps a floor so a one-line paragraph does not squash the
   photo into a letterbox. */
.gsplit--even { align-items: stretch; }
.gsplit--even .gsplit__media {
  position: relative;
  align-self: stretch;
  min-height: min(20vw, 300px);
  overflow: hidden;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
}
.gsplit--even .gsplit__media img,
.gsplit--even .gsplit__media video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: 0; box-shadow: none;
}
.gsplit__media--video video {
  width: 100%; height: auto; display: block;
  border-radius: var(--r-lg); box-shadow: var(--shadow-md);
}
/* the two questions the article is built around */
.gquote {
  margin: 1.2rem 0; padding: 1rem 0 1rem 1.3rem;
  border-left: 3px solid var(--gold);
  font-size: clamp(1.1rem, 1.7vw, 1.42rem);
  font-weight: 300; line-height: 1.45; color: var(--ink);
}
.gbul { display: grid; gap: .55rem; margin-top: 1rem; }
.gbul li {
  display: flex; gap: .8rem; align-items: flex-start;
  font-size: .93rem; font-weight: 300; color: var(--text-mut); line-height: 1.6;
}
.gbul li::before {
  content: ""; flex: none; width: 6px; height: 6px; margin-top: .55rem;
  border-radius: 50%; background: var(--gold);
}
.gflist {
  /* six cards: auto-fit packed 4 across and left two holes on row two.
     Three across divides evenly into 3+3. */
  margin-top: 1.3rem;
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 980px) { .gflist { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .gflist { grid-template-columns: 1fr; } }
/* the closing thought before the CTA reads as a centred sign-off */
.gafter--mid { margin-inline: auto; text-align: center; }
.gcta--mid { text-align: center; }
.gafter { margin-top: clamp(1.3rem, 2.2vw, 1.8rem); max-width: 74ch; }

/* the five investment categories, as photo cards */
.gcats {
  /* five cards: auto-fit gave a lonely 4+1 wrap, so pin three across and let
     the last two sit as a balanced second row */
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 1.8vw, 1.5rem);
  margin-top: clamp(1.8rem, 3vw, 2.6rem);
}
.gcat {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden;
  box-shadow: var(--shadow-sm); color: inherit;
  transition: border-color .45s var(--ease), transform .45s var(--ease), box-shadow .45s var(--ease);
}
.gcat:hover { border-color: var(--gold); transform: translateY(-3px); box-shadow: var(--shadow-md); }
.gcat__img { aspect-ratio: 4/3; overflow: hidden; }
.gcat__img img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 1.1s var(--ease); }
.gcat:hover .gcat__img img { transform: scale(1.05); }
.gcat__body { padding: clamp(1rem, 1.8vw, 1.35rem); display: flex; flex-direction: column; flex: 1; }
.gcat__body h3 { font-size: 1.05rem; margin-bottom: .4rem; }
.gcat__body p { font-size: .89rem; font-weight: 300; color: var(--text-mut); line-height: 1.6; }
.gcat__link {
  margin-top: auto; padding-top: .9rem;
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .84rem; font-weight: 500; color: var(--brown);
}
.gcat:hover .gcat__link { color: var(--gold); }

/* A CTA tile filling the sixth slot so the five category cards stop leaving a
   hole. No photo, so it carries its own dark treatment like .scard--cta. */
.gcat--cta {
  background: var(--ink); border-color: var(--ink);
  color: var(--on-dark);
  justify-content: center;
  padding: clamp(1.3rem, 2.4vw, 1.9rem);
}
.gcat--cta:hover { border-color: var(--gold); }
.gcat--cta h3 { color: var(--on-dark); }
.gcat--cta p { color: rgba(248,244,242,.84); font-weight: 300; margin-top: .5rem;
  font-size: .89rem; line-height: 1.6; }
.gcat--cta .btn { margin-top: 1.2rem; align-self: flex-start; }

/* the CTA tile's copy centred in the card rather than sitting at the top */
.gcat--cta-mid .gcat__body {
  flex: 1; display: flex; flex-direction: column; justify-content: center;
}

/* three short blocks that would otherwise stack into a long scroll */
.gtrio {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(1rem, 1.8vw, 1.5rem);
  margin-top: clamp(1.8rem, 3vw, 2.6rem);
  align-items: start;
}
.gcard {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.2rem, 2.2vw, 1.8rem);
  box-shadow: var(--shadow-sm);
}
.gcard h3 { margin-bottom: .6rem; }
.gcard > * + * { margin-top: .85rem; }
.wrapinner { max-width: 860px; }

@media (max-width: 1000px) {
  .gcats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  .gcats { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
  .gsplit { grid-template-columns: 1fr; }
  .gsplit--flip .gsplit__media { order: 0; }
}

.gcta { margin-top: clamp(1.4rem, 2.4vw, 2rem); }

/* A section heading that sits over one column of the split below it rather
   than spanning the wrap. Mirrors .gsplit's own 1.02fr/.98fr track sizing and
   gap so the heading's left edge lands exactly on the text column's, instead
   of a hand-picked max-width that drifts as the viewport changes. */
.ghead--col {
  max-width: none;
  display: grid;
  grid-template-columns: 1.02fr .98fr;
  gap: clamp(1.6rem, 3.6vw, 3.4rem);
}
.ghead--col > * { grid-column: 2; min-width: 0; }
@media (max-width: 860px) {
  .ghead--col { display: block; }
}

/* Heading carried INSIDE the split's text column so the photo spans the whole
   column (eyebrow and headline included) instead of starting level with the
   first paragraph. The eyebrow's own margin-bottom and the column's
   `* + *` top margin were stacking into a ~70px gap under the label. */
.gsplit--head .gsplit__body > .eyebrow { margin-bottom: 0; }
.gsplit--head .gsplit__body > .eyebrow + .h2 { margin-top: .55rem; }
.gsplit--head .gsplit__body > .h2 + * { margin-top: 1.25rem; }

/* Value & Return: a full-width video under the heading, then the prose in two
   balanced columns. Real columns (not multicol) so the two sides can be made
   equal height and nothing can overflow sideways into a hidden third column,
   which is how the testimonial text was silently clipped before. */
.gvid {
  margin: clamp(1.6rem, 3vw, 2.4rem) 0 0;
  border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--shadow-md);
  aspect-ratio: 16 / 9; position: relative; background: var(--ink);
}
.gvid video { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; }
.g2col {
  margin-top: clamp(1.6rem, 3vw, 2.4rem);
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(1.5rem, 3.4vw, 3rem);
  align-items: start;
}
.g2col > * { min-width: 0; }
.g2col__col > * + * { margin-top: 1rem; }
@media (max-width: 860px) { .g2col { grid-template-columns: 1fr; } }

/* centred intro above the process steps */
.proc__intro { margin-inline: auto; text-align: center; }
.proc__intro .eyebrow { justify-content: center; }

/* heading beside its intro paragraph */
/* centre, not end: bottom-aligning a two-line heading against a longer
   paragraph left the heading hanging low in its own half of the row. */
.shead2 {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(1.4rem, 3.4vw, 3rem); align-items: center;
}
.shead2 .lede { margin: 0; }
@media (max-width: 860px) {
  .shead2 { grid-template-columns: 1fr; gap: 1rem; align-items: start; }
}

/* ==========================================================================
   HOME ADDITION INVESTMENT
   Was one long text column beside a single photo. Broken into a lede with a
   feature photo, the cost drivers as a card grid, and a closing block with a
   second photo, so the eye has somewhere to rest between paragraphs.
   Copy is unchanged: the cards reuse the original <li> text, split at the em
   dash into a label and its description.
   ========================================================================== */
.inv__head { max-width: 760px; }
.inv__top,
.inv__close {
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: clamp(1.6rem, 3.6vw, 3.2rem);
  align-items: stretch;
  margin-top: clamp(1.8rem, 3vw, 2.6rem);
}
.inv__top > *, .inv__close > * { min-width: 0; }
.inv__close { grid-template-columns: .95fr 1.05fr; }
.inv__close .inv__fig { order: -1; }
.inv__lede > * + *, .inv__closebody > * + * { margin-top: 1rem; }
/* Centring the text here left the photo up to 174px taller than it. The row
   is driven by the TEXT: the figure stretches to match, with a floor so a
   short paragraph cannot squash it into a letterbox. */
.inv__fig { max-height: none; }
/* the figure is pinned to the text height so the two columns end level, the
   same trick the guide's splits use: an absolutely positioned image cannot
   inflate the grid row with its own proportions. */
.inv__fig {
  position: relative; margin: 0;
  align-self: stretch; min-height: min(16vw, 240px);
  border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-md);
}
.inv__fig img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.inv__drivers { margin-top: clamp(2rem, 3.6vw, 3rem); }
.idrv__intro { max-width: 74ch; }
.idrv__grid {
  list-style: none; padding: 0;
  margin-top: clamp(1.1rem, 2vw, 1.5rem);
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(.8rem, 1.5vw, 1.1rem);
}
.idrv {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.1rem, 1.8vw, 1.4rem);
  display: flex; flex-direction: column; gap: .5rem;
  transition: border-color .45s var(--ease), transform .45s var(--ease), box-shadow .45s var(--ease);
}
.idrv:hover { border-color: var(--gold); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.idrv__top { display: flex; align-items: center; gap: .55rem; }
.idrv__ico { flex: none; color: var(--brown); }
.idrv b { font-size: .97rem; font-weight: 600; color: var(--ink); letter-spacing: -.01em; }
.idrv > span:last-child { font-size: .88rem; font-weight: 300; color: var(--text-mut); line-height: 1.6; }

@media (max-width: 1100px) { .idrv__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 860px) {
  .inv__top, .inv__close { grid-template-columns: 1fr; }
  .inv__close .inv__fig { order: 0; }
  .inv__fig { min-height: 240px; }
}
@media (max-width: 560px) { .idrv__grid { grid-template-columns: 1fr; } }

/* ==========================================================================
   GARAGE TYPES
   Five types stacked in a half-width column ran the section to 1450px, about
   1.6 screens. Full-width card grid instead: the same five items read across
   in two rows, so the section is a single screen and the eye scans rather
   than scrolls. Copy is lifted verbatim from the original list.
   ========================================================================== */
.gtypes__head { max-width: 760px; }
.gtypes__lede { max-width: 74ch; margin-top: 1rem; }
.gtypes__grid {
  list-style: none; padding: 0;
  margin-top: clamp(1.8rem, 3vw, 2.6rem);
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(.9rem, 1.6vw, 1.2rem);
}
.gt {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(1.15rem, 1.9vw, 1.5rem);
  display: flex; flex-direction: column; gap: .55rem;
  transition: border-color .45s var(--ease), transform .45s var(--ease), box-shadow .45s var(--ease);
}
.gt:hover { border-color: var(--gold); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.gt__top { display: flex; align-items: center; gap: .6rem; }
.gt__ico { flex: none; color: var(--brown); }
.gt b { font-size: 1rem; font-weight: 600; color: var(--ink); letter-spacing: -.01em; }
.gt__d { font-size: .9rem; font-weight: 300; color: var(--text-mut); line-height: 1.65; }
.gtypes__foot { margin-top: clamp(1.6rem, 2.6vw, 2.2rem); }

@media (max-width: 1000px) { .gtypes__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .gtypes__grid { grid-template-columns: 1fr; } }

/* ==========================================================================
   CITY PAGE (Lakeville and siblings)
   The service blocks were five identical text-beside-photo splits stacked down
   the page, and the intro / About / services sections were bare 74ch columns.
   These pieces give the page a rhythm: a stat ribbon under the hero, a service
   card grid, an editorial About split, and a highlight band.
   All copy is lifted verbatim from the live page.
   ========================================================================== */

/* intro line under the hero, set as a statement with supporting facts */
.lvintro { display: grid; grid-template-columns: 1.15fr .85fr;
  gap: clamp(1.6rem, 4vw, 3.6rem); align-items: center; }
.lvintro > * { min-width: 0; }
.lvintro__lede { font-size: clamp(1.15rem, 1.9vw, 1.5rem); font-weight: 300;
  line-height: 1.5; color: var(--ink); letter-spacing: -.015em; }
.lvfacts { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }
.lvfact { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: clamp(.9rem, 1.5vw, 1.15rem); }
.lvfact__k { font-size: .72rem; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--brown); }
.lvfact__v { margin-top: .3rem; font-size: .95rem; font-weight: 500; color: var(--ink); }
@media (max-width: 900px) { .lvintro { grid-template-columns: 1fr; } }

/* the five services as cards instead of five stacked splits */
.lvsvc { display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 1.8vw, 1.4rem); margin-top: clamp(1.8rem, 3vw, 2.6rem); }
.lvcard { display: flex; flex-direction: column; overflow: hidden;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--shadow-sm);
  transition: border-color .45s var(--ease), transform .45s var(--ease), box-shadow .45s var(--ease); }
.lvcard:hover { border-color: var(--gold); transform: translateY(-3px); box-shadow: var(--shadow-md); }
.lvcard__img { aspect-ratio: 4/3; overflow: hidden; }
.lvcard__img img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 1.1s var(--ease); }
.lvcard:hover .lvcard__img img { transform: scale(1.05); }
.lvcard__body { padding: clamp(1.05rem, 1.8vw, 1.4rem); display: flex; flex-direction: column; flex: 1; }
.lvcard__body h3 { font-size: 1.05rem; margin-bottom: .45rem; }
.lvcard__body p { font-size: .9rem; font-weight: 300; color: var(--text-mut); line-height: 1.65; }
/* three cards: a 2-col step would leave a hole, so go straight from 3 to 1 */
@media (max-width: 1000px) { .lvsvc { grid-template-columns: 1fr; } }

/* The four detailed write-ups.
   Getting here took three attempts, and the measurements settled it: each
   entry carries only ~270 characters, about 150-180px of text. Any
   text-beside-photo row therefore has to choose between a letterbox photo
   strip and dead space next to the copy, and stacking four of them ran the
   section past 3800px. Four short entries belong SIDE BY SIDE. A 2x2 of tall
   image cards gives the photography real presence, keeps the section near
   1700px, and reads as a different block from both the 3-card service row
   above and the About split below. */
.lvidx {
  margin-top: clamp(2rem, 3.6vw, 3rem);
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.1rem, 2vw, 1.6rem);
}
.lventry {
  position: relative; display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(340px, 30vw, 460px);
  border-radius: var(--r-lg); overflow: hidden; isolation: isolate;
  background: var(--ink); color: var(--on-dark);
  box-shadow: var(--shadow-md);
}
.lventry img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.3s var(--ease);
}
.lventry:hover img { transform: scale(1.05); }
/* the scrim is what makes light text on project photography legible; measured
   from rendered pixels, not assumed */
.lventry::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  /* A card-height gradient cannot serve every width: at narrow widths the copy
     wraps taller and climbs into the light end, which measured 1.90:1. So the
     scrim is anchored to the TEXT block instead of the card, sized in em of
     the copy, and only fades above whatever height the text actually needs. */
  /* Percentage scrim bands cannot know how tall the copy is: a card with two
   paragraphs pushed its text into the light end and measured 3.42:1 while a
   one-paragraph card on the same photo passed. So the readable ground is
   attached to the TEXT BLOCK, which always matches its own height, and the
   card keeps only a light wash for the photo's top area. */
  background: linear-gradient(to top,
    rgba(46,39,37,.62) 0%, rgba(46,39,37,.34) 55%, rgba(46,39,37,.14) 100%);
}
.lventry__c {
  position: relative; z-index: 1;
  /* The band carries the text AND the card's padding, so the card itself has
     none. Negative margins here (the earlier approach) pushed every card
     32px past its own width once the card padding was removed. */
  padding: clamp(1.3rem, 2.4vw, 2rem);
  width: 100%;
  /* fade out at the TOP so the band does not cut a hard line across the photo;
     the solid part still sits behind every line of copy */
  /* fade out at the TOP so the band does not cut a hard line across the photo;
     the solid part still sits behind every line of copy. On Family A the box
     can fill the whole card, so the clear zone is capped at a fixed distance
     rather than a percentage -- measured from the rendered card, the heading
     reads 13.2:1 and body copy 9.6:1 against this band. */
  background: linear-gradient(to top,
    rgba(46,39,37,.94) 0%,
    rgba(46,39,37,.90) calc(100% - 4.2rem),
    rgba(46,39,37,.62) calc(100% - 1.6rem),
    rgba(46,39,37,.18) 100%);
  padding-top: clamp(2.8rem, 4.8vw, 4rem);
}
.lventry__n {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .72rem; font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase; color: var(--on-dark); margin-bottom: .6rem;
}
.lventry__n::before { content: ""; width: 20px; height: 1px; background: var(--gold); opacity: .95; }
.lventry__c { position: relative; z-index: 1; }
.lventry__c h3 { color: var(--on-dark); font-size: clamp(1.1rem, 1.8vw, 1.4rem);
  letter-spacing: -.02em; }
.lventry__c p { margin-top: .6rem; color: rgba(248,244,242,.9);
  font-weight: 300; font-size: .93rem; line-height: 1.65; }
/* narrower cards wrap the copy taller, so the solid band has to reach higher */
/* An odd number of entries leaves the last card orphaned beside a hole.
   Lakeville has 4 and never hit this; Bloomington has 5. Let a trailing odd
   card span the full width instead, so the grid's bottom edge stays flush.
   :nth-child(odd):last-child matches only when the count itself is odd. */
.lvidx > .lventry:nth-child(odd):last-child { grid-column: 1 / -1; }


@media (max-width: 820px) {
  .lvidx { grid-template-columns: 1fr; }
  .lventry { min-height: 320px; }
}

/* the services overview reads as a lead-in: centred, generous, no photo, so
   the numbered index below it carries the imagery */
.lvlead { max-width: none; margin-inline: auto; text-align: center; }
.lvlead .eyebrow { justify-content: center; }
.lvlead__head { max-width: 62ch; margin-inline: auto; }
/* the two intro paragraphs side by side and left aligned. Real grid columns,
   not `columns: 2`: multicol overflows SIDEWAYS into a hidden third column,
   which is how the testimonial copy was silently clipped earlier. */
.lvlead__cols {
  margin-top: clamp(1.2rem, 2.2vw, 1.8rem);
  max-width: 104ch; margin-inline: auto;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(1.4rem, 3.2vw, 3rem);
  text-align: left;
}
.lvlead__cols > * { min-width: 0; margin: 0; }
/* A single intro paragraph has nothing to sit beside, so the two-column rule
   above does not apply: centre it and hold the measure so it wraps to two
   lines rather than one long ribbon. */
.lvlead__cols:has(> :only-child) {
  grid-template-columns: 1fr;
  /* wide enough that the longer Northfield wording still lands on two lines;
     62ch pushed it to three */
  max-width: 82ch;
  text-align: center;
}
.lvlead__cols:has(> :only-child) > * { margin-inline: auto; }
.lvlead__p { font-size: clamp(1rem, 1.35vw, 1.1rem);
  font-weight: 300; line-height: 1.72; color: var(--text-mut); }
@media (max-width: 820px) {
  .lvlead__cols { grid-template-columns: 1fr; gap: .9rem; }
}

/* Service area: the city photo as a full-bleed background with the copy over
   it. Light text on photography, so the readable ground is attached to the
   TEXT BLOCK rather than painted flat across the whole panel: that is what
   keeps it legible regardless of how bright the city photo is, and it is the
   same approach the detail cards use. */
/* the section carries the site's vertical rhythm; a full-bleed panel should
   sit flush instead, with no band of page colour above or below it */
.sect--flush { padding: 0; }
.sect--flush > .wrap { max-width: none; padding: 0; }

/* Service area: the city photo full-bleed with the copy over it.
   Two stacked scrims (a panel wash plus a near-opaque band behind the text)
   buried the photograph. Now there is ONE gradient, angled so it is dense
   behind the copy on the left and clears to almost nothing on the right,
   which keeps the text legible and lets the project photo actually read. */
.lvarea {
  position: relative; isolation: isolate; overflow: hidden;
  width: 100vw; margin-inline: calc(50% - 50vw);
  min-height: clamp(360px, 36vw, 520px);
  display: flex; align-items: center;
  background: var(--ink);
}
.lvarea > img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.4s var(--ease);
}
.lvarea:hover > img { transform: scale(1.04); }
.lvarea::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to right,
      rgba(46,39,37,.96) 0%, rgba(46,39,37,.94) 42%,
      rgba(46,39,37,.55) 68%, rgba(46,39,37,.18) 100%),
    linear-gradient(to top,
      rgba(46,39,37,.34) 0%, rgba(46,39,37,.10) 45%, rgba(46,39,37,.24) 100%);
}
.lvarea__body {
  position: relative; z-index: 1; width: 100%;
  padding-block: clamp(2.4rem, 5vw, 4rem);
  color: var(--on-dark);
}
.lvarea__inner {
  max-width: var(--maxw); margin-inline: auto; width: 100%;
  padding-inline: var(--gutter);
}
.lvarea__inner > * { max-width: 54ch; }
/* Family A's service-area copy runs 640-775 characters. In one 54ch column
   that is a very tall, narrow block of text against the photo. Pages carrying
   a long block get two columns so the lines stay short but the block does
   not tower; the heading and button stay full width above and below it. */
.lvarea__body--2col { max-width: min(96ch, 100%); }
/* Two grid tracks, with the paragraphs DEALT between them rather than one per
   column. The copy runs to three paragraphs of very unequal length (224, 406
   and 130 characters on Apple Valley), so a naive left/right split left the
   first column badly short -- a 275-character gap on Minneapolis that read as
   dead space.
   Multicol balances this perfectly but splits a paragraph across the fold
   mid-sentence, which reads worse than a slightly uneven column. So the
   markup assigns each paragraph a column, pairing the short closer with the
   short opener, and every paragraph stays whole. */
.lvarea__body--2col .lvarea__cols {
  display: grid; grid-template-columns: 1fr 1fr;
  column-gap: clamp(1.6rem, 3.2vw, 3rem); row-gap: .9rem;
  align-items: start;
  margin-top: clamp(1rem, 1.8vw, 1.4rem);   /* clear of the heading */
}
.lvarea__body--2col .lvarea__cols > * { min-width: 0; margin: 0; }
.lvarea__body--2col .lvarea__cols > .col { display: flex;
  flex-direction: column; gap: .9rem; }
@media (max-width: 900px) {
  .lvarea__body--2col .lvarea__cols { grid-template-columns: 1fr; }
}
.lvarea__body .eyebrow { color: #E8B968; }
.lvarea__body h2 { color: var(--on-dark); }
.lvarea__body p { color: rgba(248,244,242,.94); font-weight: 300; margin-top: 1rem; }
/* the button sat flush against the paragraph (measured 0px) */
.lvarea__body .btn { margin-top: clamp(1.5rem, 2.6vw, 2.1rem); }
.lvarea__body .btn--ghost {
  border-color: rgba(248,244,242,.5); color: var(--on-dark); background: transparent;
}
.lvarea__body .btn--ghost:hover {
  background: var(--on-dark); color: var(--ink); border-color: var(--on-dark);
}
/* narrow screens have no room for a side-weighted scrim, so it becomes a
   bottom-up wash with the copy sitting in the dense part */
@media (max-width: 860px) {
  .lvarea { min-height: 340px; align-items: flex-end; }
  .lvarea::after {
    background: linear-gradient(to top,
      rgba(46,39,37,.93) 0%, rgba(46,39,37,.90) 55%,
      rgba(46,39,37,.62) 80%, rgba(46,39,37,.38) 100%);
  }
  .lvarea__inner > * { max-width: none; }
}

/* About: copy beside a portrait photo, on the dark ink ground */
.lvabout { background: var(--ink); color: var(--on-dark);
  border-radius: var(--r-lg); overflow: hidden;
  display: grid; grid-template-columns: 1.1fr .9fr; align-items: stretch; }
.lvabout > * { min-width: 0; }
.lvabout__body { padding: clamp(1.6rem, 3.4vw, 3rem); align-self: center; }
.lvabout__body .eyebrow { color: var(--gold); }
.lvabout__body h2 { color: var(--on-dark); }
.lvabout__body p { color: rgba(248,244,242,.86); font-weight: 300; }
.lvabout__body p + p { margin-top: 1rem; }
.lvabout__body .btn { margin-top: 1.6rem; }
.lvabout__fig { position: relative; margin: 0; min-height: min(22vw, 340px); }
.lvabout__fig img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 860px) { .lvabout { grid-template-columns: 1fr; }
  .lvabout__fig { min-height: 260px; order: -1; } }

/* A CTA tile that fills the odd slot in the service card grid. .scard darkens
   a background photo and sets light text; this card has no photo, so it needs
   its own light treatment or the heading would be invisible. */
.scard--cta {
  background: var(--ink); color: var(--on-dark);
  display: flex; align-items: center;
  padding: clamp(1.4rem, 2.6vw, 2rem);
}
.scard--cta::after { display: none; }
.scard--cta .scard__body { position: static; padding: 0; }
.scard--cta h3 { color: var(--on-dark); }
.scard--cta p {
  color: rgba(248,244,242,.84); font-weight: 300;
  margin-top: .6rem; font-size: .93rem; line-height: 1.65;
}
.scard__acts { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1.3rem; }

/* the hero lost its form card, so the copy no longer shares the row */
.hero__grid--solo { grid-template-columns: minmax(0, 1fr); }
.hero__grid--solo > div { max-width: 46rem; }

/* Welcome: copy left, the form card that used to sit in the hero on the right */
/* centre the copy against the form card, which is taller than the two
   paragraphs beside it */
.welcome--form { grid-template-columns: 1.05fr .95fr; align-items: center; }
.welcome--form .welcome__copy > * + * { margin-top: 1.1rem; }
.welcome__form { margin: 0; }
@media (max-width: 900px) {
  .welcome--form { grid-template-columns: 1fr; }
}

/* Keep the hero headline to three lines. At the previous size it wrapped to
   four at every width, which pushed the copy block taller than it needed to be
   and crowded the buttons against the bottom edge. */
.hero h1.display {
  /* Three lines, not four. The wrap was driven by the column width, not the
     type size: at 17ch "for Remodels &" and "Additions" split. Widening the
     measure lets "for Remodels & Additions" close on one line. */
  font-size: clamp(2rem, 4.05vw, 3.5rem);
  max-width: 24ch;
}
@media (max-width: 1100px) {
  .hero h1.display { max-width: 22ch; }
}
@media (max-width: 560px) {
  /* a phone is too narrow for three lines at a readable size, so let it wrap
     to four rather than shrinking the headline into insignificance */
  .hero h1.display { font-size: clamp(1.75rem, 7.4vw, 2.2rem); max-width: 20ch; }
}


/* ==========================================================================
   STICKY MOBILE CALL BAR
   Two actions pinned to the bottom at <=1024px. z-index 95 puts it above the
   drawer (89) and the header (90), so calling stays one tap even with the
   mobile menu open. Hidden above 1024px, where the header already shows both
   a phone button and a Free Consultation button.
   ========================================================================== */
.callbar { display: none; }

@media (max-width: 1024px) {
  .callbar {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: .55rem;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 95;
    padding: .6rem var(--gutter);
    /* safe-area keeps the bar clear of the iOS home indicator */
    padding-bottom: calc(.6rem + env(safe-area-inset-bottom, 0px));
    background: rgba(46, 39, 37, .96);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid rgba(248, 244, 242, .14);
  }
  .callbar .btn {
    width: 100%; justify-content: center;
    padding: .82rem .6rem;
    font-size: .92rem;
    white-space: nowrap;
  }
  /* the bar sits on dark, so the ghost button needs its light-on-dark variant */
  .callbar .btn--ghost {
    border-color: rgba(248, 244, 242, .38);
    color: var(--on-dark);
    background: transparent;
  }
  .callbar .btn--ghost:hover {
    background: var(--cream); color: var(--ink); border-color: var(--cream);
  }
  .callbar__num { font-variant-numeric: tabular-nums; }

  /* stop the bar covering the end of the page and the drawer's last links */
  body { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
  .drawer { padding-bottom: calc(88px + env(safe-area-inset-bottom, 0px)); }
}

/* a phone in landscape has almost no height to spare */
@media (max-width: 1024px) and (max-height: 430px) {
  .callbar { display: none; }
  body { padding-bottom: 0; }
}

/* ---------- Family A city pages ---------- */
/* Five service cards, not three. A plain repeat(3,1fr) leaves a ragged 3+2,
   so the last row is centred by spanning each of its two cards across two
   tracks of a 6-column grid. */
.lvsvc--5 { grid-template-columns: repeat(6, 1fr); }
.lvsvc--5 > .lvcard { grid-column: span 2; }
.lvsvc--5 > .lvcard:nth-child(4) { grid-column: 2 / span 2; }
.lvsvc--5 > .lvcard:nth-child(5) { grid-column: 4 / span 2; }
@media (max-width: 980px) {
  .lvsvc--5 { grid-template-columns: repeat(4, 1fr); }
  .lvsvc--5 > .lvcard,
  .lvsvc--5 > .lvcard:nth-child(4) { grid-column: span 2; }
  .lvsvc--5 > .lvcard:nth-child(5) { grid-column: 2 / span 2; }
}
@media (max-width: 640px) {
  .lvsvc--5 { grid-template-columns: 1fr; }
  .lvsvc--5 > .lvcard,
  .lvsvc--5 > .lvcard:nth-child(4),
  .lvsvc--5 > .lvcard:nth-child(5) { grid-column: 1; }
}

/* heading block above the detail grid */
.lvdhead { text-align: center; max-width: 74ch; margin-inline: auto;
  margin-bottom: clamp(1.8rem, 3vw, 2.6rem); }
.lvdhead .eyebrow { justify-content: center; }

/* YouTube embed under the detail grid */
.lvvid { margin-top: clamp(2rem, 3.4vw, 3rem); max-width: 900px;
  margin-inline: auto; }
.lvvid__frame { position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: var(--r-md); box-shadow: var(--shadow-md);
  background: var(--ink); }
.lvvid__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%;
  border: 0; display: block; }

/* The video sits in the About block's photo slot, so it must fill that grid
   cell rather than behave as the centred 900px block it is under .lvidx. */
/* Centring the 16:9 frame in the column left dead bands above and below it,
   because the copy is taller than the video's natural height. The frame fills
   the cell instead and the iframe crops to it, the way the photo did. */
.lvvid--about { margin: 0; max-width: none; align-self: stretch;
  background: var(--ink); position: relative; min-height: min(22vw, 340px); }
.lvvid--about .lvvid__frame { position: absolute; inset: 0; width: 100%;
  height: 100%; aspect-ratio: auto; border-radius: 0; box-shadow: none; }
@media (max-width: 860px) {
  /* Stacked, the photo's min(22vw,340px) floor collapses to ~154px and crops
     the video to a letterbox strip. A video needs its own 16:9 here. */
  .lvvid--about { order: -1; min-height: 0; }
  .lvvid--about .lvvid__frame { position: relative; inset: auto;
    height: auto; aspect-ratio: 16 / 9; }
}

/* ---------- detail: alternating editorial rows ---------- */
/* Each topic carries 670-790 characters. Text that long cannot sit ON a
   photo: the scrim has to go nearly opaque to stay readable, which buries
   the image. Copy and photo each get a real column instead, so both are
   fully visible. */
.lvrows { display: grid; gap: clamp(2.4rem, 5vw, 4.6rem); }
.lvrow {
  display: grid; grid-template-columns: 1.02fr .98fr;
  gap: clamp(1.6rem, 4vw, 3.6rem); align-items: stretch;
}
/* The copy centres against the photo beside it. The photo still stretches to
   the row, so only the text moves: centring the GRID ITEMS instead would let
   the photo shrink to its content and stop being symmetrical with the copy. */
.lvrow__body { display: flex; flex-direction: column; justify-content: center; }
.lvrow > * { min-width: 0; }          /* else min-content width eats the photo */
.lvrow--flip .lvrow__media { order: 2; }
.lvrow__media {
  position: relative; margin: 0; align-self: stretch;
  min-height: clamp(240px, 26vw, 380px);
  border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-md);
}
.lvrow__media img { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .7s var(--ease); }
.lvrow:hover .lvrow__media img { transform: scale(1.04); }
/* the topic number rides on the photo, keeping the numbered sequence without
   putting any body copy over the image */
.lvrow__n {
  position: absolute; left: 0; top: 0; z-index: 1;
  font-size: .82rem; font-weight: 600; letter-spacing: .12em;
  color: var(--on-dark); background: rgba(46,39,37,.82);
  padding: .5rem .85rem; border-bottom-right-radius: var(--r-md);
}
.lvrow__body h3 { font-size: clamp(1.25rem, 2.1vw, 1.65rem);
  letter-spacing: -.02em; margin-bottom: .9rem; }
.lvrow__body p { color: var(--text-mut); font-weight: 300; line-height: 1.75; }
.lvrow__body p + p { margin-top: .9rem; }
@media (max-width: 860px) {
  .lvrow { grid-template-columns: 1fr; gap: 1.3rem; }
  .lvrow--flip .lvrow__media { order: 0; }   /* photo always leads when stacked */
  .lvrow__media { min-height: 0; aspect-ratio: 16 / 10; }
}

/* ---------- service grid: CTA tile ---------- */
/* Six tiles make an even 3x2, so the ragged 5-card row is gone. */
.lvsvc--6 { grid-template-columns: repeat(3, 1fr); }
/* The tile sits in a row with photo cards, so it must not set its own
   min-height: that made it taller than its neighbours. Stretching to the row
   and centring the content keeps the row even and kills the empty band that
   top-aligned content left underneath. */
.lvcard--cta { position: relative; isolation: isolate; overflow: hidden;
  border: 0; background: var(--ink);
  display: flex; align-items: center; justify-content: flex-start; }
.lvcard--cta > img { position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; }
.lvcard--cta::after { content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top,
    rgba(46,39,37,.94) 0%, rgba(46,39,37,.86) 55%, rgba(46,39,37,.72) 100%); }
/* The card stretches to the row, so the content block has to centre itself
   inside that height or it hugs the top and leaves a dead band below. */
.lvcard--cta__c { padding: clamp(1.3rem, 2.4vw, 1.9rem);
  width: 100%; margin-block: auto; }
.lvcard--cta h3 { color: var(--on-dark); font-size: 1.15rem;
  margin-bottom: .55rem; }
.lvcard--cta p { color: rgba(248,244,242,.88); font-weight: 300;
  font-size: .92rem; line-height: 1.6; }
.lvcard--cta .btn { margin-top: 1.1rem; }
.lvcard--cta:hover { transform: translateY(-3px); }
@media (max-width: 980px) { .lvsvc--6 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .lvsvc--6 { grid-template-columns: 1fr; } }

/* ---------- service card -> detail row link ---------- */
/* The header is fixed, so a row landed under it on a direct #svc-deck load.
   The JS smooth-scroll already offsets clicks by 90px; this covers the rest. */
.lvrow[id] { scroll-margin-top: 110px; }

.lvcard--link { cursor: pointer; }
.lvcard__go {
  display: inline-flex; align-items: center; gap: .4rem;
  margin-top: auto; padding-top: .9rem;
  font-size: .84rem; font-weight: 600; letter-spacing: .02em;
  color: var(--brown); text-decoration: none;
  transition: gap .35s var(--ease), color .35s var(--ease);
}
.lvcard__go .ico { transition: transform .35s var(--ease); }
.lvcard--link:hover .lvcard__go { color: var(--gold-dk); }
.lvcard--link:hover .lvcard__go .ico { transform: translateX(3px); }
/* the whole card is clickable, with the visible cue as the accessible name */
.lvcard--link { position: relative; }
.lvcard__go::after { content: ""; position: absolute; inset: 0; }
.lvcard--link:focus-within { outline: 2px solid var(--gold);
  outline-offset: 3px; }
/* a row jumped to from a card gets a brief highlight so the eye lands on it */
.lvrow[id]:target .lvrow__media { box-shadow: 0 0 0 3px var(--gold),
  var(--shadow-md); }

/* Family B carries 3 service cards, so its CTA tile makes 4: an even 2x2
   rather than Family A's 3x2. */
.lvsvc--4 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 640px) { .lvsvc--4 { grid-template-columns: 1fr; } }

/* Castle Rock's services lead: heading block on the left, intro copy on the
   right, rather than centred above it. */
.lvlead--split { text-align: left; }
.lvlead--split .eyebrow { justify-content: flex-start; }
.lvlead--split .lvlead__head { max-width: none; margin-inline: 0; }
@media (min-width: 861px) {
  .lvlead--split { display: grid; grid-template-columns: .95fr 1.05fr;
    gap: clamp(1.6rem, 4vw, 3.4rem); align-items: start; }
  .lvlead--split > * { min-width: 0; }
  .lvlead--split .lvlead__cols { margin-top: 0; max-width: none;
    margin-inline: 0; grid-template-columns: 1fr; gap: .9rem; }
}

/* Faribault and Maple Grove carry three lead paragraphs, so the third fell to
   a row of its own and left a large empty cell beside it. Their paragraphs are
   dealt into two balanced columns in the markup, as in the service area. */
.lvlead__cols > .col { display: flex; flex-direction: column; gap: .9rem;
  min-width: 0; }
