/* ── Icons ──────────────────────────────────────────────────────────────
   <svg class="ic"><use href="#i-name"/></svg> against the per-page <symbol> sprite
   inlined by generate-icons.mjs from the vendored icons/ folder. No CDN, no JS.
   Stroke props live here once; inner fill attrs (e.g. star-filled) still win. */
.ic {
  width: 1em; height: 1em;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* the client — shared site styles
 * Layered on top of colors_and_type.css.
 * Layouts and components shared across homepage variants and service pages.
 */

*, *::before, *::after { box-sizing: border-box; }
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; }

/* Prevent stray horizontal overflow on mobile from any element that
   forgets a max-width. Belt-and-suspenders alongside container rules. */
html, body { overflow-x: clip; }

/* Body lock while the mobile menu is open. */
body.menu-open-lock { overflow: hidden; }

/* ── Container ────────────────────────────────────────────────────── */
.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--container-pad-x-desk);
}
@media (max-width: 900px) {
  .container { padding: 0 var(--container-pad-x-tab); }
}
@media (max-width: 640px) {
  .container { padding: 0 var(--container-pad-x-mob); }
}

/* ── Promo bar ────────────────────────────────────────────────────── */
.promo-bar {
  background-image: var(--gradient-brand-dark);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 0.55rem 0;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}
.promo-bar .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--color-brand-secondary);
  display: inline-block;
  box-shadow: 0 0 0 0 rgba(150,192,225,0.6);
  animation: pulse 1.8s ease-out infinite;
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(150,192,225,0.55); }
  70% { box-shadow: 0 0 0 8px rgba(150,192,225,0); }
  100% { box-shadow: 0 0 0 0 rgba(150,192,225,0); }
}

/* ── Navbar ───────────────────────────────────────────────────────── */
.nav-wrap {
  position: sticky; top: 0; z-index: 50;
}
.navbar {
  position: relative;
  z-index: 10;  /* sit above the mobile menu panel inside .nav-wrap */
  background-color: var(--color-glass-bg);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--color-border-subtle);
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 140px;
}
.nav-logo img { height: 96px; width: auto; }
.nav-links {
  display: flex; align-items: center; gap: 2.4rem;
  list-style: none; margin: 0; padding: 0;
}
.nav-links > li { position: relative; }
.nav-links a {
  font-size: 15.5px;
  font-weight: 600;
  color: var(--color-text-secondary);
  letter-spacing: -0.005em;
  transition: color 0.2s ease;
  display: inline-flex; align-items: center; gap: 4px;
}
.nav-links a:hover { color: var(--color-text-primary); }
.nav-links .chev {
  width: 16px; height: 16px; opacity: 0.6;
  transition: transform 200ms var(--ease-out);
}
.nav-links .has-dropdown:hover > a .chev,
.nav-links .has-dropdown.open > a .chev {
  transform: rotate(180deg);
}

/* Dropdown menu — opens below trigger, always light-themed so it
   reads cleanly against both light and dark hero navbars. */
.nav-links .dropdown {
  position: absolute;
  top: 100%;
  left: -0.75rem;
  min-width: 260px;
  background: #fff;
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-menu);
  padding: 0.5rem;
  margin-top: 0.5rem;
  list-style: none;
  display: flex; flex-direction: column;
  gap: 2px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 200ms var(--ease-out),
              transform 200ms var(--ease-out),
              visibility 200ms;
  z-index: 60;
}
.nav-links .has-dropdown:hover > .dropdown,
.nav-links .has-dropdown:focus-within > .dropdown,
.nav-links .has-dropdown.open > .dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* Dropdown items live on a light surface and must render dark text
   even when the parent nav is in overlay (white-on-hero) state. We
   anchor the selector on `.dropdown` so the same rule wins regardless
   of which nav variant is rendering above. */
.nav-links .dropdown li a,
.nav-wrap.nav-overlay .nav-links .dropdown li a,
.nav-wrap.nav-overlay.is-solid .nav-links .dropdown li a,
.svc-hero-wrap .nav-links .dropdown li a {
  display: block;
  padding: 0.7rem 0.9rem;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-text-body);
  border-radius: var(--radius-sm);
  letter-spacing: -0.005em;
  transition: background 0.15s ease, color 0.15s ease;
}
.nav-links .dropdown li a:hover,
.nav-wrap.nav-overlay .nav-links .dropdown li a:hover,
.nav-wrap.nav-overlay.is-solid .nav-links .dropdown li a:hover,
.svc-hero-wrap .nav-links .dropdown li a:hover {
  background: var(--color-surface-subtle);
  color: var(--color-brand-primary-700);
}

.nav-cta {
  display: flex; align-items: center; gap: 0.75rem;
}
.nav-phone {
  font-weight: 700; font-size: 15px;
  color: var(--color-brand-primary-700);
  display: inline-flex; align-items: center; gap: 6px;
}
.nav-phone svg { width: 16px; height: 16px; }

/* Phone-as-button variant — outline button with transparent fill,
   used in service-page navs so the call CTA reads as a button rather
   than a bare link. Same visual weight as the secondary "See How It
   Works" button. */
.btn.nav-phone-btn {
  padding: 0.7rem 1.25rem;
  font-size: 14.5px;
  border-radius: var(--radius-button);
  background: transparent;
  color: var(--color-brand-primary-700);
  border: 1px solid var(--color-border-default);
}
.btn.nav-phone-btn:hover {
  border-color: var(--color-brand-primary);
  background: rgba(10,37,65,0.04);
  color: var(--color-brand-primary-700);
}
.btn.nav-phone-btn svg { width: 16px; height: 16px; }

/* Overlay nav (homepage hero over dark video): flip the phone button
   to white-on-transparent with a white outline. No hover change while
   the video is visible. Reverts to the default navy state once the
   nav goes solid on scroll. */
.nav-wrap.nav-overlay .btn.nav-phone-btn,
.nav-wrap.nav-overlay .btn.nav-phone-btn:hover {
  background: transparent;
  border-color: var(--color-white-outline);
  color: #fff;
}
.nav-wrap.nav-overlay.is-solid .btn.nav-phone-btn {
  border-color: var(--color-brand-primary);
  color: var(--color-brand-primary-700);
}
.nav-wrap.nav-overlay.is-solid .btn.nav-phone-btn:hover {
  background: rgba(10,37,65,0.04);
  border-color: var(--color-brand-primary);
  color: var(--color-brand-primary-700);
}

/* Outline nav CTA — adapts to nav state. White outline + translucent
   white hover over the dark hero; flips to brand-navy outline + tinted
   hover once the nav goes solid on scroll. Matches the hero's
   "See How It Works" ghost button. */
.btn.nav-cta-outline {
  background: transparent;
  border: 1px solid var(--color-white-outline);
  color: #fff;
  padding: 0.7rem 1.25rem;
  font-size: 14.5px;
}
.btn.nav-cta-outline svg { width: 16px; height: 16px; }
.btn.nav-cta-outline:hover {
  background: var(--color-white-border);
  border-color: #fff;
  color: #fff;
}
.nav-wrap.nav-overlay.is-solid .btn.nav-cta-outline {
  border-color: var(--color-brand-primary);
  color: var(--color-brand-primary-700);
}
.nav-wrap.nav-overlay.is-solid .btn.nav-cta-outline:hover {
  background: rgba(10,37,65,0.08);
  border-color: var(--color-brand-primary);
  color: var(--color-brand-primary-700);
}

