/* ============================================================
   NJ INDOOR OUTDOOR MAINTENANCE, LLC — site.css

   Structure is the Home Built And Renovations build, unchanged:
   dark cinematic video hero with the quote panel alongside it,
   fully-rounded pills, one high-chroma accent, and the nav that
   is transparent over the hero then solid once it is behind you.

   Reskinned to this brand: Montserrat (from the reference site)
   in place of Poppins, and the logo's blue as the accent. The
   headline carries the reference site's accent bar behind one
   word — see .mark.
   ============================================================ */

:root {
  /* Dark — pulled toward the logo's navy rather than neutral black. */
  --ink:       #0B1226;
  --ink-2:     #121C3A;
  --ink-deep:  #060A16;

  /* Light surfaces */
  --paper:     #FFFFFF;
  --paper-2:   #F5F6F9;
  --line:      #E4E7EE;

  /* Type on light */
  --text:      #0B1226;
  --text-2:    #4C5265;
  --text-3:    #767C90;

  /* The logo's blue, opened up. A literal navy (#1B2A5B, the shade in the
     mark itself) is only ~4% luminance away from --ink, so as the hero
     underline and the button fill it would read as a hole in the dark
     rather than an accent. This keeps the hue and lifts the value. */
  --accent:     #2F6FE5;
  --accent-hi:  #4B87F2;
  --accent-dim: rgba(47, 111, 229, 0.34);

  /* The green from the logo's ellipse. Used sparingly — the eco/recycling
     claims are the only place their brand actually spends it. */
  --leaf:       #6FAF3E;

  --white:    #FFFFFF;
  --white-80: rgba(255,255,255,.80);
  --white-60: rgba(255,255,255,.60);

  --font: 'Montserrat', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --page-max: 1240px;
  --gutter:   28px;
  --nav-h:    104px;

  --r-card: 18px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.65;
  color: var(--text-2);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }

.container { max-width: var(--page-max); margin: 0 auto; padding: 0 var(--gutter); }
.section { padding: 104px 0; }
@media (max-width: 780px) { .section { padding: 68px 0; } }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--accent); color: #FFFFFF;
  padding: 12px 20px; font-weight: 600;
}
.skip-link:focus { left: 0; top: 0; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

/* ---------- Type ---------- */
.label {
  margin: 0 0 16px;
  font-size: 14px; font-weight: 600;
  letter-spacing: .02em;
  color: var(--accent);
}
.display {
  margin: 0;
  font-size: clamp(30px, 4vw, 50px);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -.015em;
  color: var(--text);
}
.display--xl { font-size: clamp(36px, 5.4vw, 68px); }
.lede { margin: 20px 0 0; font-size: 17px; line-height: 1.75; color: var(--text-2); max-width: 62ch; }
.sec-head { margin-bottom: 54px; max-width: 760px; }

/* ---------- Pills ---------- */
.pill-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 56px; padding: 15px 38px;
  border-radius: 999px;
  font-size: 16px; font-weight: 600; line-height: 1;
  white-space: nowrap;
  border: 2px solid var(--accent);
  color: var(--accent);
  background: transparent;
  transition: background-color .22s ease, color .22s ease, border-color .22s ease;
}
.pill-btn:hover { background: var(--accent); color: #FFFFFF; }
.pill-btn--solid {
  background: var(--accent); border-color: var(--accent); color: #FFFFFF;
  font-weight: 700; font-size: 15px; letter-spacing: .07em; text-transform: uppercase;
  padding: 15px 44px;
}
.pill-btn--solid:hover { background: var(--accent-hi); border-color: var(--accent-hi); }
.pill-btn--ghost { color: var(--white); border-color: rgba(255,255,255,.55); }
.pill-btn--ghost:hover { background: var(--white); color: var(--ink); border-color: var(--white); }

/* ---------- NAV ---------- */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  /* Transparent and borderless over the hero — no bar, no hairline. */
  background: transparent;
  transition: background-color .3s ease, box-shadow .3s ease;
}
.nav--solid {
  background: rgba(11, 18, 38, .95);
  backdrop-filter: blur(10px);
  box-shadow: 0 8px 30px rgba(0,0,0,.28);
}
.nav-inner {
  max-width: var(--page-max); margin: 0 auto;
  padding: 0 var(--gutter);
  height: var(--nav-h);
  display: flex; align-items: center; gap: 24px;
}
/* The mark lives in the HERO at full size and only migrates up here
   once the hero is behind you — otherwise you'd briefly see it twice. */