/* ── Buttons ──────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1.5rem;
  border-radius: var(--radius-button);
  font-size: var(--font-size-button);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.3s var(--ease-brand);
  border: none;
}
.btn svg { width: 18px; height: 18px; }
.btn-sm {
  padding: 0.75rem 1.35rem;
  font-size: 14.5px;
}
.btn-sm svg { width: 16px; height: 16px; }
.btn-lg {
  padding: 1.05rem 1.85rem;
  font-size: 1.0625rem;
}

/* Brand CTA — light logo gradient (sky → pale, diagonal) with deep-ink
   label. Light gradient is the dominant button treatment site-wide;
   dark gradients are reserved for section backgrounds. */
.btn-brand {
  background-image: var(--gradient-brand);
  color: var(--color-brand-secondary);
  box-shadow: 0 4px 14px -4px rgba(10,37,65,0.35);
}
.btn-brand:hover {
  filter: brightness(1.04);
  box-shadow: 0 12px 28px -8px rgba(10,37,65,0.45);
  transform: translateY(-1px);
}
.btn-brand svg { stroke: var(--color-brand-secondary); }
/* Primary accent CTA — same light gradient + dark label. Legacy class
   name kept to avoid HTML churn; visually equivalent to .btn-brand and
   .btn-soft, just with a heavier shadow for prominence. */
.btn-accent {
  background-image: var(--gradient-brand);
  color: var(--color-brand-secondary);
  box-shadow: 0 8px 22px -8px rgba(10,37,65,0.55);
}
.btn-accent:hover {
  filter: brightness(1.04);
  box-shadow: 0 12px 28px -8px rgba(10,37,65,0.65);
  transform: translateY(-1px);
}
.btn-accent svg { stroke: var(--color-brand-secondary); }
.btn-secondary {
  background: #fff;
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-default);
}
.btn-secondary:hover {
  border-color: var(--color-brand-primary);
  color: var(--color-brand-primary-700);
  background: #fdfdff;
}
.btn-ghost {
  background: transparent;
  color: var(--color-text-primary);
  border: 1px solid var(--color-white-outline);
}
.btn-ghost.on-dark { color: #fff; }
.btn-ghost.on-dark:hover { background: var(--color-white-surface-hi); }

/* Light/logo-gradient CTA — sky → pale wash mirroring the logo badge.
   The background is light, so the label must be the deep brand ink. Pairs
   well with the dark hero so the button reads as a bright lift, not as
   another dark slab. */
.btn-soft {
  background-image: var(--gradient-brand);
  color: var(--color-brand-secondary);
  box-shadow: 0 8px 22px -8px rgba(10,37,65,0.35);
}
.btn-soft:hover {
  filter: brightness(1.04);
  box-shadow: 0 12px 28px -8px rgba(10,37,65,0.45);
  transform: translateY(-1px);
}
.btn-soft svg { stroke: var(--color-brand-secondary); }

/* ── Eyebrow pill ─────────────────────────────────────────────────── */
/* Eyebrow pill on light surfaces.
   Uses the logo sky tint as the chip fill, the deep ink as the text, and
   the deep brand-blue as the pulse dot — so the chip itself "wears the
   brand color" and the label still reads with strong contrast. */
.eyebrow-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--color-brand-primary-200);
  border: 1px solid var(--color-brand-primary-300);
  border-radius: var(--radius-pill);
  padding: 0.4rem 0.85rem 0.4rem 0.55rem;
  font-size: var(--font-size-eyebrow);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
  color: var(--color-brand-secondary);
  box-shadow: var(--shadow-subtle);
}
.eyebrow-pill .dot-wrap {
  position: relative;
  width: 8px; height: 8px;
}
.eyebrow-pill .dot-wrap .dot {
  position: absolute; inset: 0;
  background: var(--color-brand-primary);
  border-radius: 50%;
}
.eyebrow-pill .dot-wrap .ring {
  position: absolute; inset: 0;
  background: var(--color-brand-primary);
  border-radius: 50%;
  animation: pm-ping 1.5s cubic-bezier(0, 0, 0.2, 1) infinite;
}
/* Accent variant — uses deep brand-blue text (legacy `.green` class kept
   for HTML markup compatibility; styling is brand-blue, not green). */
.eyebrow-pill.green { color: var(--color-brand-primary-700); }
.eyebrow-pill.green .dot, .eyebrow-pill.green .ring { background: var(--color-brand-primary); }
.eyebrow-pill.on-dark {
  background: var(--color-white-surface-hi);
  border-color: var(--color-white-border);
  color: #fff;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.eyebrow-pill.on-dark .dot, .eyebrow-pill.on-dark .ring {
  background: var(--color-brand-primary);
}
@media (max-width: 640px) {
  .eyebrow-pill {
    padding: 0.3rem 0.65rem 0.3rem 0.45rem;
    font-size: 0.75rem;
    letter-spacing: 0.18em;
  }
}

/* ── Section heading block ────────────────────────────────────────── */
.section-heading {
  text-align: center;
  max-width: 760px;
  margin: 0 auto 4rem;
}
.section-heading .eyebrow-pill { margin-bottom: 1.5rem; }
.section-heading h1, .section-heading h2 { margin-bottom: 1.25rem; }
.section-heading .t-lead {
  text-wrap: pretty;
}

/* ── Star rating ──────────────────────────────────────────────────── */
.stars {
  display: inline-flex; gap: 2px;
  color: var(--color-accent-gold);
}
.stars svg { width: 16px; height: 16px; fill: currentColor; }

/* ── Card ─────────────────────────────────────────────────────────── */
.card {
  background: var(--color-surface-card);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  padding: 2.5rem;
  transition: all 0.5s ease;
}
.card:hover {
  box-shadow: var(--shadow-card-hover);
  border-color: var(--color-border-brand-30);
  transform: translateY(-4px);
}
.card .icon-chip {
  width: 48px; height: 48px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-subtle);
  color: var(--color-brand-primary-700);
  display: inline-flex; align-items: center; justify-content: center;
  margin-bottom: 1.5rem;
}
.card .icon-chip.green {
  background: var(--color-surface-subtle-2);
  color: var(--color-brand-secondary);
}
.card .icon-chip svg { width: 24px; height: 24px; }
.card h3 { margin-bottom: 0.75rem; font-size: 1.5rem; }
.card p { font-size: 1rem; }

/* ── Footer ───────────────────────────────────────────────────────── */
/* Uses the same dark gradient as every other dark band, so the footer
   reads as the continuation of the brand-blue family rather than a
   separate navy.
   Text colour rule (QA 8 Sep 2026): the footer is a DARK surface, so
   every label in it takes a white-alpha token. It used to reuse
   --color-text-tertiary / --color-text-secondary, which are slate greys
   scaled for WHITE backgrounds — on the dark band they measured
   1.1–2.8:1. Never reach for --color-text-* inside .footer. */
.footer {
  background-color: var(--color-brand-primary-950);
  background-image: var(--gradient-brand-dark);
  color: rgba(255,255,255,0.78);
  padding: 5rem 0 2.5rem;
}
.footer h4 {
  color: #fff;
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  margin: 0 0 1.25rem;
}
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { margin-bottom: 0.6rem; }
.footer a { font-size: 0.9375rem; color: var(--color-white-text-muted); transition: color 0.2s; }
.footer a:hover { color: #fff; }
.footer .footer-static li { font-size: 0.9375rem; color: var(--color-white-text-muted); }
/* Buttons keep their own label colour. `.footer a` (0,1,1) out-specifies
   `.btn-accent` (0,1,0), which is why the footer CTA rendered as grey
   text on a near-white pill (~1.5:1) — QA 8 Sep 2026. */
.footer a.btn,
.footer a.btn:hover { color: var(--color-brand-secondary); }
.footer a.btn svg { stroke: var(--color-brand-secondary); }
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr 1.2fr;
  gap: 3rem;
  padding-bottom: 3rem;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.footer-grid .brand img { height: 96px; width: auto; margin-bottom: 1.5rem; }
.footer-grid .brand p { color: var(--color-white-text-muted); font-size: 0.9375rem; max-width: 28ch; }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  padding-top: 2rem;
  font-size: 0.8125rem;
  /* space-between drops Privacy / Terms / Sitemap on the lightest end of
     the sweep, so this row needs the strongest of the muted tokens. */
  color: var(--color-white-text-muted);
}
.footer-bottom a { font-size: inherit; }
.footer-bottom .legal { display: flex; gap: 1.5rem; }