.nav-brand {
  flex: 0 0 auto;
  opacity: 0; visibility: hidden;
  transition: opacity .3s ease, visibility .3s ease;
}
.nav--solid .nav-brand { opacity: 1; visibility: visible; }
.nav-brand img { height: 54px; width: auto; }

.nav-links { margin-left: auto; display: flex; align-items: center; gap: 34px; }
.nav-link {
  font-size: 16px; font-weight: 500;
  color: var(--white);
  padding: 9px 0;
  transition: color .2s ease;
}
.nav-link:hover { color: var(--accent); }
.nav-phone { font-weight: 600; }
.nav-pill {
  min-height: 50px; padding: 13px 30px; margin-left: 4px;
  /* Filled, not outlined. Over the hero video an outlined accent pill
     put accent-on-video text at the mercy of whatever frame was
     underneath it; a solid fill keeps the primary CTA legible. */
  background: var(--accent); border-color: var(--accent); color: var(--white);
}
.nav-pill:hover { background: var(--accent-hi); border-color: var(--accent-hi); }

.menu-btn {
  display: none; margin-left: auto;
  width: 48px; height: 48px;
  background: transparent;
  border: 1px solid rgba(255,255,255,.3);
  border-radius: 999px; padding: 0;
  flex-direction: column; align-items: center; justify-content: center; gap: 5px;
}
.menu-btn .bar { display: block; width: 20px; height: 2px; background: var(--white); border-radius: 2px; }

@media (max-width: 1080px) {
  :root { --nav-h: 84px; }
  .nav-links { display: none; }
  .menu-btn { display: flex; }
  /* On phones the bar carries the mark permanently — the hero one is
     hidden, so it is never two logos on one screen. */
  .nav-brand { opacity: 1; visibility: visible; }
  .nav-brand img { height: 46px; }
}

.mobile-menu {
  display: none;
  position: fixed; inset: var(--nav-h) 0 0 0; z-index: 99;
  background: var(--ink);
  padding: 28px var(--gutter) 48px;
  flex-direction: column; gap: 2px; overflow-y: auto;
}
.mobile-menu.open { display: flex; }
.mobile-menu a {
  padding: 17px 0; font-size: 20px; font-weight: 500; color: var(--white);
  border-bottom: 1px solid rgba(255,255,255,.08);
}
.mobile-menu .mm-pill { margin-top: 26px; border-bottom: none; align-self: flex-start; }

/* ---------- HERO ---------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex; align-items: center;
  padding: calc(var(--nav-h) + 40px) 0 56px;
  overflow: hidden;
  background: var(--ink-deep);
}
.hero-media { position: absolute; inset: 0; z-index: 0; }
.hero-media img, .hero-media video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.hero-media video { opacity: 0; transition: opacity .7s ease; }
.hero-media video.ready { opacity: 1; }

/* NO flat wash over the footage. Two directional gradients only: one
   bedding the copy column, one giving the transparent nav something to
   sit on. Past ~55% across, the video is completely untinted. */
.hero-scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(96deg, rgba(5,7,15,.80) 0%, rgba(5,7,15,.60) 26%, rgba(5,7,15,.18) 46%, rgba(5,7,15,0) 58%),
    linear-gradient(180deg, rgba(5,7,15,.60) 0%, rgba(5,7,15,.12) 22%, rgba(5,7,15,0) 40%);
}

.hero-inner {
  position: relative; z-index: 2;
  width: 100%; max-width: var(--page-max);
  margin: 0 auto; padding: 0 var(--gutter);
  display: grid; grid-template-columns: 1fr 396px; gap: 56px; align-items: center;
}
/* Load-bearing. Grid items default to min-width:auto, so a column can
   never shrink below its content's min-content width — and the quote
   panel's <select> carries the width of its longest option ("Project
   Planning & Management"), which pins the column at ~337px and forces
   the whole hero to overflow a 360px phone. */
.hero-inner > * { min-width: 0; }

.hero-copy { max-width: 680px; }
.hero-brand { display: block; margin-bottom: 22px; }
.hero-brand img { height: 178px; width: auto; }   /* ~1.7x, per the brief */

/* ---------- Hero badges ----------
   These sit BELOW the two CTAs, with the rating badge below them. */
.badges {
  list-style: none; margin: 28px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 9px;
}
.badges li {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 14px;
  font-size: 13px; font-weight: 500; color: var(--white);
  background: rgba(11,18,38,.42);
  border: 1px solid rgba(255,255,255,.24);
  border-radius: 999px;
  backdrop-filter: blur(6px);
}
.badges svg { width: 17px; height: 17px; flex: 0 0 auto; color: var(--accent); }

/* ---------- Rating badge ----------
   Same shape as a platform badge but deliberately unbranded — the score
   comes from the review form on the client's own site. -->*/
.rating-badge {
  display: inline-flex; align-items: center; gap: 14px;
  margin-top: 22px; padding: 12px 20px;
  background: rgba(11,18,38,.52);
  border: 1px solid rgba(255,255,255,.22);
  border-radius: 999px;
  backdrop-filter: blur(6px);
}
.rb-stars { display: inline-flex; gap: 3px; color: var(--accent); }
.rb-stars svg { width: 17px; height: 17px; }
.rb-divider { width: 1px; align-self: stretch; background: rgba(255,255,255,.24); }
.rb-meta { display: flex; flex-direction: column; line-height: 1.3; }
.rb-score { font-size: 14px; font-weight: 600; color: var(--white); }
.rb-sub { font-size: 12px; color: var(--white-60); }

.eyebrow {
  display: flex; align-items: center; gap: 20px;
  margin: 0 0 24px;
  font-size: 18px; font-weight: 600; color: var(--white);
  text-shadow: 0 1px 12px rgba(0,0,0,.5);
}
.eyebrow-rule { flex: 0 0 auto; width: 56px; height: 2px; background: var(--accent); }

.hero-title {
  margin: 0;
  /* The low end is vw-driven, not a fixed floor: a fixed minimum that
     fits a 390px phone still overflows a 320px one, so the small end
     has to keep scaling rather than stop. This headline is long — nine
     words, and "Junk Removal" has to stay on one line for the .mark bar
     to make sense — so the ceiling is lower than the skeleton's. */
  font-size: clamp(24px, 5.2vw, 52px);
  font-weight: 700; line-height: 1.06; letter-spacing: -.015em;
  color: var(--white);
  /* Cheap insurance where the copy rides up onto the brighter sky. */
  text-shadow: 0 2px 26px rgba(0,0,0,.5);
  /* Own stacking context, so the .mark bar's z-index:-1 lands behind the
     glyphs and not behind the hero video. */
  position: relative;
  z-index: 0;
}

/* The reference site's accent bar under one word of the headline. Theirs is
   a fixed 152x13 background-image pinned at "0 59px" — it only lines up for
   the exact word and size they shipped, and they switch it off under 480px.
   This rebuilds it as a pseudo-element on a span: left/right:0 makes the bar
   exactly as wide as whatever word it wraps, and sizing it in em keeps the
   original's 13/64 proportion at every step of the clamp, so it survives
   down to 320px instead of disappearing. */
.mark { position: relative; display: inline-block; }
.mark::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: .094em;
  height: .203em;
  background: var(--accent);
  z-index: -1;
}

.hero-sub {
  margin: 22px 0 0;
  max-width: 46ch;
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.6;
  color: var(--white-80);
  text-shadow: 0 1px 14px rgba(0,0,0,.55);
}

.hero-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; margin-top: 36px; }