/* ── Fade-up animation on scroll ──────────────────────────────────── */
.fade-up {
  opacity: 0;
  transform: translateY(32px);
  transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out);
  will-change: opacity, transform;
}
.fade-up.in {
  opacity: 1;
  transform: translateY(0);
}
/* Gentler variant for tight rows of cards / small text blocks. */
.fade-up.soft {
  transform: translateY(18px);
  transition-duration: 0.8s;
}
/* `.fade-up.soft` and `.fade-up.in` have equal specificity, so without
   this rule the later `.soft` declaration would pin the element at
   +18px even after fade-in — turning small hover lifts into 20px+
   jumps. Restore the intended landing position. */
.fade-up.soft.in { transform: translateY(0); }
/* Cascade children with a small per-row delay so a grid of cards
   reveals row-by-row instead of landing as a block. Apply `.stagger`
   on the parent, `.fade-up` on each child. */
.stagger > .fade-up:nth-child(1) { transition-delay: 0ms; }
.stagger > .fade-up:nth-child(2) { transition-delay: 80ms; }
.stagger > .fade-up:nth-child(3) { transition-delay: 160ms; }
.stagger > .fade-up:nth-child(4) { transition-delay: 240ms; }
.stagger > .fade-up:nth-child(5) { transition-delay: 320ms; }
.stagger > .fade-up:nth-child(6) { transition-delay: 400ms; }
.stagger > .fade-up:nth-child(7) { transition-delay: 480ms; }
.stagger > .fade-up:nth-child(8) { transition-delay: 560ms; }

@media (prefers-reduced-motion: reduce) {
  .fade-up, .fade-up.soft {
    transform: none !important;
    transition: opacity 0.3s ease !important;
    transition-delay: 0ms !important;
  }
}

/* ── Comparison table ─────────────────────────────────────────────── */
/* Three-column "feature vs. competitor vs. brand" table with a
   gradient-filled brand header cell. Pages set their own column
   labels and row contents; this owns the visual chrome. */
.compare {
  background: #fff;
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-card-lg);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.compare-row {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr;
  align-items: center;
  border-bottom: 1px solid var(--color-border-subtle);
}
.compare-row:last-child { border-bottom: 0; }
.compare-row > div { padding: 1.25rem 2rem; }
.compare-row.head > div {
  padding: 1.75rem 2rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-weight: 800;
  color: var(--color-text-secondary);
  background: var(--color-surface-app);
  border-bottom: 1px solid var(--color-border-default);
  text-align: center;
}
.compare-row.head > div:first-child {
  text-align: left;
}
.compare-row.head .ours {
  color: #fff;
  border-bottom-color: var(--color-brand-primary);
  position: relative;
}
.compare-row.head .ours::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--gradient-brand-deep);   /* Header cell carries white text — needs the dark variant for legibility. */
  z-index: 0;
}
.compare-row.head .ours span { position: relative; z-index: 1; }
.compare-row .feature {
  font-weight: 700;
  color: var(--color-text-primary);
  font-size: 1rem;
  letter-spacing: -0.01em;
}
.compare-row .feature small {
  display: block;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  font-weight: 500;
  margin-top: 0.25rem;
}
.compare-row .cell {
  font-size: 0.9375rem;
  color: var(--color-text-body);
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
}
.compare-row .check {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--color-surface-subtle-2);
  color: var(--color-brand-secondary);
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.compare-row .check svg { width: 14px; height: 14px; }
.compare-row .x {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: #fff1f3;
  color: var(--color-status-danger);
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.compare-row .x svg { width: 14px; height: 14px; }
.compare-row .ours {
  background: linear-gradient(180deg, rgba(10,37,65,0.025), transparent);
  border-left: 1px solid var(--color-border-subtle);
}
.compare-row .ours .check { background: var(--color-brand-secondary); color: #fff; }
/* When a compare row is also a fade-up target, only opacity should
   animate — sliding a table row reads as broken. */
.compare-row.fade-up { transform: none; }

/* ── Stat utility ─────────────────────────────────────────────────── */
/* Big gradient-text number recipe used in hero trust stats, review
   aggregate, testimonial result rows, and stage numerals. Page sets
   font-size; this owns the weight, tracking, and gradient fill. */
.t-stat {
  font-weight: 900;
  letter-spacing: -0.04em;
  line-height: 1;
  background-image: var(--gradient-brand-deep);
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
.t-stat.accent {
  background-image: var(--gradient-accent);
}

/* ── Reviews carousel ─────────────────────────────────────────────── */
/* ── Review card (used inside the reviews carousel) ───────────── */
.svc-review {
  background: #fff;
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  padding: 2rem;
  display: flex; flex-direction: column;
  gap: 1.25rem;
  transition: all 0.4s var(--ease-brand);
}
.svc-review:hover {
  box-shadow: var(--shadow-card);
  border-color: var(--color-border-brand-30);
  transform: translateY(-4px);
}
.svc-review .stars { color: var(--color-accent-gold); display: flex; gap: 2px; }
.svc-review .stars svg { width: 16px; height: 16px; fill: currentColor; }
.svc-review blockquote {
  margin: 0;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--color-text-primary);
  font-weight: 500;
  letter-spacing: -0.005em;
  text-wrap: pretty;
  flex: 1;
  /* Clamp to 6 lines: real GBP reviews run 80-1200 chars, and one long review
     otherwise stretches every card in the row (QA 28 Jul). Full text stays in the
     DOM; the reviews page shows it unclamped. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
          line-clamp: 6;
  overflow: hidden;
}
.reviews-wall .svc-review blockquote { display: block; -webkit-line-clamp: none; line-clamp: none; overflow: visible; }
.svc-review .meta {
  display: flex; align-items: center; gap: 0.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--color-border-subtle);
}
.svc-review .avatar {
  width: 36px; height: 36px;
  background: var(--color-surface-subtle);
  color: var(--color-brand-primary-700);
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 0.8125rem;
  flex: 0 0 auto;
}
.svc-review .name { font-size: 0.9375rem; font-weight: 700; color: var(--color-text-primary); }
.svc-review .where { font-size: 0.8125rem; color: var(--color-text-secondary); }
.svc-review .verified {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.75rem;
  font-weight: 800;
  color: var(--color-brand-secondary);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.svc-review .verified svg { width: 11px; height: 11px; }

/* Horizontal scroll-snap track with arrow nav. Three cards visible on
   desktop, two on tablet, one on mobile. Arrows scroll one card at a
   time and disable at the ends. */
.reviews-carousel { position: relative; }
.reviews-carousel .carousel-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 2 * 1.25rem) / 3);
  gap: 1.25rem;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  padding: 0.5rem 0 1rem;
}
.reviews-carousel .carousel-track::-webkit-scrollbar { display: none; }
.reviews-carousel .carousel-track > * { scroll-snap-align: start; }
.reviews-carousel .carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px; height: 48px;
  background: #fff;
  border: 1px solid var(--color-border-default);
  border-radius: 50%;
  color: var(--color-text-primary);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow-card);
  z-index: 2;
  transition: all 0.3s var(--ease-brand);
}
.reviews-carousel .carousel-arrow:hover {
  border-color: var(--color-brand-primary);
  color: var(--color-brand-primary-700);
}
.reviews-carousel .carousel-arrow:disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}
.reviews-carousel .carousel-arrow svg { width: 20px; height: 20px; }
.reviews-carousel .carousel-arrow.prev { left: -24px; }
.reviews-carousel .carousel-arrow.next { right: -24px; }
@media (max-width: 900px) {
  .reviews-carousel .carousel-track { grid-auto-columns: calc((100% - 1rem) / 2); }
}
@media (max-width: 640px) {
  .reviews-carousel .carousel-track { grid-auto-columns: 100%; }
  /* Arrows would overlap card content at this width — rely on
     scroll-snap touch behavior and hide them. */
  .reviews-carousel .carousel-arrow { display: none; }
}