/* ---------- Quote panel ---------- */
.quote-panel {
  background: var(--paper);
  border-radius: 22px;
  padding: 30px 28px;
  box-shadow: 0 30px 70px rgba(0,0,0,.42);
}
.quote-title { margin: 0 0 6px; font-size: 23px; font-weight: 700; letter-spacing: -.01em; color: var(--text); }
.quote-sub { margin: 0 0 20px; font-size: 14px; color: var(--text-3); }
.q-label { display: block; margin: 14px 0 6px; font-size: 13px; font-weight: 500; color: var(--text-2); }
.q-input {
  width: 100%; padding: 13px 16px;
  font-family: var(--font); font-size: 16px;   /* 16px stops iOS zoom-on-focus */
  color: var(--text); background: var(--paper-2);
  border: 1px solid var(--line); border-radius: 12px;
  transition: border-color .2s ease, background-color .2s ease;
}
.q-input:focus { border-color: var(--accent); background: var(--paper); }
.q-select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text) 50%), linear-gradient(135deg, var(--text) 50%, transparent 50%);
  background-position: calc(100% - 20px) 50%, calc(100% - 14px) 50%;
  background-size: 6px 6px, 6px 6px; background-repeat: no-repeat;
  padding-right: 40px;
}
.q-textarea { resize: vertical; min-height: 84px; line-height: 1.55; }
.q-submit { width: 100%; margin-top: 22px; }
.q-note { margin: 12px 0 0; font-size: 12px; color: var(--text-3); text-align: center; }
.q-note.is-error { color: #B3261E; }
.q-done { font-size: 16px; line-height: 1.6; color: var(--text); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

@media (max-width: 1080px) {
  .hero { min-height: 0; padding: 0 0 60px; }
  .hero-inner { grid-template-columns: 1fr; gap: 0; align-items: start; }
  .hero-copy { max-width: none; }
  .hero-brand { display: none; }   /* nav carries the mark on phones */
  .hero-brand img { height: 120px; }

  /* The copy block owns the first screenful on its own, so the footage
     behind it is actually visible; the quote panel starts below the fold
     rather than covering the video the moment the page loads.
     padding-top clears the fixed nav — without it, content taller than
     the block overflows upward and slides under the bar. */
  .hero-copy {
    min-height: calc(100svh - var(--nav-h));
    display: flex; flex-direction: column; justify-content: center;
    padding: calc(var(--nav-h) + 20px) 0 44px;
  }
  .quote-panel { margin-bottom: 8px; }

  /* The media used to be inset:0, i.e. it covered the WHOLE hero —
     including the quote panel — so on a 390px screen `cover` was fitting
     a 16:9 frame into a ~1500px-tall box and showing barely a seventh of
     it. Confining it to one screenful roughly doubles what you see. */
  .hero-media,
  .hero-scrim { bottom: auto; height: calc(100svh - var(--nav-h)); }
}
@media (max-width: 680px) {
  /* Pills are nowrap by default, which is right on desktop but makes a
     long label ("Get your free estimate") a rigid 302px box that
     overflows a 320px phone — and once the document is wider than the
     viewport, the fixed nav stretches with it. Let them wrap and shrink. */
  .pill-btn {
    max-width: 100%;
    white-space: normal; text-align: center;
    padding-left: 26px; padding-right: 26px;
  }
  .about-copy .pill-btn, .cta-actions .pill-btn { width: 100%; }

  .hero-actions { flex-direction: column; align-items: stretch; gap: 12px; }
  .hero-actions .pill-btn { width: 100%; }
  .eyebrow { font-size: 16px; gap: 14px; }
  .eyebrow-rule { width: 40px; }
  /* Two per row rather than a four-deep stack eating the fold. */
  .badges { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 22px; }
  .badges li { padding: 8px 12px; font-size: 12px; gap: 7px; min-width: 0; }
  .badges svg { width: 15px; height: 15px; }
  .rating-badge { margin-top: 26px; }
}
@media (max-width: 440px) {
  /* No eyebrow is short enough to guarantee one line at every width, so
     stack the rule above the label rather than strand it beside a
     wrapped sentence. */
  .eyebrow { flex-direction: column; align-items: flex-start; gap: 12px; }
  .eyebrow-rule { width: 46px; }
}
/* Short viewports (phones in landscape): the copy is far taller than the
   screen, so forcing a full-height centred block just pushes it under the
   nav. Let it flow from the top instead. */
@media (max-width: 1080px) and (max-height: 620px) {
  .hero-copy { min-height: 0; justify-content: flex-start; }
  .hero-media, .hero-scrim { height: 100%; bottom: 0; }
}
@media (max-width: 340px) {
  /* Two columns hold down to here because .badges li has min-width:0, so
     a long label wraps inside its pill rather than forcing the grid
     wider. Below this even a wrapped pill gets too cramped. */
  .badges { grid-template-columns: 1fr; }
  .rating-badge { gap: 11px; padding: 11px 16px; }
}

/* ---------- TRUST BAND ---------- */
.trust { background: var(--ink); }
.trust-inner {
  padding-top: 26px; padding-bottom: 26px;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px;
}
.trust-item { display: flex; align-items: center; gap: 12px; font-size: 14px; font-weight: 500; color: var(--white); }
.trust-item svg { width: 22px; height: 22px; flex: 0 0 auto; color: var(--accent); }
@media (max-width: 900px) { .trust-inner { grid-template-columns: repeat(2, 1fr); gap: 18px; } }
@media (max-width: 420px) { .trust-item { font-size: 13px; } }

/* ---------- SERVICES ---------- */
.services { background: var(--paper); }
.card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; }
.card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
  transition: transform .3s ease, box-shadow .3s ease;
}
.card:hover { transform: translateY(-4px); box-shadow: 0 18px 44px rgba(11,18,38,.10); }
.card-media { aspect-ratio: 3 / 2; overflow: hidden; }
.card-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
.card:hover .card-media img { transform: scale(1.05); }
.card-body { padding: 24px 24px 28px; }
.card-num { margin: 0 0 8px; font-size: 13px; font-weight: 600; color: var(--accent); }
.card-body h3 { margin: 0 0 10px; font-size: 20px; font-weight: 600; color: var(--text); line-height: 1.25; }
.card-body p { margin: 0; font-size: 15px; line-height: 1.7; color: var(--text-2); }

/* They sell exactly two services, so the services grid runs two-up with a
   taller image rather than being padded out to the six the skeleton had.
   The six-card grid still earns its keep further down, on the use cases. */
.card-grid--duo { grid-template-columns: repeat(2, 1fr); gap: 32px; }
.card-grid--duo .card-media { aspect-ratio: 16 / 10; }
.card-grid--duo .card-body { padding: 30px 30px 34px; }
.card-grid--duo .card-body h3 { font-size: 25px; }
.card-grid--duo .card-body p { font-size: 16px; }

.more-wrap { display: flex; justify-content: center; margin-top: 36px; }
.more-btn { color: var(--text); border-color: var(--text); }
.more-btn:hover { background: var(--text); color: var(--white); }

@media (max-width: 1040px) { .card-grid { grid-template-columns: repeat(2, 1fr); gap: 22px; } }
@media (max-width: 680px) {
  .card-grid { grid-template-columns: 1fr; gap: 20px; }
  /* .js-gated for the same reason as the FAQ: the "See all 6" button
     starts [hidden] and only JS reveals it, so without JS this rule
     would silently drop half the cards with no way to get them back. */
  .js .card-grid[data-collapsed="true"] .card:nth-child(n+4) { display: none; }
}
@media (min-width: 681px) { .more-wrap { display: none; } }

/* ---------- ABOUT ----------
   Full-bleed photograph. The scrim is DIRECTIONAL, not a flat wash: it
   carries the copy column and is gone by the right-hand third, so the
   chalet reads as a photograph rather than a darkened backdrop. */
.about { position: relative; overflow: hidden; background: var(--ink); }
/* The crew photo is landscape in a section taller than it is wide, so a
   centred cover crop lands on everybody's knees. Bias the window up to
   hold the faces. */
.about-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 28%; }
.about-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(96deg, rgba(5,7,15,.90) 0%, rgba(5,7,15,.74) 32%, rgba(5,7,15,.30) 58%, rgba(5,7,15,.05) 78%),
    linear-gradient(180deg, rgba(5,7,15,.30) 0%, rgba(5,7,15,0) 30%);
}
.about-inner {
  position: relative; z-index: 1;
  padding-top: 104px; padding-bottom: 104px;
  display: grid; grid-template-columns: 1.08fr .92fr; gap: 56px; align-items: center;
}
.about-inner > * { min-width: 0; }
.about-copy .display { color: var(--white); }
.about-quote {
  margin: 26px 0 14px; padding-left: 22px;
  border-left: 3px solid var(--accent);
  font-size: 18px; line-height: 1.75; color: rgba(255,255,255,.9);
}
.about-attrib { margin: 0 0 30px; font-size: 14px; font-weight: 600; color: var(--accent); }

.spec-card { background: rgba(255,255,255,.96); border-radius: 22px; padding: 28px 26px; }
@media (max-width: 720px) { .spec-card { padding: 24px 22px; } }
.spec-head {
  margin: 0 0 16px; padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
  font-size: 14px; font-weight: 600; color: var(--accent);
}
.spec-list { list-style: none; margin: 0; padding: 0; }
.spec-list li {
  padding: 9px 0 9px 24px; position: relative;
  font-size: 14px; line-height: 1.5; color: var(--text);
  border-bottom: 1px solid var(--line);
}
.spec-list li:last-child { border-bottom: none; }
/* The card carries the three process steps here rather than a licence
   list, so each row leads with its step name. */
.spec-list strong { display: block; margin-bottom: 2px; font-weight: 700; }
.spec-list li::before {
  content: ''; position: absolute; left: 4px; top: 17px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
}
@media (max-width: 1040px) {
  .about-inner { grid-template-columns: 1fr; gap: 36px; padding-top: 72px; padding-bottom: 72px; }
  /* Stacked, the copy no longer sits in a left column, so the scrim has
     to work top-to-bottom instead of left-to-right. */
  .about-scrim { background: linear-gradient(180deg, rgba(5,7,15,.86) 0%, rgba(5,7,15,.70) 55%, rgba(5,7,15,.80) 100%); }
}