/* ── Why the client reasons grid ────────────────────────────────────── */
.why-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
}
.why-card {
  background: #fff;
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  padding: 2.25rem 1.75rem;
  display: flex; flex-direction: column; gap: 0.75rem;
  transition:
    transform 0.3s var(--ease-out),
    box-shadow 0.3s var(--ease-out),
    border-color 0.3s var(--ease-out);
}
.why-card.fade-up.soft:hover {
  border-color: var(--color-border-brand-30);
  background:
    linear-gradient(#fff, #fff) padding-box,
    var(--gradient-brand) border-box;
  box-shadow: 0 14px 26px -18px rgba(10,37,65,0.28);
  transform: translateY(-4px);
}
.why-card .icon-chip {
  width: 48px; height: 48px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-subtle);
  color: var(--color-brand-primary-700);
  display: inline-flex; align-items: center; justify-content: center;
  margin-bottom: 0.5rem;
  transition: background 0.35s var(--ease-brand), color 0.35s var(--ease-brand);
}
.why-card .icon-chip.accent {
  background: var(--color-surface-subtle-2);
  color: var(--color-brand-secondary);
}
.why-card.fade-up.soft:hover .icon-chip {
  background: var(--gradient-brand);   /* 48px chip — light variant; dark icon for legibility. */
  color: var(--color-brand-secondary);
}
.why-card .icon-chip svg { width: 22px; height: 22px; }
.why-card h3 {
  font-size: 1.125rem;
  letter-spacing: -0.02em;
  margin: 0;
}
.why-card p {
  font-size: 0.9375rem;
  color: var(--color-text-secondary);
  margin: 0;
  line-height: 1.55;
}
@media (max-width: 1100px) { .why-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .why-grid { grid-template-columns: 1fr; } }

/* ── Service areas + map ─────────────────────────────────────────── */
/* Shared across homepage and service pages. Two-column grid: stacked
   area rows on the left, embedded Google Map on the right with a
   floating overlay badge. */
.svc-areas-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 3rem;
  align-items: stretch;
}
.svc-areas-list {
  display: grid; gap: 0.75rem;
  align-content: start;
}
.svc-area-row {
  background: #fff;
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  padding: 1.75rem;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 1rem;
  align-items: start;
  transition: all 0.4s ease;
}
.svc-area-row:hover {
  border-color: var(--color-border-brand-30);
  box-shadow: var(--shadow-card);
}
.svc-area-row .name {
  font-size: 1.25rem;
  font-weight: 900;
  letter-spacing: -0.02em;
  color: var(--color-text-primary);
  margin-bottom: 0.5rem;
}
.svc-area-row .neighborhoods {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  line-height: 1.55;
}
.svc-area-row .pill {
  align-self: start;
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 0.35rem 0.65rem;
  background: var(--color-surface-subtle-2);
  color: var(--color-brand-secondary);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.svc-area-row .pill .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--color-brand-secondary);
}
.svc-map {
  border-radius: var(--radius-card-lg);
  overflow: hidden;
  box-shadow: var(--shadow-image);
  position: relative;
  min-height: 460px;
  background: var(--color-surface-subtle);
}
.svc-map iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
  filter: saturate(0.9) contrast(0.96);
}
.svc-map .map-overlay {
  position: absolute;
  bottom: 1.5rem; left: 1.5rem;
  background: #fff;
  padding: 1rem 1.25rem;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  display: flex; align-items: center; gap: 0.75rem;
  pointer-events: none;
}
.svc-map .map-overlay .pin {
  width: 32px; height: 32px;
  background-image: var(--gradient-brand);   /* 32px pin — light variant; dark icon for legibility. */
  color: var(--color-brand-secondary);
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.svc-map .map-overlay .pin svg { width: 16px; height: 16px; }
.svc-map .map-overlay .label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-weight: 800;
  color: var(--color-text-secondary);
}
.svc-map .map-overlay strong {
  font-size: 0.9375rem;
  color: var(--color-text-primary);
  font-weight: 800;
  letter-spacing: -0.01em;
}
@media (max-width: 1100px) {
  .svc-areas-grid { grid-template-columns: 1fr; }
}

/* ── Nav overlay (homepage) ───────────────────────────────────────── */
/* Used when the nav floats transparent over a hero video and then
   becomes solid on scroll. Service pages still use the default nav. */
.nav-wrap.nav-overlay {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  transition: background 350ms var(--ease-out),
              border-color 350ms var(--ease-out),
              backdrop-filter 350ms var(--ease-out);
}
.nav-wrap.nav-overlay .navbar {
  background: transparent;
  border-bottom: 1px solid transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.nav-wrap.nav-overlay .nav-links a { color: rgba(255,255,255,0.75); }
.nav-wrap.nav-overlay .nav-links a:hover { color: #fff; }
.nav-wrap.nav-overlay .nav-phone { color: #fff; }
.nav-wrap.nav-overlay .nav-logo .logo-dark { display: none; }
.nav-wrap.nav-overlay .nav-logo .logo-light { display: block; }
/* lift the logo off busy hero imagery while the nav is transparent */
.nav-wrap.nav-overlay:not(.is-solid) .nav-logo img { filter: drop-shadow(0 2px 12px rgba(9, 20, 35, 0.35)); }

.nav-wrap.nav-overlay.is-solid .navbar {
  background: var(--color-glass-bg);
  border-bottom-color: var(--color-border-subtle);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}
.nav-wrap.nav-overlay.is-solid .nav-links a { color: var(--color-text-secondary); }
.nav-wrap.nav-overlay.is-solid .nav-links a:hover { color: var(--color-text-primary); }
.nav-wrap.nav-overlay.is-solid .nav-phone { color: var(--color-brand-primary-700); }
.nav-wrap.nav-overlay.is-solid .nav-logo .logo-light { display: none; }
.nav-wrap.nav-overlay.is-solid .nav-logo .logo-dark { display: block; }

/* ── Section base (shared by homepage and service pages) ──────────── */
section.svc-section { padding: 7rem 0; position: relative; }
section.svc-alt     { background: var(--color-surface-section); }

/* ── Vapure section (video + intro), shared layout ────────────────── */
/* Used on homepage and service pages alike. Pages may override the
   media side (some show video, some show a photo with a play overlay)
   but the grid + copy rules are the same everywhere. */
.vapure {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 4rem;
  align-items: center;
}
.vapure-video {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-card-lg);
  overflow: hidden;
  box-shadow: var(--shadow-image-large);
  background: var(--color-brand-primary-900);
}
.vapure-video iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
  display: block;
}
.vapure-copy .eyebrow-pill { margin-bottom: 1.5rem; }
.vapure-copy h2            { margin-bottom: 1.5rem; text-wrap: balance; }
.vapure-copy .t-lead       { margin-bottom: 2rem; max-width: 56ch; }
.vapure-features {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
  display: grid; gap: 0.6rem;
}
.vapure-features li {
  display: flex; align-items: center; gap: 0.6rem;
  font-size: 0.9375rem;
  color: var(--color-text-body);
}
.vapure-features li svg {
  width: 18px; height: 18px;
  color: var(--color-brand-secondary);
  flex: 0 0 auto;
}
.vapure-cta-row { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
@media (max-width: 1100px) { .vapure { grid-template-columns: 1fr; } }

/* ── Dark-section grid overlay (paint via ::before) ───────────────── */
/* Add this class to any dark navy section that wants the subtle
   grid-pattern stamp + radial mask. Set --grid-opacity inline to tune
   if the section needs a more or less prominent overlay. */
.surface-grid-dark {
  position: relative;
  overflow: hidden;
}
.surface-grid-dark::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--color-white-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--color-white-grid) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, black 30%, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, black 30%, transparent 80%);
  pointer-events: none;
  opacity: var(--grid-opacity, 0.5);
}