/* ---------- CAROUSEL (projects + reviews) ---------- */
.work { background: var(--paper-2); }
/* The projects run wider than the rest of the page and show two per view
   rather than three, which roughly doubles each card and stops the row
   floating in dead margin. */
.work > .container { max-width: 1560px; }
.work .tile { flex-basis: calc((100% - 28px) / 2); }
@media (max-width: 1040px) { .work .tile { flex-basis: calc((100% - 26px) / 2); } }
@media (max-width: 680px)  { .work .tile { flex-basis: 88%; } }
.carousel { position: relative; }
.car-track {
  display: flex; gap: 26px;
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-bottom: 4px;
}
.car-track::-webkit-scrollbar { display: none; }
@media (prefers-reduced-motion: reduce) { .car-track { scroll-behavior: auto; } }

.tile {
  flex: 0 0 calc((100% - 52px) / 3);
  margin: 0; scroll-snap-align: start;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
}
.tile img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.tile figcaption { display: block; padding: 18px 20px 22px; font-size: 16px; font-weight: 600; line-height: 1.35; color: var(--text); }
.tile-n { display: block; margin-bottom: 8px; font-size: 13px; font-weight: 600; color: var(--accent); }
.tile-loc { display: block; margin-top: 7px; font-size: 13px; font-weight: 400; color: var(--text-3); }

.car-nav {
  position: absolute; top: 32%; z-index: 3;
  width: 48px; height: 48px;
  display: none; align-items: center; justify-content: center;
  background: var(--paper); color: var(--text);
  border: 1px solid var(--line); border-radius: 999px;
  box-shadow: 0 6px 20px rgba(11,18,38,.12);
  transition: background-color .2s ease, color .2s ease, opacity .2s ease;
}
.carousel.is-ready .car-nav { display: flex; }
.car-nav:hover:not(:disabled) { background: var(--accent); color: #FFFFFF; border-color: var(--accent); }
.car-nav:disabled { opacity: .3; cursor: default; }
.car-nav svg { width: 20px; height: 20px; }
.car-prev { left: -20px; }
.car-next { right: -20px; }
.car-dots { display: none; justify-content: center; gap: 4px; margin-top: 20px; }
.carousel.is-ready .car-dots { display: flex; }
.car-dot { position: relative; width: 34px; height: 40px; padding: 0; background: transparent; border: none; }
.car-dot::before {
  content: ''; position: absolute; left: 3px; right: 3px; top: 50%;
  height: 3px; margin-top: -1.5px; border-radius: 2px;
  background: var(--line); transition: background-color .2s ease;
}
.car-dot[aria-current="true"]::before { background: var(--accent); }

@media (max-width: 1040px) { .tile { flex-basis: calc((100% - 26px) / 2); } }
@media (max-width: 680px) {
  .tile { flex-basis: 86%; }
  .car-track { gap: 16px; }
  .car-nav { display: none !important; }
}
@media (max-width: 1340px) and (min-width: 681px) { .car-prev { left: 6px; } .car-next { right: 6px; } }

/* ---------- STATS ---------- */
.stats { background: var(--ink); }
.stats-inner {
  padding-top: 56px; padding-bottom: 56px;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px;
}
.stat { text-align: center; }
.stat-v { margin: 0 0 8px; font-size: clamp(32px, 4.2vw, 48px); font-weight: 700; line-height: 1; color: var(--white); letter-spacing: -.02em; }
.stat-v span { color: var(--accent); }
.stat-l { margin: 0; font-size: 14px; color: var(--white-60); }
@media (max-width: 780px) { .stats-inner { grid-template-columns: repeat(2, 1fr); gap: 34px 20px; } }

/* ---------- REVIEWS ----------
   A side-scroller on the same carousel machinery as the projects, per
   the Addicted to Color pattern. */
.reviews { background: var(--paper); }
.review {
  position: relative;
  /* Two per view, not three. The longest testimonial is ~90 words against
     ~20 for the shortest, and in a narrow column that gap becomes 200px of
     dead space in every short card. A wider column wraps it into roughly
     half the lines, which closes most of the difference without truncating
     anybody's words. */
  flex: 0 0 calc((100% - 26px) / 2);
  margin: 0; padding: 34px 30px 28px;
  scroll-snap-align: start;
  background: var(--paper);
  border: 1px solid var(--line);
  /* Near-square, not pill-soft — these sit between two heavily rounded
     sections and the change of shape is what stops them reading as more
     of the same. */
  border-radius: 4px;
  display: flex; flex-direction: column;
  transition: border-color .25s ease, box-shadow .25s ease;
}
/* A short accent tick on the top edge, and an oversized quote glyph sunk
   into the background. Two quiet marks, nothing more — the cards still
   have to read as testimony, not as decoration. */
.review::before {
  content: '';
  position: absolute; top: -1px; left: -1px;
  width: 48px; height: 3px;
  background: var(--accent);
}
.review::after {
  content: '\201C';
  position: absolute; top: 6px; right: 22px;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 76px; line-height: 1; font-weight: 700;
  color: var(--accent); opacity: .16;
  pointer-events: none;
}
.review:hover { border-color: var(--accent); box-shadow: 0 12px 34px rgba(11,18,38,.09); }
@media (max-width: 680px) { .review { flex-basis: 88%; } }
.rv-title {
  position: relative; z-index: 1;
  margin: 0 0 14px; padding-right: 42px;   /* clears the quote glyph */
  font-size: 17px; font-weight: 600; line-height: 1.3;
  letter-spacing: -.01em; color: var(--text);
}
/* Capped at 6 lines. Carousel cards stretch to the tallest, and the longest
   testimonial is ~90 words against ~20 for the shortest — on a phone that one
   card was setting a ~1100px height and every other card became a void. At
   the desktop 2-up width nothing actually reaches 6 lines, so this only bites
   on narrow screens, where a 90-word block is a wall of text regardless. The
   ellipsis makes the truncation visible rather than silent. */
.review blockquote {
  margin: 0; font-size: 15.5px; line-height: 1.75; color: var(--text-2);
  display: -webkit-box;
  -webkit-line-clamp: 6;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Pinned to the bottom: cards stretch to the tallest, and without this the
   shorter ones trail off instead of closing. */
.review figcaption {
  margin-top: auto; padding-top: 18px;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  border-top: 1px solid var(--line);
}
.rv-name { font-size: 14px; font-weight: 600; color: var(--text); }
.rv-name::before {
  content: ''; display: inline-block;
  width: 7px; height: 7px; margin-right: 9px;
  background: var(--accent);
}
.rv-meta { font-size: 13px; color: var(--text-3); margin-left: auto; }

/* ---------- FAQ ---------- */
.faq { background: var(--paper-2); }
.faq-list { max-width: 860px; }
.faq-item { border-bottom: 1px solid var(--line); }
.faq-item:first-child { border-top: 1px solid var(--line); }
.faq-q {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 22px 0;
  font-size: 17px; font-weight: 600; text-align: left;
  color: var(--text); background: transparent; border: none;
}
.faq-q:hover { color: var(--accent); }
.plus { position: relative; flex: 0 0 auto; width: 15px; height: 15px; }
.plus::before, .plus::after { content: ''; position: absolute; background: var(--accent); transition: transform .25s ease; }
.plus::before { top: 6.5px; left: 0; width: 15px; height: 2px; }
.plus::after { left: 6.5px; top: 0; width: 2px; height: 15px; }
.faq-q[aria-expanded="true"] .plus::after { transform: scaleY(0); }
/* visibility, not just max-height: a clipped panel stays in the
   accessibility tree and gets read out. */
/* .js-gated: only collapse once the script that can re-open it is
   running. Otherwise every answer is hidden with no working control. */
.js .faq-a { max-height: 0; overflow: hidden; visibility: hidden; transition: max-height .3s ease, visibility 0s linear .3s; }
.js .faq-q[aria-expanded="true"] + .faq-a { visibility: visible; transition: max-height .3s ease, visibility 0s linear 0s; }
.faq-a p { margin: 0 0 22px; font-size: 16px; line-height: 1.75; color: var(--text-2); max-width: 68ch; }

/* ---------- CTA ---------- */
.cta { position: relative; overflow: hidden; background: var(--ink); }
.cta video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Started at .88/.80 — a wash that buried the footage entirely. Now down
   to roughly a fifth of that, with legibility carried by text-shadow. */
.cta-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(5,7,15,.14) 0%, rgba(5,7,15,.26) 50%, rgba(5,7,15,.22) 100%);
}
.cta-inner { position: relative; z-index: 2; padding-top: 120px; padding-bottom: 120px; text-align: center; }
.cta-inner .display { color: var(--white); text-shadow: 0 2px 26px rgba(0,0,0,.62); }
.cta-inner .label { text-shadow: 0 1px 14px rgba(0,0,0,.6); }
.cta-lede { margin: 22px auto 34px; color: rgba(255,255,255,.92); text-shadow: 0 1px 16px rgba(0,0,0,.62); }
.cta-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px; }
@media (max-width: 680px) {
  .cta-inner { padding-top: 76px; padding-bottom: 76px; }
  .cta-actions { flex-direction: column; }
}