/* ── Glass card on dark backgrounds ───────────────────────────────── */
/* Reusable recipe for cards that sit on navy/dark sections — used by
   .health-card, .b-closing-card, and similar one-off panels. */
.card-on-dark {
  background: var(--color-white-surface);
  border: 1px solid var(--color-white-border);
  border-radius: var(--radius-card);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition:
    transform 0.3s var(--ease-out),
    background 0.3s var(--ease-out),
    border-color 0.3s var(--ease-out);
}
/* Two selectors so the hover works both for plain cards and for
   `.fade-up.soft` cards. The 3-class form is needed because
   `.fade-up.soft.in` (0,2,0) would otherwise pin the transform after
   scroll-in. See memory: hover-on-fade-up-soft-cards. */
.card-on-dark:hover,
.card-on-dark.fade-up.soft:hover {
  background: var(--color-white-surface-hi);
  border-color: var(--color-white-border-hi);
  transform: translateY(-4px);
}

/* ── Dark navy section variant ────────────────────────────────────── */
/* Apply `.is-dark` (with `.surface-grid-dark` for the grid overlay) to
   any `.svc-section` that should sit on the brand navy band — used by
   the home-health "Why the client" intro on the homepage and service
   pages, the testing-options 3-up grid, the closing CTA, etc. */
.svc-section.is-dark {
  background-color: var(--color-brand-primary-950);
  background-image: var(--gradient-brand-dark);   /* Clean two-stop sweep — no overlays that introduce off-family tints. */
  color: #fff;
  --grid-opacity: 0.6;
}
.svc-section.is-dark .container { position: relative; }
.svc-section.is-dark .section-heading h1, .svc-section.is-dark .section-heading h2 { color: #fff; text-wrap: balance; }
.svc-section.is-dark .section-heading .t-lead{ color: var(--color-white-text-lead); }
.health-grid {
  display: grid;
  grid-template-columns: 1fr 1.35fr;
  gap: 4rem;
  align-items: start;
}
.health-intro h2 {
  text-wrap: balance;
  margin-bottom: 1.25rem;
  color: #fff;
}
.health-intro .t-lead {
  max-width: 42ch;
  color: var(--color-white-text-lead);
}
.health-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
/* `.health-card` inherits chrome from `.card-on-dark`. */
.health-card {
  display: flex;
  gap: 1.1rem;
  align-items: flex-start;
  padding: 1.6rem 1.5rem;
}
.health-icon {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  border-radius: var(--radius-md);
  background: rgba(150,192,225,0.22);
  color: var(--color-brand-primary-300);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.health-icon svg { width: 22px; height: 22px; }
.health-card h3 {
  font-size: 1.0625rem;
  letter-spacing: -0.015em;
  margin: 0 0 0.35rem;
  line-height: 1.25;
  color: #fff;
}
.health-card p {
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--color-white-text-muted);
  margin: 0;
}
/* Left column pins while the benefit cards scroll (post-PMM improvement from the
   NoMoldWNC / PAR-Utah builds). align-self:start is required — a stretched grid item
   is as tall as its track, which makes position:sticky a no-op. */
@media (min-width: 1101px) { .health-intro { align-self: start; position: sticky; top: 7rem; } }
@media (max-width: 1100px) { .health-grid { grid-template-columns: 1fr; } }
@media (max-width: 640px)  { .health-cards { grid-template-columns: 1fr; } }

/* ── "The Evidence" section · study cards ────────────────────────── */
/* Shared by index.html and mold-remediation.html. */
.studies {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}
.study {
  background: #fff;
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  padding: 2.25rem;
  display: flex; flex-direction: column; gap: 1rem;
  position: relative;
  overflow: hidden;
  transition: all 0.4s ease;
}
.study:hover {
  border-color: var(--color-border-brand-30);
  box-shadow: var(--shadow-card);
  transform: translateY(-4px);
}
.study::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 3px;
  background-image: var(--gradient-brand);
}
/* Full-bleed photo header — pulls against the card padding so the image
   meets the card edges; the card's overflow:hidden rounds the corners. */
.study-photo {
  margin: -2.25rem -2.25rem 0.5rem;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  position: relative;
}
.study-photo img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(15%);
  transition: transform 0.8s var(--ease-out), filter 0.6s var(--ease-out);
}
.study:hover .study-photo img {
  transform: scale(1.04);
  filter: grayscale(0%);
}
.study-photo .doc-tag {
  position: absolute;
  bottom: 0.85rem; left: 0.85rem;
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: rgba(255,255,255,0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-pill);
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-brand-primary-700);
  box-shadow: var(--shadow-subtle);
}
.study-photo .doc-tag svg { width: 12px; height: 12px; }
.study .meta-row {
  display: flex; align-items: center; gap: 0.75rem;
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--color-text-secondary);
}
.study .meta-row .journal {
  color: var(--color-brand-primary-700);
  padding: 0.35rem 0.7rem;
  background: var(--color-surface-subtle);
  border-radius: var(--radius-pill);
}
.study h3 {
  font-size: 1.1875rem;
  letter-spacing: -0.02em;
  line-height: 1.3;
  text-wrap: balance;
}
.study .finding {
  font-size: 0.9375rem;
  color: var(--color-text-body);
  line-height: 1.6;
  flex: 1;
}
.study .finding-stat {
  display: flex; align-items: baseline; gap: 0.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--color-border-subtle);
  margin-top: 0.5rem;
}
.study .finding-stat .num {
  font-size: 1.75rem;
  font-weight: 900;
  letter-spacing: -0.03em;
  background-image: var(--gradient-brand-deep);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
.study .finding-stat .lbl {
  font-size: 0.75rem;
  color: var(--color-text-secondary);
  font-weight: 600;
}
.study .source {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--color-brand-primary-700);
}
.study .source svg { width: 12px; height: 12px; }
.evidence-coda {
  text-align: center;
  margin-top: 2.5rem;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  font-style: italic;
  letter-spacing: -0.005em;
}
@media (max-width: 1100px) { .studies { grid-template-columns: 1fr 1fr; } }
@media (max-width: 720px)  { .studies { grid-template-columns: 1fr; } }

/* ── FAQ accordion ────────────────────────────────────────────────── */
/* Shared by faqs.html and the FAQ section on mold-remediation.html. */
.faq-list {
  max-width: 820px;
  margin: 0 auto;
  display: flex; flex-direction: column;
  gap: 0.75rem;
}
.faq-item {
  background: #fff;
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  overflow: hidden;
  transition: border-color 0.3s var(--ease-brand), box-shadow 0.3s var(--ease-brand);
}
.faq-item:hover { border-color: var(--color-border-default); }
.faq-q {
  width: 100%;
  background: none; border: 0; cursor: pointer;
  text-align: left;
  font: inherit;
  padding: 1.4rem 1.6rem;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  font-weight: 700;
  font-size: 1.0625rem;
  color: var(--color-text-primary);
  letter-spacing: -0.01em;
}
.faq-q .faq-icon {
  width: 20px; height: 20px;
  flex: 0 0 auto;
  color: var(--color-brand-primary-700);
  transition: transform 0.3s var(--ease-brand);
}
.faq-q.open .faq-icon { transform: rotate(180deg); }
.faq-a {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.4s var(--ease-brand);
}
.faq-a p {
  padding: 0 1.6rem 1.4rem;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--color-text-body);
}

/* ── Heading-after-eyebrow rhythm ─────────────────────────────────── */
/* Standard 1.5rem gap between an eyebrow-pill and the heading that
   immediately follows it. Replaces inline margin-top declarations
   scattered across pages. */
.eyebrow-pill + h1,
.eyebrow-pill + h2,
.eyebrow-pill + h3 { margin-top: 1.5rem; }

/* ── Inline body links ────────────────────────────────────────────── */
/* Long-form prose links (about, science, faqs) need underline
   affordance. Apply `.prose a` or use the class directly. */
.prose a,
a.body-link {
  border-bottom: 1px dotted var(--color-border-brand-30);
  transition: color 0.2s ease, border-color 0.2s ease;
}
.prose a:hover,
a.body-link:hover {
  color: var(--color-brand-primary-700);
  border-bottom-color: var(--color-brand-primary);
}

/* ── Footer phone CTA ─────────────────────────────────────────────── */
/* The footer phone number is the loudest legal/contact mark in the
   footer. Replaces an inline style="" repeated across every page. */
.footer .footer-static li.phone {
  color: #fff;
  font-weight: 800;
  font-size: 1.125rem;
  letter-spacing: -0.02em;
}
.footer .footer-static li.book-cta { margin-top: 1rem; }
.footer .footer-static li.book-cta .btn { margin-top: 0.5rem; }

/* ── Form input focus ring on dark sections ───────────────────────── */
.form-on-dark input,
.form-on-dark textarea {
  background: var(--color-white-surface-hi);
  border: 1px solid var(--color-white-border);
  border-radius: var(--radius-md);
  padding: 0.95rem 1.1rem;
  color: #fff;
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.form-on-dark input::placeholder,
.form-on-dark textarea::placeholder { color: rgba(255,255,255,0.45); }
.form-on-dark input:focus,
.form-on-dark textarea:focus {
  outline: none;
  border-color: rgba(255,255,255,0.4);
  box-shadow: 0 0 0 3px rgba(255,255,255,0.1);
}

/* ── Hamburger toggle (mobile/tablet nav) ─────────────────────────── */
/* The button is rendered on every nav by site.js at runtime. It sits in
   `.nav-inner` after the desktop CTAs and is hidden on desktop. */
.nav-toggle {
  display: none;
  background: none;
  border: 0;
  cursor: pointer;
  width: 44px; height: 44px;
  padding: 0;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
  color: var(--color-text-primary);
  transition: color 0.2s ease;
}
.nav-toggle span {
  display: block;
  width: 26px; height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform 0.3s var(--ease-brand), opacity 0.2s ease;
}
.nav-wrap.menu-open .nav-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-wrap.menu-open .nav-toggle span:nth-child(2) { opacity: 0; }
.nav-wrap.menu-open .nav-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* On the homepage overlay variant, the toggle sits over the dark video
   hero — flip it to white. Goes back to navy once the nav scrolls solid. */
.nav-wrap.nav-overlay .nav-toggle { color: #fff; }
.nav-wrap.nav-overlay.is-solid .nav-toggle { color: var(--color-text-primary); }
.nav-wrap.nav-overlay.menu-open .nav-toggle { color: var(--color-text-primary); }

/* ── Mobile menu panel (≤900px) ───────────────────────────────────── */
/* Slides down from below the navbar. Content is generated by site.js
   from the desktop nav structure so this CSS only owns presentation. */
.nav-mobile-panel {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: var(--color-surface-app);
  padding: calc(var(--nav-height, 72px) + 1.5rem) 1.5rem 2rem;
  overflow-y: auto;
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform 0.4s var(--ease-brand), visibility 0s linear 0.4s;
  z-index: 5;  /* below the navbar inside .nav-wrap so the toggle stays clickable */
  -webkit-overflow-scrolling: touch;
}
.nav-wrap.menu-open .nav-mobile-panel {
  transform: translateY(0);
  visibility: visible;
  transition: transform 0.4s var(--ease-brand), visibility 0s;
}
.nav-mobile-panel ul {
  list-style: none;
  padding: 0; margin: 0;
}
.nav-mobile-panel .nav-mobile-section-title {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-weight: 800;
  color: var(--color-text-secondary);
  padding: 1.25rem 0.5rem 0.35rem;
}
.nav-mobile-panel li a {
  display: block;
  padding: 0.95rem 0.5rem;
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--color-text-primary);
  border-bottom: 1px solid var(--color-border-subtle);
  letter-spacing: -0.01em;
  transition: color 0.2s ease;
}
.nav-mobile-panel li a:hover {
  color: var(--color-brand-primary-700);
}
/* Dropdown children are indented and set lighter so they read as members of
   the section label above them. Without this every row is identical, so a
   standalone top-level link that happens to follow a section ("Reviews"
   after Resources) looks like one of its children. */
.nav-mobile-panel .nav-mobile-sub a {
  padding-left: 1.5rem;
  font-weight: 600;
  color: var(--color-text-body);
}
/* A top-level link directly after a section's children starts a new group. */
.nav-mobile-panel .nav-mobile-sub + .nav-mobile-top a {
  margin-top: 0.75rem;
}
.nav-mobile-panel .nav-mobile-cta {
  margin-top: 1.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.nav-mobile-panel .nav-mobile-cta .btn {
  width: 100%;
  justify-content: center;
}
/* The mobile panel is a light surface, but it lives inside .nav-wrap —
   which on the homepage carries .nav-overlay, whose rule flips the phone
   button to white-on-transparent (invisible here). Force the dark/default
   voice for the cloned phone CTA regardless of the overlay state. */
.nav-wrap .nav-mobile-panel .nav-mobile-cta .btn.nav-phone-btn,
.nav-wrap.nav-overlay .nav-mobile-panel .nav-mobile-cta .btn.nav-phone-btn {
  background: transparent;
  color: var(--color-brand-primary-700);
  border-color: var(--color-border-default);
}

/* Nav height on tablet/mobile — compressed so the mobile menu panel
   has more breathing room. The CSS custom prop is read by the panel
   to offset its top padding. */
@media (max-width: 900px) {
  .nav-wrap { --nav-height: 72px; }
  .nav-inner { height: 72px; }
  .nav-logo img { height: 48px; }
  .nav-inner nav,
  .nav-cta { display: none; }
  .nav-toggle {
    display: inline-flex;
    position: relative;
    z-index: 11;  /* sits above the panel even within navbar's stack */
  }
}

/* The overlay nav on the homepage stays transparent over the video on
   mobile by default; once the user opens the menu, we promote it to
   the same light-themed glass treatment used post-scroll so links stay
   readable when the panel is open behind it. */
@media (max-width: 900px) {
  .nav-wrap.nav-overlay.menu-open .navbar {
    background: var(--color-glass-bg);
    border-bottom-color: var(--color-border-subtle);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
  }
  .nav-wrap.nav-overlay.menu-open .nav-logo .logo-light { display: none; }
  .nav-wrap.nav-overlay.menu-open .nav-logo .logo-dark  { display: block; }
}

/* ── Pulsating call FAB (mobile only) ─────────────────────────────── */
/* Rendered by site.js so it ships once and applies to every page. */

/* Height the FAB occludes in the bottom-right corner: 60px button +
   1.1rem offset + 1.2rem breathing room. Zero above the FAB's breakpoint
   so desktop layout is untouched. Consumed by the page-end clearance
   rules below; change it here and every page follows. */
:root { --call-fab-clearance: 0px; }
@media (max-width: 640px) { :root { --call-fab-clearance: 6rem; } }

/* Page-end clearance (QA 8 Sep 2026 — D2).
   The FAB is position:fixed, so it sits over whatever happens to be in
   the bottom-right corner. Mid-page that is harmless (scroll and the
   control comes clear); at the very END of the document it is
   PERMANENT — the page cannot scroll any further, so the last
   interactive controls stay buried under the button forever. Reserving
   the FAB's height at the foot of every page guarantees a reachable
   scroll offset for every element on it.
   .footer covers the 14 standard pages; .err-foot is the 404's
   self-contained footer. The paid landing pages carry .lp-sticky-bar
   instead and site.js skips the FAB there entirely. */
@media (max-width: 640px) {
  .footer   { padding-bottom: calc(2rem + var(--call-fab-clearance)); }
  .err-foot { padding-bottom: calc(2rem + var(--call-fab-clearance)); }
}

/* Second guard: while a form control has focus the FAB steps out of the
   way, so it can never sit on top of the field the visitor is filling in
   (the /contact Zip input was the reported case). Browsers without :has()
   drop the rule and still get the clearance above. */
@media (max-width: 640px) {
  body:has(input:focus, select:focus, textarea:focus) .call-fab { display: none; }
}

.call-fab { display: none; }
body.menu-open-lock .call-fab { display: none !important; }
@media (max-width: 640px) {
  .call-fab {
    position: fixed;
    right: 1.1rem;
    bottom: 1.1rem;
    z-index: 200;
    width: 60px; height: 60px;
    border-radius: 50%;
    background-image: var(--gradient-accent);
    /* Dark ink so the phone icon reads clearly on the light gradient. */
    color: var(--color-brand-secondary);
    /* Faint dark outline + a soft dark drop shadow to lift it off the page. */
    border: 1px solid rgba(10,37,65,0.18);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 14px 28px -10px rgba(150,192,225,0.55), 0 6px 16px -4px rgba(10,37,65,0.30), 0 2px 6px rgba(0,0,0,0.12);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
  }
  .call-fab:hover,
  .call-fab:focus-visible {
    transform: scale(1.06);
    outline: none;
  }
  .call-fab svg {
    width: 26px; height: 26px;
    position: relative;
    z-index: 2;
  }
  .call-fab::before,
  .call-fab::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: var(--color-brand-secondary);
    z-index: 0;
    animation: pm-fab-pulse 2.4s cubic-bezier(0, 0, 0.2, 1) infinite;
  }
  .call-fab::after { animation-delay: 1.2s; }
}
@keyframes pm-fab-pulse {
  0%   { transform: scale(0.97); opacity: 0.38; }
  80%  { transform: scale(1.6);  opacity: 0;    }
  100% { transform: scale(1.6);  opacity: 0;    }
}
@media (prefers-reduced-motion: reduce) {
  .call-fab::before, .call-fab::after { animation: none; opacity: 0; }
}

/* ── Footer responsive ────────────────────────────────────────────── */
@media (max-width: 900px) {
  .footer-grid {
    grid-template-columns: 1fr 1fr;
    gap: 2.5rem 2rem;
  }
  .footer-grid .brand { grid-column: 1 / -1; }
  .footer-grid .brand p { max-width: none; }
  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
  }
  .footer-bottom .legal { flex-wrap: wrap; gap: 1rem 1.5rem; }
}
@media (max-width: 640px) {
  /* Bottom pad keeps the call FAB's clearance — see --call-fab-clearance. */
  .footer { padding: 4rem 0 calc(2rem + var(--call-fab-clearance)); }
  .footer-grid {
    grid-template-columns: 1fr;
    gap: 2rem;
    padding-bottom: 2.25rem;
  }
  .footer-grid .brand img { height: 72px; }
}