/* ---------- FOOTER ----------
   Gradient plus noise, never a flat dark fill: a perfectly flat dark
   panel is what a spatial-dithering display pipeline latches onto, and
   it surfaces as a faint diagonal hairline across the whole band. */
.footer { position: relative; background: linear-gradient(180deg, var(--ink-2) 0%, var(--ink-deep) 100%); color: var(--white-80); }
.noise-overlay {
  position: absolute; inset: 0; pointer-events: none;
  opacity: .035; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/></svg>");
}
.footer-inner { position: relative; z-index: 1; padding-top: 76px; }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1.3fr 1fr; gap: 44px; }
.footer-brand img { height: 72px; width: auto; margin-bottom: 18px; }
.footer-brand p { margin: 0 0 14px; font-size: 14.5px; line-height: 1.75; max-width: 40ch; }
.footer-reg { font-size: 13px; color: var(--white-60); }
.footer h3 { margin: 0 0 16px; font-size: 14px; font-weight: 600; color: var(--accent); }
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
/* njindooroutdoormaintenance@gmail.com is 35 unbroken characters. Left
   alone it sets a min-content floor wider than a 320px phone, the grid
   column refuses to shrink past it, and the whole document goes 16px
   wide — which the fixed nav then stretches to match. */
.footer li { font-size: 14.5px; line-height: 1.5; overflow-wrap: anywhere; }
.footer-grid > * { min-width: 0; }
.footer a { transition: color .2s ease; }
.footer a:hover { color: var(--accent); }
/* 28 town names. As a list it would be a wall; as a single wrapped
   paragraph at reduced contrast it reads as the SEO footprint it is. */
.footer-areas { margin-top: 48px; padding-top: 34px; border-top: 1px solid rgba(255,255,255,.12); }
.footer-areas p {
  margin: 0; max-width: 96ch;
  font-size: 13.5px; line-height: 2; color: var(--white-60);
}

.footer-bottom {
  margin-top: 40px; padding: 22px 0 30px;
  border-top: 1px solid rgba(255,255,255,.12);
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px;
  font-size: 13px; color: var(--white-60);
}
@media (max-width: 1040px) { .footer-grid { grid-template-columns: 1fr 1fr; gap: 36px; } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; gap: 30px; } }

/* ---------- MOBILE STICKY CTAs ----------
   Two floating pills, not a full-width panel. The container itself is
   transparent — only the pills have a surface. */
.mobile-cta {
  position: fixed; left: 14px; right: 14px; z-index: 90;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  display: none; gap: 10px;
  background: transparent;
  transform: translateY(calc(100% + 24px));
  transition: transform .32s cubic-bezier(.22,.61,.36,1), opacity .32s ease;
  opacity: 0;
}
.mobile-cta.show { transform: translateY(0); opacity: 1; }
.mobile-cta a {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 54px; padding: 0 14px;
  font-size: 15px; font-weight: 600;
  border-radius: 999px;
  box-shadow: 0 12px 30px rgba(0,0,0,.42);
}
.mobile-cta svg { width: 18px; height: 18px; }
.mc-call { background: var(--accent); color: #FFFFFF; }
.mc-quote { background: rgba(11,18,38,.94); color: var(--white); border: 1px solid rgba(255,255,255,.24); backdrop-filter: blur(8px); }
@media (max-width: 900px) {
  .mobile-cta { display: flex; }
  /* Reserve the pills' height so they can never cover the last of the
     footer, even though they hide there. */
  body { padding-bottom: 82px; }
}

/* ---------- Reveal ----------
   Default VISIBLE; site.js opts in via .js-reveal on <html>, so a no-JS
   or JS-error visitor gets a finished page rather than a blank one. */
.reveal { opacity: 1; transform: none; }
.js-reveal .reveal { opacity: 0; transform: translateY(16px); transition: opacity .6s ease, transform .6s cubic-bezier(.22,.61,.36,1); }
.js-reveal .reveal.in { opacity: 1; transform: none; }

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .js-reveal .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  .card:hover { transform: none; }
  .card:hover .card-media img { transform: none; }
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}