/* ── Compare table on mobile ──────────────────────────────────────── */
/* 5-column grid is too wide for phones. Wrap in horizontal scroll so
   users can still see every column by sliding sideways within the
   table rather than losing data via stacking. */
@media (max-width: 900px) {
  .compare {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .compare-row { min-width: 640px; }
  .compare-row > div { padding: 1rem 1.25rem; }
}

/* ── Section padding compression on mobile ────────────────────────── */
/* The standard 7rem section padding crushes vertical rhythm on phones. */
@media (max-width: 640px) {
  section.svc-section { padding: 4rem 0; }
}

/* ── Utility ──────────────────────────────────────────────────────── */
.text-center { text-align: center; }
.muted { color: var(--color-text-secondary); }
.divider {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--color-border-default), transparent);
  margin: 0;
}

/* Lead-form success message (injected by site.js after webhook POST) */
.form-sent {
  padding: 1.25rem 1.5rem;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.04);
  font-size: 1.05rem;
  line-height: 1.55;
}
.form-sent strong { display: inline-block; font-size: 1.15rem; margin-bottom: 0.15rem; }
.form-sent--dark { background: rgba(255, 255, 255, 0.08); color: #fff; }
.form-sent--dark a { color: #fff; text-decoration: underline; }

/* Required-field marker on any form (contact + LPs). lp.css scopes its own copy to
   .lp-field, which never matched the contact form — this is the general rule. */
.req { color: var(--color-brand-primary-700); }

/* ── Meet the Team (PAA pattern, no photo/awards — those are client-specific) ── */
.lp-team-copy { display: grid; grid-template-columns: 1.1fr 1fr; gap: 3.5rem; margin-top: 2.5rem; }
.lp-team-trust h3, .lp-team-why h3 { font-size: 1.35rem; margin: 0 0 1rem; }
.lp-team-trust p { color: var(--color-text-secondary); line-height: 1.65; margin: 0 0 1rem; }
.lp-team-points { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.1rem; }
.lp-team-points li { display: flex; gap: 0.85rem; align-items: flex-start; line-height: 1.55; color: var(--color-text-secondary); }
.lp-team-points b { color: var(--color-text-primary); }
.lp-team-points .pt-ic { flex-shrink: 0; display: inline-flex; width: 2.4rem; height: 2.4rem; border-radius: 0.8rem; background: var(--color-surface-subtle); color: var(--color-brand-primary-700); align-items: center; justify-content: center; }
.lp-team-points .pt-ic .ic { width: 1.2rem; height: 1.2rem; }
@media (max-width: 900px) { .lp-team-copy { grid-template-columns: 1fr; gap: 2rem; } }

/* ── Eyebrow pill + geo locator (pill stays short; territory sits beside it) ── */
.hero-eyebrow-row { display: flex; align-items: center; gap: 0.9rem 1.1rem; flex-wrap: wrap; }
div.hero-eyebrow-row > .eyebrow-pill { margin-bottom: 0; }
.svc-hero-stack .hero-eyebrow-row { justify-content: center; margin-bottom: 2rem; }
.hero-copy .hero-eyebrow-row { margin-bottom: 1.75rem; }
.hero-eyebrow-row + h1, .hero-eyebrow-row + h2 { margin-top: 1.5rem; }
.hero-geo {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-size: 14px; font-weight: 600; letter-spacing: 0.01em;
  color: var(--color-text-secondary);
}
.hero-geo .ic { width: 15px; height: 15px; flex: 0 0 auto; opacity: 0.85; }
.hero-geo.on-dark { color: rgba(255, 255, 255, 0.78); }


/* ── Audit fixes, 11 September 2026 (PureAire; ported to _template) ────── */
/* Nav between 900 and 1120px: the logo squashed (fixed height + max-width:100%)
   and "Reviews" collided with the phone pill. */
.nav-logo img { object-fit: contain; }
@media (max-width: 1120px) {
  .nav-inner { height: 104px; }
  .nav-logo img { height: 64px; }
  .nav-links { gap: 1.4rem; }
  .nav-cta .btn { padding-left: 1rem; padding-right: 1rem; }
}
/* Card rows follow the card count: a fifth card centres on its own row instead
   of sitting beside three empty slots. */
.svc-overview-grid, .why-grid, .studies { display: flex; flex-wrap: wrap; justify-content: center; }
.svc-overview-grid > * { flex: 0 1 calc((100% - 3 * 1.25rem) / 4); }
.why-grid > * { flex: 0 1 calc((100% - 3 * 1.25rem) / 4); }
.studies > * { flex: 0 1 calc((100% - 2 * 1.25rem) / 3); }
@media (max-width: 1100px) {
  .svc-overview-grid > * { flex-basis: calc((100% - 1.25rem) / 2); }
  .why-grid > * { flex-basis: calc((100% - 1.25rem) / 2); }
  .studies > * { flex-basis: calc((100% - 1.25rem) / 2); }
}
@media (max-width: 640px) {
  .svc-overview-grid > *, .why-grid > *, .studies > * { flex-basis: 100%; }
}
/* Evidence tags wrap as a row, never inside a pill. */
.study .meta-row { flex-wrap: wrap; }
.study .meta-row .journal { white-space: nowrap; }
/* Headline figures never break on a hyphen. */
.study .finding-stat .num { white-space: nowrap; }
.study .finding-stat .lbl { font-size: 0.8125rem; }
/* Tap targets: footer lists, breadcrumbs and evidence links. */
.footer a { display: inline-block; padding: 0.35rem 0; }
.footer a.btn { display: inline-flex; }
.hero-breadcrumb a, .svc-hero-breadcrumb a { display: inline-block; padding: 0.55rem 0; }
.study .source { display: inline-flex; align-items: center; padding: 0.55rem 0; font-size: 0.875rem; }
/* Mobile call button: hidden until the visitor has scrolled past the hero, and
   off entirely on pages whose whole body is a form or an accordion. */
@media (max-width: 640px) {
  .call-fab { opacity: 0; pointer-events: none; transform: translateY(12px); transition: opacity 0.25s ease, transform 0.25s ease; }
  .call-fab.is-visible { opacity: 1; pointer-events: auto; transform: translateY(0); }
}
body.no-fab .call-fab { display: none !important; }
/* Review carousel on phones: keep the arrows, below the track. */
@media (max-width: 640px) {
  .reviews-carousel { padding-bottom: 3.75rem; }
  .reviews-carousel .carousel-arrow { display: inline-flex; top: auto; bottom: 0; transform: none; }
  .reviews-carousel .carousel-arrow.prev { left: calc(50% - 56px); }
  .reviews-carousel .carousel-arrow.next { right: auto; left: calc(50% + 8px); }
}
/* Comparison table on phones: scroll it rather than clip it. */
@media (max-width: 640px) {
  .compare { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .compare-row { min-width: 600px; }
}
/* Visible keyboard focus everywhere. */
a:focus-visible, button:focus-visible, [tabindex="0"]:focus-visible { outline: 3px solid var(--color-brand-primary-500); outline-offset: 3px; }
/* Reduced motion: no pulsing dots. */
@media (prefers-reduced-motion: reduce) { .eyebrow-pill .ring, .eyebrow-pill .dot-wrap .ring, .dot-wrap .ring { animation: none !important; } }
@media (max-width: 1000px) { .nav-links { gap: 1rem; } .nav-cta { gap: 0.5rem; } }

/* ── Social channels (PureAire, 14 September 2026) ──────────────────────
   Liz asked for Instagram / Facebook / LinkedIn "upper-right in the header"
   so it is obvious they are PureAire's channels. Circular icon buttons sit
   ahead of the phone pill on desktop, mirror into the mobile panel (site.js
   clones .nav-social → .nav-mobile-social) and repeat under the footer blurb.
   Colours follow the nav state: white over the homepage video, brand navy
   once the nav goes solid. Landing pages deliberately carry none. */
.nav-social { display: flex; align-items: center; gap: 0.15rem; margin-right: 0.25rem; }
.nav-social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  color: var(--color-brand-primary-700);
  border: 1px solid transparent;
  transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
.nav-social a:hover { background: rgba(10,37,65,0.06); border-color: var(--color-border-default); color: var(--color-brand-primary-700); }
.nav-social svg { width: 18px; height: 18px; }
.nav-wrap.nav-overlay .nav-social a { color: #fff; }
.nav-wrap.nav-overlay .nav-social a:hover { background: var(--color-white-border); border-color: var(--color-white-outline); color: #fff; }
.nav-wrap.nav-overlay.is-solid .nav-social a { color: var(--color-brand-primary-700); }
.nav-wrap.nav-overlay.is-solid .nav-social a:hover { background: rgba(10,37,65,0.06); border-color: var(--color-border-default); }
/* 900–1120px is already the squeeze band (11 Sep fix): three more icons
   there squash the logo out of the bar. Header icons yield to the footer
   row on that band; under 900px the mobile panel carries them again. */
@media (max-width: 1120px) { .nav-social { display: none; } }

.nav-mobile-panel .nav-mobile-social { display: flex; gap: 0.6rem; padding: 1.25rem 0 0.25rem; }
.nav-mobile-panel .nav-mobile-social a {
  width: 44px; height: 44px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(10,37,65,0.06); color: var(--color-brand-primary-700);
  border: 1px solid var(--color-border-default);
}
.nav-mobile-panel .nav-mobile-social svg { width: 20px; height: 20px; }

.footer .footer-social { display: flex; gap: 0.6rem; margin-top: 1.25rem; }
.footer .footer-social a {
  width: 40px; height: 40px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--color-white-outline); color: #fff;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.footer .footer-social a:hover { background: var(--color-white-border); border-color: #fff; color: #fff; }
.footer .footer-social svg { width: 18px; height: 18px; stroke: currentColor; }

/* "Powered by Pure Maintenance" badge (Liz, 8 Oct 2026 sync): ties the network-wide
   100,000+ figure to Pure Maintenance. Text only; never re-typeset the PM logo. */
.powered-by-pm {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  margin: 1.25rem 0 0;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--color-border-default);
  border-radius: 999px;
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--color-text-secondary);
  background: var(--color-surface-card);
}
.powered-by-pm strong { font-weight: 700; color: var(--color-text-primary); }
.powered-by-pm.on-dark {
  border-color: var(--color-white-border);
  background: var(--color-white-surface);
  color: var(--color-white-text-muted);
}
.powered-by-pm.on-dark strong { color: var(--color-text-inverse); }
/* Turnstile lead gate (1.13.0): the slot stays empty and hidden unless Cloudflare
   asks a visitor to tick the "verify you are human" box (interaction-only widget). */
.ts-slot:empty { display: none; }
/* Until Cloudflare asks for a tick, keep the rendered widget out of the layout so the
   form's grid/flex gap doesn't grow; before-interactive-callback adds .ts-active. */
.ts-slot:not(.ts-active) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); margin: 0; padding: 0; border: 0; }
.ts-slot.ts-active { margin-top: 1rem; }
.ts-hint { margin: 0.75rem 0 0.4rem; font-size: 0.875rem; font-weight: 600; color: var(--color-text-primary); }
.form-on-dark .ts-hint { color: var(--color-text-inverse); }
