/* ==========================================================================
   CLEAR PATH GROUND WORKS — DESIGN SYSTEM
   ---------------------------------------------------------------------------
   Brand palette (fixed, supplied by client):
     Charcoal    #1E1E1E
     Bronze      #B07D3C
     Olive Green #6B7A46
     Warm White  #F7F6F2

   Type: Barlow Condensed (headings) / Montserrat (body). Self-hosted, see
   css/fonts.css.

   ---------------------------------------------------------------------------
   CONTRAST NOTE — why bronze is not used as body text on light backgrounds
   ---------------------------------------------------------------------------
   Measured WCAG ratios for the supplied palette:

     Bronze #B07D3C on Charcoal #1E1E1E .......... 4.69:1  -> AA normal text OK
     Bronze #B07D3C on Warm White #F7F6F2 ........ 3.28:1  -> LARGE TEXT ONLY
     Olive  #6B7A46 on Warm White #F7F6F2 ........ 4.26:1  -> fails AA normal

   So on dark surfaces bronze is free to carry text of any size, but on light
   surfaces it is restricted to display-size headings, rules, icons and fills.
   Anywhere a bronze-coloured link or small label sits on white, the darkened
   --bronze-ink (#8E6230, 4.93:1) is substituted instead. Olive is treated as a
   fill/rule colour only, with --olive-ink (#55603A) for the rare text use.
   None of the four brand colours were altered — these are additional shades
   derived from bronze/olive purely to keep text legible.
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
  /* --- Brand, exactly as supplied ---------------------------------------- */
  --charcoal:    #1E1E1E;
  --bronze:      #B07D3C;
  --olive:       #6B7A46;
  --warm-white:  #F7F6F2;

  /* --- Derived neutrals --------------------------------------------------- */
  --char-950: #141414;
  --char-900: #1A1A1A;
  --char-850: #1E1E1E;
  --char-800: #242424;
  --char-700: #2E2E2E;
  --char-600: #3A3A3A;
  --char-500: #4E4E4C;

  --paper:     #FFFFFF;
  --paper-alt: #F7F6F2;
  --paper-dim: #EFEDE6;

  --ink:        #1E1E1E;
  --ink-body:   #3A3A36;   /* 11.1:1 on warm white */
  --ink-muted:  #6A6A62;   /* 5.2:1  on warm white */

  /* --- Accent shades derived for legibility (see contrast note) ---------- */
  --bronze-ink:   #8E6230;  /* bronze darkened for text on light   4.93:1 */
  --bronze-lift:  #C89355;  /* bronze lightened for hover on dark        */
  --bronze-glow:  rgba(176, 125, 60, 0.16);
  --olive-ink:    #55603A;
  --olive-lift:   #7E8E55;

  /* --- Hairlines ---------------------------------------------------------- */
  --rule-dark:  rgba(247, 246, 242, 0.14);
  --rule-light: rgba(30, 30, 30, 0.12);
  --rule-bronze: rgba(176, 125, 60, 0.38);

  /* --- Type -------------------------------------------------------------- */
  --font-head: 'Barlow Condensed', 'Arial Narrow', system-ui, sans-serif;
  --font-body: 'Montserrat', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Fluid display scale. clamp() keeps headings proportional from 360px to
     1440px without a stack of breakpoints. */
  --t-display: clamp(2.75rem, 1.4rem + 5.9vw, 6.25rem);
  --t-h1:      clamp(2.25rem, 1.3rem + 4.2vw, 4.5rem);
  --t-h2:      clamp(1.85rem, 1.25rem + 2.6vw, 3.25rem);
  --t-h3:      clamp(1.35rem, 1.1rem + 1.1vw, 1.85rem);
  --t-h4:      clamp(1.1rem, 1rem + 0.5vw, 1.3rem);
  --t-lead:    clamp(1.02rem, 0.97rem + 0.28vw, 1.19rem);
  --t-body:    1rem;
  --t-small:   0.875rem;
  --t-micro:   0.75rem;

  /* --- Space -------------------------------------------------------------- */
  --shell:      1240px;
  --shell-narrow: 900px;
  --gutter:     clamp(1.25rem, 0.8rem + 2vw, 2.5rem);
  --section-y:  clamp(4rem, 2.5rem + 6vw, 8rem);
  --section-y-sm: clamp(3rem, 2rem + 4vw, 5.5rem);

  /* --- Motion ------------------------------------------------------------- */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 0.45s;

  /* Tall enough to clear the 64px logo badge with real breathing room. */
  --header-h: 92px;
  /* Live height of .stormbar, kept in sync by an inline script right after it
     in the markup (pre-paint) and by js/main.js thereafter (post-load, on
     resize/wrap changes). .header reads this so it always sits below the bar
     instead of the two occupying the same pixels — see the note on .header. */
  --stormbar-h: 0px;
  --shadow-card: 0 1px 2px rgba(30,30,30,.05), 0 12px 32px -12px rgba(30,30,30,.18);
  --shadow-lift: 0 2px 4px rgba(30,30,30,.06), 0 28px 56px -20px rgba(30,30,30,.30);
}

@media (max-width: 900px) {
  :root { --header-h: 72px; }
}

/* ==========================================================================
   2. RESET / BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

/* The UA stylesheet implements [hidden] as `display: none`, which ANY author
   `display` declaration silently outranks. Several components here set an
   explicit display on an element that also toggles [hidden] (.brand__fallback
   being the one that bit: the logo and its type-lockup fallback both rendered,
   widening the header until the burger was pushed off-screen on phones).
   This makes the attribute authoritative, as its semantics imply. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1.5rem);
}

body {
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.7;
  color: var(--ink-body);
  background: var(--warm-white);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, picture, svg, video {
  display: block;
  max-width: 100%;
}
img { height: auto; }

input, button, textarea, select { font: inherit; color: inherit; }

a { color: var(--bronze-ink); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--bronze); }

/* Visible, brand-coloured focus ring on every interactive element. Uses
   :focus-visible so mouse users never see it but keyboard users always do. */
:focus-visible {
  outline: 3px solid var(--bronze);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection { background: var(--bronze); color: #fff; }

.skip-link {
  position: absolute;
  left: 1rem;
  top: -100px;
  z-index: 999;
  /* --bronze-ink, not --bronze — same 3.59:1 white-text failure as .btn,
     fixed the same way. Notable here specifically: this is a keyboard-
     accessibility feature, so a contrast failure on it is doubly wrong. */
  background: var(--bronze-ink);
  color: #fff;
  padding: 0.75rem 1.25rem;
  font-family: var(--font-head);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 1rem; color: #fff; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   3. TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4 {
  font-family: var(--font-head);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  color: var(--ink);
  text-wrap: balance;
}

.h1, h1 { font-size: var(--t-h1); }
.h2, h2 { font-size: var(--t-h2); }
.h3, h3 { font-size: var(--t-h3); line-height: 1.12; }
.h4, h4 { font-size: var(--t-h4); line-height: 1.2; letter-spacing: 0.02em; }

.display {
  font-size: var(--t-display);
  line-height: 0.94;
  letter-spacing: -0.005em;
}

p { text-wrap: pretty; }
p + p { margin-top: 1.1em; }

.lead {
  font-size: var(--t-lead);
  line-height: 1.65;
  color: var(--ink-body);
}

.on-dark { color: var(--warm-white); }
.on-dark h1, .on-dark h2, .on-dark h3, .on-dark h4 { color: var(--warm-white); }
.on-dark p { color: rgba(247, 246, 242, 0.82); }
.on-dark a { color: var(--bronze); }
.on-dark a:hover { color: var(--bronze-lift); }

/* Headings inherit --ink (charcoal) by default, which is invisible against
   .section--dark's charcoal background unless every heading is individually
   wrapped in .on-dark or hand-colored. That dependency was missed on six
   headings across the site (contrast audit found them rendering charcoal-on-
   charcoal — literally blank space where a heading should be, e.g. "Where We
   Work" on the homepage). Making dark sections self-contained for their own
   headings removes the failure mode instead of just patching each instance. */
.section--dark h1, .section--dark h2, .section--dark h3, .section--dark h4 {
  color: var(--warm-white);
}

/* --- Eyebrow: the small numbered label above section headings.
       Reads like a survey station marker — part of the "ground works" motif. */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--font-head);
  font-size: var(--t-small);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--bronze-ink);
  margin-bottom: 1.1rem;
}
.on-dark .eyebrow, .eyebrow--light { color: var(--bronze); }

.eyebrow::before {
  content: "";
  width: 34px;
  height: 2px;
  background: currentColor;
  flex: none;
}
.eyebrow--center { justify-content: center; }

/* --- Section heading block ---------------------------------------------- */
.section-head { max-width: 62ch; margin-bottom: clamp(2.25rem, 1.5rem + 2vw, 3.5rem); }
.section-head--center { margin-left: auto; margin-right: auto; text-align: center; }
.section-head p { margin-top: 1.15rem; font-size: var(--t-lead); }

/* ==========================================================================
   4. LAYOUT
   ========================================================================== */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.shell--narrow { max-width: var(--shell-narrow); }

.section { padding-block: var(--section-y); position: relative; }
.section--sm { padding-block: var(--section-y-sm); }
.section--flush-top { padding-top: 0; }

.section--dark { background: var(--charcoal); color: var(--warm-white); }
.section--paper { background: var(--paper); }
.section--alt { background: var(--paper-alt); }
.section--dim { background: var(--paper-dim); }

/* Hairline that separates stacked light sections without a heavy border. */
.section--ruled { border-top: 1px solid var(--rule-light); }

.grid { display: grid; gap: clamp(1.25rem, 0.9rem + 1.4vw, 2rem); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 1000px) {
  .grid--3, .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: minmax(0, 1fr); }
}

/* Split: text column + media column, reversible. */
.split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, 1rem + 4vw, 5rem);
  align-items: center;
}
.split--reverse > :first-child { order: 2; }
@media (max-width: 900px) {
  .split { grid-template-columns: minmax(0, 1fr); }
  .split--reverse > :first-child { order: 0; }
}

/* Pins the media column in place while the other column scrolls past beside
   it — used by the "How It Runs" process section so the photo stays put as
   the visitor scrolls through the four steps. align-self: start is required
   because .split's default align-items: center stretches grid children to
   the row's full height, which would leave nothing for `sticky` to travel
   within (a sticky element can't move inside a box it's already stretched
   to fill). Off below 900px, where the two columns stack and there is no
   side-by-side scroll relationship left to preserve. */
.split--sticky-media > :first-child {
  align-self: start;
  position: sticky;
  top: calc(var(--header-h) + 2rem);
}
@media (max-width: 900px) {
  .split--sticky-media > :first-child { position: static; }
}

/* ==========================================================================
   5. BUTTONS
   ========================================================================== */

.btn {
  /* Matches .btn--primary's fix below: --bronze-ink, not --bronze, so a
     button that ends up with no modifier class still carries accessible
     white text instead of silently reintroducing the 3.59:1 failure. */
  --btn-bg: var(--bronze-ink);
  --btn-fg: #fff;
  --btn-bd: var(--bronze-ink);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.95rem 1.9rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 2px solid var(--btn-bd);
  border-radius: 2px;
  font-family: var(--font-head);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.28s var(--ease),
              border-color 0.28s var(--ease),
              color 0.28s var(--ease),
              transform 0.28s var(--ease),
              box-shadow 0.28s var(--ease);
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 24px -10px rgba(176, 125, 60, 0.55);
  color: var(--btn-fg);
}
.btn:active { transform: translateY(0); }

/* Resting state uses --bronze-ink, not the brand's literal --bronze, for the
   button FILL specifically. White text on raw --bronze (#B07D3C) measures
   3.59:1 — confirmed by the WCAG relative-luminance formula, not a rounding
   artifact — which fails the 4.5:1 minimum for normal-size text, on every
   primary CTA sitewide ("Request a Free Estimate", "Call 941-699-6992", every
   "Free Estimate" button). White on --bronze-ink (#8E6230) measures 5.33:1,
   comfortably clearing it. Hover swaps to the brighter, literal --bronze —
   the button now lightens on hover instead of darkening, which reads as more
   "alive" as an interaction anyway. --bronze itself is untouched everywhere
   else (rules, icons, numbers, borders); only what a primary button's fill
   resolves to changed. */
.btn--primary { --btn-bg: var(--bronze-ink); --btn-fg: #fff; --btn-bd: var(--bronze-ink); }
.btn--primary:hover { --btn-bg: var(--bronze); --btn-bd: var(--bronze); }

/* Outline on light surfaces */
.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  --btn-bd: rgba(30, 30, 30, 0.28);
}
.btn--ghost:hover {
  --btn-bg: var(--charcoal);
  --btn-fg: var(--warm-white);
  --btn-bd: var(--charcoal);
  box-shadow: 0 12px 24px -10px rgba(30, 30, 30, 0.45);
}

/* Outline on dark surfaces */
.btn--ghost-light {
  --btn-bg: transparent;
  --btn-fg: var(--warm-white);
  --btn-bd: rgba(247, 246, 242, 0.42);
}
.btn--ghost-light:hover {
  --btn-bg: var(--warm-white);
  --btn-fg: var(--charcoal);
  --btn-bd: var(--warm-white);
  box-shadow: 0 12px 24px -10px rgba(0, 0, 0, 0.5);
}

.btn--olive { --btn-bg: var(--olive); --btn-fg: #fff; --btn-bd: var(--olive); }
.btn--olive:hover { --btn-bg: var(--olive-ink); --btn-bd: var(--olive-ink); box-shadow: 0 12px 24px -10px rgba(107,122,70,.55); }

.btn--sm { padding: 0.7rem 1.25rem; font-size: 0.9375rem; letter-spacing: 0.08em; }
.btn--lg { padding: 1.15rem 2.4rem; font-size: 1.15rem; }

/* .btn is white-space:nowrap everywhere else in the system — deliberately,
   since a button label breaking mid-word looks broken. The one long-label
   CTA ("Call 941-699-6992 for Emergency Response") overflowed the viewport
   on phones as a result, so large buttons specifically are allowed to wrap
   below 480px, where a two-line centered button reads as a considered
   choice rather than a bug. Small/default buttons keep single-line text,
   except .btn--wrap, opted into the same treatment case-by-case for other
   long-label default buttons (e.g. "Read More 5-Star Reviews on Google",
   which overflowed 320px screens by 13px with nowrap). */
@media (max-width: 480px) {
  .btn--lg,
  .btn--wrap { white-space: normal; text-align: center; line-height: 1.25; }
}
.btn--block { width: 100%; }

.btn__icon { width: 1.05em; height: 1.05em; flex: none; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  align-items: center;
}
.btn-row--center { justify-content: center; }

/* Text link with an animated bronze underline. */
.link-cut {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-head);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--bronze-ink);
  padding-bottom: 0.3rem;
  background-image: linear-gradient(var(--bronze), var(--bronze));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 2px;
  transition: background-size 0.35s var(--ease), color 0.28s var(--ease), gap 0.28s var(--ease);
}
.link-cut:hover { gap: 0.85rem; color: var(--bronze); }
.on-dark .link-cut { color: var(--bronze); }
.on-dark .link-cut:hover { color: var(--bronze-lift); }
.link-cut svg { width: 0.95em; height: 0.95em; }

/* ==========================================================================
   6. HEADER
   ---------------------------------------------------------------------------
   Sits transparent over the hero on every page, then condenses to solid
   charcoal once the user scrolls past the hero (js/main.js toggles .is-stuck).

   `top` reads --stormbar-h rather than being pinned to 0. .header is
   position:fixed (removed from flow) and .stormbar is a normal in-flow
   element directly above it, so a hard-coded top:0 puts the header on top of
   — literally overlapping — the storm bar for as long as the bar is still on
   screen, since .header's z-index (100) simply paints over it. js/main.js
   narrows this offset by the scroll distance each frame, so the header sits
   below the bar at the top of the page and glides up flush with it exactly
   as the bar scrolls away, instead of the two ever sharing the same pixels.
   ========================================================================== */

.header {
  position: fixed;
  top: var(--stormbar-h, 0px);
  left: 0;
  right: 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color 0.35s var(--ease),
              border-color 0.35s var(--ease),
              box-shadow 0.35s var(--ease),
              height 0.35s var(--ease);
}

.header::before {
  /* Scrim so white nav text stays readable over bright hero photography
     before the header goes solid. */
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(20,20,20,.78), rgba(20,20,20,0));
  opacity: 1;
  transition: opacity 0.35s var(--ease);
  pointer-events: none;
}

.header.is-stuck {
  background: var(--char-950);
  border-bottom-color: var(--rule-dark);
  box-shadow: 0 10px 30px -18px rgba(0,0,0,.9);
}
.header.is-stuck::before { opacity: 0; }

.header__inner {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  width: 100%;
  position: relative;
  z-index: 1;
}

/* --- Brand lockup --------------------------------------------------------
   .brand__logo is the client's approved artwork (images/Logo.png), used
   exactly as supplied — only its height is constrained, width follows the
   file's own 362:231 aspect ratio. It is never recoloured, cropped or redrawn.

   The supplied logo is a PICTORIAL badge with no company name in it, so the
   .brand__wordmark type lockup sits permanently beside it rather than acting
   as a fallback — without it a visitor could not read who the company is. The
   image carries alt="" because the wordmark next to it already states the name;
   announcing it twice would just be noise for screen-reader users.
   ------------------------------------------------------------------------ */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  text-decoration: none;
  margin-right: auto;
  flex: none;
}

/* The badge is nearly square (362x231), so it earns a little more height than a
   horizontal wordmark would — at 44px tall the illustrated scene turns to mush. */
.brand__logo {
  /* 4.4vw reaches the 64px ceiling at ~1440px, the most common desktop width,
     so the badge is at full size where most visitors see it. */
  height: clamp(48px, 4.4vw, 64px);
  width: auto;
  display: block;
  flex: none;
  transition: height 0.35s var(--ease);
}
.header.is-stuck .brand__logo { height: clamp(42px, 3.2vw, 54px); }

.brand__wordmark {
  display: flex;
  flex-direction: column;
  line-height: 1;
  font-family: var(--font-head);
  text-transform: uppercase;
  color: var(--warm-white);
}
.brand__wordmark-name {
  font-size: clamp(1.25rem, 1rem + 0.75vw, 1.65rem);
  font-weight: 700;
  letter-spacing: 0.05em;
  white-space: nowrap;
}
.brand__wordmark-sub {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.32rem;
  font-size: clamp(0.6rem, 0.54rem + 0.2vw, 0.72rem);
  font-weight: 600;
  letter-spacing: 0.28em;
  color: var(--bronze);
  white-space: nowrap;
}
.brand__wordmark-sub::before {
  content: "";
  width: 18px;
  height: 2px;
  background: var(--bronze);
  flex: none;
}

/* --- Primary nav --------------------------------------------------------- */
.nav { display: block; }
.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 0.3rem + 1.5vw, 2.1rem);
  list-style: none;
  padding: 0;
  margin: 0;
}

.nav__link {
  position: relative;
  display: block;
  padding: 0.4rem 0;
  font-family: var(--font-head);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: rgba(247, 246, 242, 0.9);
  white-space: nowrap;
  transition: color 0.25s var(--ease);
}

/* The bronze "cut line" that wipes in under a nav item — the same blade-path
   motif used for section rules and link underlines. */
.nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--bronze);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}
.nav__link:hover { color: #fff; }
.nav__link:hover::after { transform: scaleX(1); }

.nav__link.is-current { color: #fff; }
.nav__link.is-current::after { transform: scaleX(1); }

.header__actions {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  flex: none;
}

.header__phone {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-head);
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-decoration: none;
  color: var(--warm-white);
  white-space: nowrap;
  transition: color 0.25s var(--ease);
}
.header__phone:hover { color: var(--bronze); }
.header__phone svg { width: 1.05em; height: 1.05em; color: var(--bronze); flex: none; }

/* --- Burger -------------------------------------------------------------- */
.burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  width: 46px;
  height: 46px;
  padding: 0 9px;
  background: transparent;
  border: 1px solid rgba(247,246,242,.3);
  border-radius: 2px;
  cursor: pointer;
  flex: none;
}
.burger__bar {
  display: block;
  height: 2px;
  width: 100%;
  background: var(--warm-white);
  transition: transform 0.35s var(--ease), opacity 0.2s var(--ease);
}
.burger.is-open .burger__bar:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.burger.is-open .burger__bar:nth-child(2) { opacity: 0; }
.burger.is-open .burger__bar:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

/* Header breakpoints are set by measured fit, not by round numbers.
   The full lockup is brand + 5 nav items + phone + CTA button, and none of
   those can wrap. Measured against the 1240px shell it stops fitting below
   ~1140px, so the drawer takes over there — a tablet in landscape (1024px)
   correctly gets the burger rather than a nav that overflows the viewport. */
@media (max-width: 1260px) {
  .header__phone span { display: none; }
}
@media (max-width: 1140px) {
  .nav { display: none; }
  .burger { display: flex; }
  .header__actions .btn { display: none; }
}

/* At 320px the shell leaves 280px of content width. Logo (201) + gap (24) +
   phone icon (19) + gap (24) + burger (46) = 314, which pushed the burger off
   the screen entirely — the menu became untappable. The phone icon is the
   redundant one here: the storm bar directly above the header already shows
   the number, and the drawer repeats it. Dropping it plus a slightly smaller
   logo brings the row to 252px, inside 280 with room to spare. */
@media (max-width: 520px) {
  .header__actions { display: none; }
  .brand__logo { height: 42px; }
  .header.is-stuck .brand__logo { height: 38px; }
}

/* Below ~380px even the wordmark will not fit beside the badge. The badge is
   the client's actual artwork, so the type lockup is what gives way — the page
   <title>, the hero and the footer all still carry the company name. */
@media (max-width: 379px) {
  .brand__wordmark { display: none; }
  .brand__logo { height: 46px; }
}

/* --- Mobile drawer ------------------------------------------------------- */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--char-950);
  padding: calc(var(--header-h) + 2rem) var(--gutter) 2.5rem;
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-12px);
  /* visibility is stepped, not eased: 0s with a delay equal to the fade means
     it flips to hidden only AFTER the panel has faded out. On open (below) the
     delay is 0s so it becomes visible immediately — without that, the panel is
     still computed `hidden` when JS calls focus(), and a hidden element
     silently refuses focus, stranding keyboard users on the page behind. */
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease), visibility 0s linear 0.35s;
}
.drawer.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease), visibility 0s linear 0s;
}

.drawer__list { list-style: none; padding: 0; margin: 0 0 2rem; }
.drawer__list li { border-bottom: 1px solid var(--rule-dark); }

.drawer__link {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 1.05rem 0;
  font-family: var(--font-head);
  font-size: 1.75rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--warm-white);
  transition: color 0.25s var(--ease), padding-left 0.25s var(--ease);
}
.drawer__link:hover, .drawer__link.is-current { color: var(--bronze); padding-left: 0.5rem; }
.drawer__link::before {
  content: attr(data-num);
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  color: var(--bronze);
  flex: none;
}

.drawer__foot { display: grid; gap: 0.9rem; }
.drawer__phone {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-head);
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--warm-white);
  text-decoration: none;
}
.drawer__phone svg { width: 1em; height: 1em; color: var(--bronze); }

body.is-locked { overflow: hidden; }

/* ==========================================================================
   7. HERO
   ========================================================================== */

.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: min(92vh, 900px);
  padding-top: calc(var(--header-h) + clamp(3rem, 6vw, 6rem));
  padding-bottom: clamp(3.5rem, 2rem + 5vw, 7rem);
  background: var(--char-950);
  overflow: hidden;
  isolation: isolate;
}

.hero--compact {
  min-height: min(66vh, 620px);
  align-items: center;
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Two-stop scrim: a strong charcoal wash from the left for text legibility,
   plus a bottom fade so the section below joins seamlessly. Kept as a
   pseudo-element pair rather than one gradient so each can be tuned per page. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(100deg,
      rgba(15, 15, 15, 0.94) 0%,
      rgba(18, 18, 18, 0.82) 34%,
      rgba(20, 20, 20, 0.45) 62%,
      rgba(20, 20, 20, 0.30) 100%),
    linear-gradient(to top, rgba(15, 15, 15, 0.85) 0%, rgba(15, 15, 15, 0) 45%);
}

.hero__inner { position: relative; width: 100%; }
.hero__content { max-width: 44rem; }

.hero__title {
  font-size: var(--t-display);
  line-height: 0.92;
  color: var(--warm-white);
  letter-spacing: -0.003em;
}
.hero__title em {
  display: block;
  font-style: normal;
  color: var(--bronze);
}

.hero__tagline {
  margin-top: 1.4rem;
  font-family: var(--font-head);
  font-size: clamp(1.15rem, 1rem + 0.7vw, 1.6rem);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(247, 246, 242, 0.88);
}

.hero__text {
  margin-top: 1.35rem;
  max-width: 46ch;
  font-size: var(--t-lead);
  color: rgba(247, 246, 242, 0.8);
}

.hero__actions { margin-top: 2.25rem; }

/* Trust strip pinned to the bottom of the hero. */
.hero__strip {
  margin-top: clamp(2.5rem, 1.5rem + 3vw, 4.5rem);
  padding-top: 1.6rem;
  border-top: 1px solid var(--rule-dark);
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.25rem, 0.5rem + 2.5vw, 3.25rem);
}
.hero__strip-item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-head);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(247, 246, 242, 0.9);
}
.hero__strip-item svg { width: 1.35em; height: 1.35em; color: var(--bronze); flex: none; }

/* The license credential needs a number on its own line — plain uppercase
   letter-spacing makes "CGC1541681" hard to scan run into the rest of the
   line, so this variant stacks a normal-case sub-line under the label
   instead of stretching .hero__strip-item onto two visually competing
   uppercase lines. */
.hero__strip-item--stacked { align-items: flex-start; flex-direction: column; gap: 0.15rem; }
.hero__strip-item--stacked .hero__strip-item-row { display: flex; align-items: center; gap: 0.7rem; }
.hero__strip-item--stacked .hero__strip-sub {
  padding-left: calc(1.35em + 0.7rem);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: none;
  color: rgba(247, 246, 242, 0.65);
}

/* Page hero (inner pages) */
.hero--page .hero__content { max-width: 52rem; }
.hero--page .hero__title { font-size: var(--t-h1); line-height: 1; }

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem;
  list-style: none;
  padding: 0;
  margin: 0 0 1.4rem;
  font-family: var(--font-head);
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(247, 246, 242, 0.6);
}
.breadcrumb a { color: var(--bronze); text-decoration: none; }
.breadcrumb a:hover { color: var(--bronze-lift); text-decoration: underline; }
.breadcrumb li::after { content: "/"; margin-left: 0.55rem; color: rgba(247,246,242,.3); }
.breadcrumb li:last-child::after { content: none; }

/* ==========================================================================
   8. EMERGENCY / STORM BAR
   ---------------------------------------------------------------------------
   Thin olive band directly under the header on every page. Storm response is
   the client's highest-urgency offer, so it gets a permanent slot rather than
   living only in the nav.
   ========================================================================== */

.stormbar {
  position: relative;
  z-index: 90;
  background: var(--olive);
  color: #fff;
}
.stormbar__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4rem 1.1rem;
  padding-block: 0.7rem;
  text-align: center;
}
.stormbar__label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-head);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.stormbar__label svg { width: 1.1em; height: 1.1em; flex: none; }
/* Solid white, not translucent: at 14px, rgba(255,255,255,.92) over the olive
   background measured 4.24:1 — just under the 4.5:1 AA minimum for normal-size
   text. Solid white clears it, matching the label and link beside it, which
   were already solid for the same reason. */
.stormbar__text { font-size: var(--t-small); color: #fff; }
.stormbar__link {
  font-family: var(--font-head);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: #fff;
  text-decoration: none;
  border-bottom: 2px solid rgba(255,255,255,.55);
  padding-bottom: 1px;
  transition: border-color 0.25s var(--ease);
}
.stormbar__link:hover { color: #fff; border-bottom-color: #fff; }

/* ==========================================================================
   9. CARDS
   ========================================================================== */

/* --- Service card: photo + copy, bronze cut-line on hover ---------------- */
.svc {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--rule-light);
  border-radius: 3px;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease), border-color 0.4s var(--ease);
}
.svc:hover { transform: translateY(-6px); box-shadow: var(--shadow-lift); border-color: var(--rule-bronze); }

.svc__media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--char-800); }
.svc__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease-out);
}
.svc:hover .svc__media img { transform: scale(1.055); }

/* Bronze rule that wipes across the base of the image on hover. */
.svc__media::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4px;
  background: var(--bronze);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease);
}
.svc:hover .svc__media::after { transform: scaleX(1); }

.svc__num {
  position: absolute;
  top: 0; left: 0;
  padding: 0.5rem 0.85rem;
  background: rgba(20,20,20,.82);
  color: var(--bronze);
  font-family: var(--font-head);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.18em;
}

.svc__body { display: flex; flex-direction: column; flex: 1; padding: 1.65rem 1.5rem 1.75rem; }
.svc__title { font-size: var(--t-h3); margin-bottom: 0.7rem; }
.svc__text { font-size: 0.9375rem; line-height: 1.7; color: var(--ink-body); }
.svc__list {
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.45rem;
}
.svc__list li {
  position: relative;
  padding-left: 1.4rem;
  font-size: 0.875rem;
  color: var(--ink-muted);
}
.svc__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 8px; height: 2px;
  background: var(--bronze);
}
.svc__foot { margin-top: auto; padding-top: 1.4rem; }

/* --- Icon card ----------------------------------------------------------- */
.icard {
  padding: clamp(1.5rem, 1.1rem + 1.2vw, 2.15rem);
  background: var(--paper);
  border: 1px solid var(--rule-light);
  border-radius: 3px;
  border-top: 3px solid var(--bronze);
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.icard:hover { transform: translateY(-5px); box-shadow: var(--shadow-lift); }
.icard--dark {
  background: var(--char-800);
  border-color: var(--rule-dark);
  border-top-color: var(--bronze);
  color: rgba(247,246,242,.8);
}
.icard--dark .icard__title { color: var(--warm-white); }

.icard__icon {
  width: 46px; height: 46px;
  margin-bottom: 1.15rem;
  color: var(--bronze);
}
.icard__icon svg { width: 100%; height: 100%; }
.icard__title { font-size: var(--t-h4); margin-bottom: 0.6rem; }
.icard__text { font-size: 0.9375rem; line-height: 1.7; }

/* --- Stats --------------------------------------------------------------- */
.stat { text-align: center; padding: 0.5rem; }
.stat__num {
  font-family: var(--font-head);
  font-size: clamp(2.75rem, 1.9rem + 3.4vw, 4.5rem);
  font-weight: 700;
  line-height: 1;
  color: var(--bronze);
  letter-spacing: -0.01em;
}
.stat__label {
  margin-top: 0.65rem;
  font-family: var(--font-head);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(247, 246, 242, 0.72);
}
.section--paper .stat__label, .section--alt .stat__label { color: var(--ink-muted); }

/* --- Process steps ------------------------------------------------------- */
.steps { counter-reset: step; display: grid; gap: 0; }
.step {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(1.25rem, 0.8rem + 1.6vw, 2.25rem);
  padding: clamp(1.6rem, 1.2rem + 1.2vw, 2.4rem) 0;
  border-top: 1px solid var(--rule-light);
}
.step:last-child { border-bottom: 1px solid var(--rule-light); }
.on-dark .step, .section--dark .step { border-color: var(--rule-dark); }

.step__num {
  font-family: var(--font-head);
  font-size: clamp(2.1rem, 1.6rem + 1.9vw, 3.1rem);
  font-weight: 700;
  line-height: 1;
  color: var(--bronze);
  min-width: 2.6ch;
  letter-spacing: 0.02em;
}
.step__title { font-size: var(--t-h3); margin-bottom: 0.55rem; }
.step__text { font-size: 0.9688rem; line-height: 1.75; max-width: 62ch; }

/* --- Scroll-linked steps ---------------------------------------------------
   Opt-in via .steps--scrolly (in the HTML) + .is-scrolly (added by JS only
   once js/main.js confirms IntersectionObserver is available and the visitor
   hasn't asked for reduced motion — see scrollySteps() in main.js). Scoped to
   that pairing rather than .step generally, so the plain step lists on the
   About and Contact pages are untouched. Without .is-scrolly every step
   simply renders at full opacity, so nothing depends on JS to be readable.
   ---------------------------------------------------------------------- */
.is-scrolly .step {
  padding-left: 1.15rem;
  opacity: 0.42;
  transition: opacity 0.45s var(--ease);
}
.is-scrolly .step__num { color: var(--ink-muted); transition: color 0.45s var(--ease); }

.is-scrolly .step::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.3rem;
  bottom: 0.3rem;
  width: 3px;
  background: var(--bronze);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.45s var(--ease);
}

.is-scrolly .step.is-active { opacity: 1; }
.is-scrolly .step.is-active .step__num { color: var(--bronze); }
.is-scrolly .step.is-active::before { transform: scaleY(1); }

/* --- Checklist ----------------------------------------------------------- */
.checks { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.85rem; }
.checks li {
  position: relative;
  padding-left: 2.1rem;
  font-size: 0.9688rem;
  line-height: 1.65;
}
.checks li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.28em;
  width: 1.25rem; height: 1.25rem;
  border: 2px solid var(--bronze);
  border-radius: 2px;
}
.checks li::after {
  content: "";
  position: absolute;
  left: 0.4rem; top: 0.5em;
  width: 0.42rem; height: 0.72rem;
  border-right: 2px solid var(--bronze);
  border-bottom: 2px solid var(--bronze);
  transform: rotate(42deg);
}

/* --- Legal content --------------------------------------------------------
   Plain reading content for the Privacy Policy / Terms & Conditions pages.
   The sitewide reset strips list markers from every <ul>, so a dedicated
   bullet style is needed here — .checks (checkbox-style) reads wrong for
   legal disclosure bullets, which aren't a completed-task list. */
.legal { max-width: 46rem; }
/* The contact-info box's email address is one unbroken string long enough
   to overflow a 320px viewport by a couple pixels otherwise. */
.legal .form-card { overflow-wrap: break-word; }
.legal h2 { margin-top: 2.5rem; }
.legal h2:first-child { margin-top: 0; }
.legal p, .legal .legal-list { margin-top: 0.9rem; }
.legal-list { padding-left: 1.3rem; display: grid; gap: 0.5rem; }
.legal-list li { list-style: disc; font-size: 0.9688rem; line-height: 1.65; }
.legal-updated { color: var(--ink-muted); font-size: 0.9375rem; }
/* --ink-muted is calibrated for warm-white backgrounds (5.2:1) — the
   Privacy Policy / Terms page headers use it inside .section--dark, where
   it measured 3.06:1 against the standing contrast-check rule. Same fix
   pattern as .hero__strip-sub: a lighter, warm-white-based muted tone. */
.section--dark .legal-updated { color: rgba(247, 246, 242, 0.72); }

/* --- Chip list -------------------------------------------------------------
   Non-interactive pill tags — used for "Who We Serve", the Southwest Florida
   condition list, and the Service Areas roll call. Deliberately not built on
   .filter (which is a clickable gallery control with hover/active states);
   these never do anything when clicked, so they aren't buttons. */
.chips { display: flex; flex-wrap: wrap; gap: 0.6rem; list-style: none; padding: 0; margin: 0; }
.chips--center { justify-content: center; }

.chip {
  padding: 0.55rem 1.1rem;
  background: var(--paper);
  border: 1px solid var(--rule-bronze);
  border-radius: 2px;
  font-family: var(--font-head);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink);
  white-space: nowrap;
}
/* Same fix as .btn--lg / .btn--wrap: nowrap is right for the usual short
   chips (a couple of words), but a long one — "USMC Military Combat
   Veteran-Led Field Operations," now joined by the license credential chip
   — doesn't fit a 320px screen and was overflowing rather than wrapping. */
@media (max-width: 480px) {
  .chip { white-space: normal; text-align: center; }
}
.section--alt .chip { background: var(--paper); }
.chip--dark {
  background: transparent;
  border-color: rgba(176, 125, 60, 0.45);
  color: var(--warm-white);
}

/* --- Team ------------------------------------------------------------------
   No headshots were supplied. Rather than illustrate a named real person with
   a stand-in stock photo — which would misrepresent who they are — each card
   uses an initials badge in the brand's numbered-marker style (the same
   treatment as .step__num / .svc__num) until real photography is provided. */
.team { display: grid; gap: clamp(1.5rem, 1rem + 2vw, 2.5rem); grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 980px) { .team { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .team { grid-template-columns: minmax(0, 1fr); } }

.team-card {
  padding: clamp(1.75rem, 1.3rem + 1.8vw, 2.5rem);
  background: var(--paper);
  border: 1px solid var(--rule-light);
  border-top: 3px solid var(--bronze);
  border-radius: 3px;
  box-shadow: var(--shadow-card);
}

.team-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  margin-bottom: 1.25rem;
  background: var(--charcoal);
  color: var(--bronze);
  border: 1px solid var(--rule-bronze);
  border-radius: 50%;
  font-family: var(--font-head);
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* .team-card { background: var(--paper) } — always a light card, including
   when the section around it is .section--dark (About page). Scoped under
   .team-card specifically so its specificity (2 classes + type) beats the
   .section--dark h1-h4 rule (1 class + type), which would otherwise turn
   this white-on-white and invisible against the card's own light background. */
.team-card .team-name {
  color: var(--ink);
  font-family: var(--font-head);
  font-size: var(--t-h3);
  text-transform: uppercase;
  line-height: 1.1;
}
.team-role {
  margin-top: 0.35rem;
  font-family: var(--font-head);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bronze-ink);
}
/* Second role line (currently only Jeff's USMC credential) — olive rather
   than bronze so it reads as a distinct credential/badge, not a continuation
   of the job title above it, and sits tighter underneath since the two
   lines are read as one unit. */
.team-role--badge {
  margin-top: 0.15rem;
  color: var(--olive-ink);
}
/* Skills line — deliberately quieter than .team-role (smaller, muted, no
   letter-spacing) so the hierarchy reads title -> skills -> bio, not two
   competing headline-style lines stacked on top of each other. */
.team-tags {
  margin-top: 0.6rem;
  font-family: var(--font-head);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--ink-muted);
}
.team-bio { margin-top: 1rem; font-size: 0.9375rem; line-height: 1.75; color: var(--ink-body); }

/* --- Equipment video (vertical/phone-shot client footage) ------------------
   Framed at a fixed portrait ratio with object-fit: cover rather than forced
   to fill a wide hero — keeps the actual equipment in frame regardless of
   the source clip's exact aspect ratio, and reads intentionally "phone shot"
   rather than like a mis-cropped stock hero. */
.equip-video {
  max-width: 380px;
  margin-inline: auto;
  aspect-ratio: 9 / 16;
  border-radius: 10px;
  overflow: hidden;
  background: var(--char-950);
  box-shadow: var(--shadow-lift);
  border: 1px solid var(--rule-dark);
}
.equip-video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* --- Rating badge ("5.0 stars | 10 Google Reviews") ------------------------ */
.rating-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1.25rem;
  padding: 0.65rem 1.25rem;
  background: var(--paper-alt);
  border: 1px solid var(--rule-bronze);
  border-radius: 2px;
}
.rating-badge__stars { display: inline-flex; gap: 0.15rem; }
.rating-badge__stars svg { width: 1rem; height: 1rem; fill: var(--bronze); }
.rating-badge__score {
  font-family: var(--font-head);
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--ink);
}
.rating-badge__count {
  padding-left: 0.6rem;
  border-left: 1px solid var(--rule-light);
  font-family: var(--font-head);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}

/* --- Review cards -----------------------------------------------------------
   Real, named 5-star Google reviewers, quotes pulled verbatim from Clear
   Path Ground Works' live Google Business Profile — see HANDOFF.md for the
   Place ID and how to re-verify. */
.review-card {
  padding: clamp(1.5rem, 1.1rem + 1.4vw, 2.15rem);
  background: var(--paper);
  border: 1px solid var(--rule-light);
  border-top: 3px solid var(--bronze);
  border-radius: 3px;
  box-shadow: var(--shadow-card);
  text-align: center;
}
.review-card__stars { display: flex; justify-content: center; gap: 0.3rem; margin-bottom: 1rem; }
.review-card__stars svg { width: 1.15rem; height: 1.15rem; fill: var(--bronze); stroke: none; }
.review-card__text { font-size: 0.9375rem; font-style: italic; color: var(--ink-muted); }
.review-card__source {
  margin-top: 0.9rem;
  font-family: var(--font-head);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--bronze-ink);
}
.review-card__name {
  margin-top: 0.85rem;
  font-family: var(--font-head);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
}

/* --- Project cards -----------------------------------------------------
   Photo-forward editorial card. The earlier version paired a small photo
   with a six-row definition list, but once the gallery became all real
   photography most of those rows read "To be added" — 60 of them across 17
   cards — which buried the actual work under placeholder text. The photo is
   the product here, so it now fills the card: title and scope sit ON the
   image over a gradient scrim, and only the facts we genuinely have
   (services, equipment) survive as tags on a slim footer. "Location:
   Southwest Florida" was dropped from every card rather than repeated 17
   times — the section intro and the whole site already say it. */
.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--char-900);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease);
}
.pcard:hover { transform: translateY(-6px); box-shadow: var(--shadow-lift); }

/* flex:1 + height:100% on the photo so a card sharing a grid row with a
   taller neighbour (the two-column .is-wide cells) stretches its photo to
   fill instead of leaving a band of bare card background under the caption.
   aspect-ratio still supplies the intrinsic height when nothing is forcing
   the card taller. */
.pcard__frame { position: relative; flex: 1 1 auto; min-height: 0; }

.pcard__media {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--char-800);
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
}
.pcard__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease-out);
}
.pcard:hover .pcard__media img { transform: scale(1.07); }

/* pointer-events:none is load-bearing — the overlay covers the whole photo,
   and without it the caption would swallow every click meant for the
   lightbox button underneath. */
.pcard__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  pointer-events: none;
  /* Weighted to the bottom on purpose. The middle band is fully clear so
     the photo reads at full strength, and the scrim only ramps up over the
     last quarter where the caption sits — that's the part carrying the
     contrast, so it can't be lightened much further without the scope line
     failing over a bright subject. The top tint is just enough to seat the
     badge; it isn't doing legibility work (the badge has its own fill). */
  background: linear-gradient(to bottom,
              rgba(18,18,18,0.34) 0%,
              rgba(18,18,18,0)    26%,
              rgba(18,18,18,0)    46%,
              rgba(18,18,18,0.58) 78%,
              rgba(18,18,18,0.90) 100%);
}

.pcard__badge {
  align-self: flex-start;
  padding: 0.5rem 0.9rem;
  background: var(--bronze-ink);
  color: #fff;
  font-family: var(--font-head);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-bottom-right-radius: 3px;
}

.pcard__caption { padding: 1.1rem 1.25rem 1.25rem; }
.pcard__title {
  margin: 0;
  font-family: var(--font-head);
  font-size: 1.1875rem;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--warm-white);
}
.pcard__scope {
  margin-top: 0.4rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: rgba(247, 246, 242, 0.86);
}

/* Magnifier that fades in on hover, so it's obvious the photo opens larger
   rather than the card being a link somewhere. */
.pcard__zoom {
  position: absolute;
  top: 50%; left: 50%;
  width: 52px; height: 52px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(247, 246, 242, 0.94);
  color: var(--charcoal);
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.82);
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}
.pcard__zoom svg { width: 22px; height: 22px; }
.pcard:hover .pcard__zoom,
.pcard__media:focus-visible ~ .pcard__overlay .pcard__zoom {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

.pcard__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0.9rem 1.1rem;
  list-style: none;
  background: var(--paper);
  border-top: 3px solid var(--bronze);
  margin-top: auto;
}
.ptag {
  padding: 0.32rem 0.72rem;
  background: var(--paper-alt);
  border: 1px solid var(--rule-light);
  border-radius: 999px;
  font-family: var(--font-head);
  font-size: 0.7188rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-body);
}
/* Equipment reads as a different kind of fact than a service — bronze
   outline separates the two without needing a visible label for each. */
.ptag--equip { border-color: var(--rule-bronze); color: var(--bronze-ink); }

@media (max-width: 480px) {
  .pcard__title { font-size: 1.0625rem; }
  .pcard__caption { padding: 0.9rem 1rem 1rem; }
}

/* --- Before / after slider --------------------------------------------------
   Two photos of the same spot stacked, the "after" clipped at a draggable
   divider so moving it wipes between them.

   Driven by a real <input type="range"> laid transparently over the photo
   rather than custom pointer handlers: that inherits drag, touch, and full
   keyboard control (arrows / Home / End) from the browser, is announced to
   screen readers as a slider, and degrades honestly — if the JS that syncs
   the divider never runs the control is still present and focusable.

   Used only for pairs confirmed to be the same property. These files carry
   no EXIF, so "looks similar" is never sufficient — see HANDOFF 3.6. */
.ba-grid { display: grid; gap: clamp(2.25rem, 1.6rem + 2.4vw, 3.5rem); }

.ba__stage {
  --ba-pos: 50%;
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 4px;
  background: var(--char-800);
  box-shadow: var(--shadow-card);
}
.ba__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Clipped from the divider leftwards, so the right-hand side is the "after"
   and the labels below match what's actually under them. */
.ba__after { position: absolute; inset: 0; clip-path: inset(0 0 0 var(--ba-pos)); }

.ba__divider {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--ba-pos);
  width: 2px;
  margin-left: -1px;
  background: var(--warm-white);
  box-shadow: 0 0 14px rgba(0, 0, 0, 0.55);
  pointer-events: none;
}
.ba__handle {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 46px; height: 46px;
  border-radius: 50%;
  background: var(--warm-white);
  color: var(--charcoal);
  display: grid;
  place-items: center;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
}
.ba__handle svg { width: 22px; height: 22px; }

.ba__label {
  position: absolute;
  top: 1rem;
  padding: 0.42rem 0.82rem;
  font-family: var(--font-head);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  border-radius: 2px;
  pointer-events: none;
}
.ba__label--before { left: 1rem; background: var(--bronze-ink); }
.ba__label--after { right: 1rem; background: var(--olive-ink); }

/* The range fills the stage and is invisible — the divider above is the
   visible affordance. A wide, full-height thumb makes the whole column
   grabbable rather than just a hairline. */
.ba__range {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: ew-resize;
}
.ba__range::-webkit-slider-runnable-track { height: 100%; background: transparent; }
.ba__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 46px; height: 46px;
  background: transparent;
  border: 0;
  cursor: ew-resize;
}
.ba__range::-moz-range-track { height: 100%; background: transparent; }
.ba__range::-moz-range-thumb {
  width: 46px; height: 46px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: ew-resize;
}
.ba__range:focus { outline: none; }
.ba__range:focus-visible { outline: 3px solid var(--bronze); outline-offset: 3px; }

.ba__cap { margin-top: 1.1rem; }
.ba__title {
  margin: 0;
  font-family: var(--font-head);
  font-size: var(--t-h4);
  text-transform: uppercase;
  color: var(--ink);
}
.ba__hint {
  margin-top: 0.35rem;
  font-size: 0.8125rem;
  color: var(--ink-muted);
}
.ba__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.85rem 0 0;
  padding: 0;
  list-style: none;
}

@media (max-width: 560px) {
  .ba__handle { width: 38px; height: 38px; }
  .ba__handle svg { width: 18px; height: 18px; }
  .ba__label { top: 0.65rem; font-size: 0.65rem; padding: 0.35rem 0.6rem; }
  .ba__label--before { left: 0.65rem; }
  .ba__label--after { right: 0.65rem; }
}

/* ==========================================================================
   10. MEDIA FRAMES
   ========================================================================== */

/* Image with an offset bronze rule behind it — the "surveyed edge" motif. */
.frame { position: relative; }
.frame::before {
  content: "";
  position: absolute;
  inset: auto -14px -14px auto;
  width: 62%;
  height: 62%;
  border-right: 3px solid var(--bronze);
  border-bottom: 3px solid var(--bronze);
  z-index: 0;
}
.frame img {
  position: relative;
  z-index: 1;
  width: 100%;
  border-radius: 3px;
  box-shadow: var(--shadow-card);
}
.frame--flip::before { inset: -14px auto auto -14px; border: none; border-left: 3px solid var(--bronze); border-top: 3px solid var(--bronze); }

@media (max-width: 640px) {
  .frame::before { display: none; }
}

/* ==========================================================================
   11. GALLERY
   ========================================================================== */

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: clamp(0.85rem, 0.6rem + 1vw, 1.35rem);
  /* dense so that when a filter hides cards, the remaining wide cells
     backfill instead of leaving holes in the grid. */
  grid-auto-flow: dense;
}

/* A few landscape-source photos run full-bleed across two columns, so the
   gallery reads as an edited spread rather than a uniform contact sheet.
   Only above 700px — at one column a span of 2 would overflow the track. */
@media (min-width: 700px) {
  .gallery > li.is-wide { grid-column: span 2; }
  .gallery > li.is-wide .pcard__media { aspect-ratio: 16 / 9; }
  .gallery > li.is-wide .pcard__title { font-size: 1.4375rem; }
}

.shot {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 3px;
  background: var(--char-800);
  aspect-ratio: 4 / 3;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: left;
  width: 100%;
}
.shot img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.75s var(--ease-out), filter 0.5s var(--ease);
}
.shot:hover img { transform: scale(1.07); filter: brightness(0.72); }

.shot__cap {
  position: absolute;
  inset: auto 0 0 0;
  padding: 1.5rem 1.15rem 1.05rem;
  background: linear-gradient(to top, rgba(15,15,15,.9), rgba(15,15,15,0));
  color: var(--warm-white);
  transform: translateY(6px);
  opacity: 0;
  transition: transform 0.4s var(--ease), opacity 0.4s var(--ease);
}
.shot:hover .shot__cap, .shot:focus-visible .shot__cap { transform: none; opacity: 1; }

.shot__title {
  font-family: var(--font-head);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  line-height: 1.15;
}
.shot__meta {
  margin-top: 0.28rem;
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* --bronze-lift, not --bronze: measured 4.32:1 against the caption's dark
     scrim with longer real-project captions, just under the 4.5:1 minimum.
     --bronze-lift is the same brand color, lightened, already used
     elsewhere for exactly this "needs more contrast on dark" case. */
  color: var(--bronze-lift);
}

/* Tag filter buttons */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin-bottom: clamp(1.75rem, 1.2rem + 1.6vw, 2.75rem);
}
.filter {
  padding: 0.6rem 1.15rem;
  background: transparent;
  border: 1px solid var(--rule-light);
  border-radius: 2px;
  font-family: var(--font-head);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
  cursor: pointer;
  /* Explicit property list, never `all` — see the note on .lightbox__close. */
  transition: background-color 0.28s var(--ease),
              border-color 0.28s var(--ease),
              color 0.28s var(--ease);
}
.filter:hover { border-color: var(--bronze); color: var(--bronze-ink); }
.filter.is-active {
  background: var(--charcoal);
  border-color: var(--charcoal);
  color: var(--warm-white);
}

/* --- Lightbox ------------------------------------------------------------ */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(12, 12, 12, 0.94);
  opacity: 0;
  visibility: hidden;
  /* Same stepped-visibility pattern as .drawer — see the note there. */
  transition: opacity 0.3s var(--ease), visibility 0s linear 0.3s;
}
.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s var(--ease), visibility 0s linear 0s;
}
.lightbox__fig { margin: 0; max-width: min(1100px, 100%); max-height: 100%; }
.lightbox__img {
  width: 100%;
  max-height: 78vh;
  object-fit: contain;
  border-radius: 3px;
}
.lightbox__cap {
  margin-top: 1rem;
  text-align: center;
  font-family: var(--font-head);
  font-size: 1.15rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warm-white);
}
.lightbox__close {
  position: absolute;
  top: clamp(0.75rem, 2vw, 1.5rem);
  right: clamp(0.75rem, 2vw, 1.5rem);
  width: 48px; height: 48px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid rgba(247,246,242,.35);
  border-radius: 2px;
  color: var(--warm-white);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  /* Must NOT be `transition: all`. The shorthand includes `visibility`, and
     this button inherits visibility from .lightbox — so `all` made the button
     spend 0.25s still computed as hidden after the dialog opened, and a hidden
     element cannot take focus(). That silently broke keyboard access to the
     close button. Transition only what actually needs animating. */
  transition: background-color 0.25s var(--ease),
              border-color 0.25s var(--ease),
              color 0.25s var(--ease);
}
.lightbox__close:hover { background: var(--bronze); border-color: var(--bronze); }

/* ==========================================================================
   12. CTA BANDS
   ========================================================================== */

.cta {
  position: relative;
  overflow: hidden;
  background: var(--charcoal);
  color: var(--warm-white);
  isolation: isolate;
}
.cta__media { position: absolute; inset: 0; z-index: -2; }
.cta__media img { width: 100%; height: 100%; object-fit: cover; }
.cta__scrim {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(95deg, rgba(15,15,15,.95) 0%, rgba(18,18,18,.86) 45%, rgba(20,20,20,.55) 100%);
}
.cta__inner { max-width: 46rem; padding-block: clamp(3.5rem, 2.2rem + 4.5vw, 6.5rem); }
.cta__title { font-size: var(--t-h2); color: var(--warm-white); }
.cta__text { margin-top: 1.15rem; font-size: var(--t-lead); color: rgba(247,246,242,.82); }
.cta__actions { margin-top: 2rem; }

/* ==========================================================================
   13. FORMS
   ========================================================================== */

.form-card {
  background: var(--paper);
  border: 1px solid var(--rule-light);
  border-top: 4px solid var(--bronze);
  border-radius: 3px;
  padding: clamp(1.5rem, 1.1rem + 1.8vw, 2.75rem);
  box-shadow: var(--shadow-card);
}

/* Emergency storm callout beside the estimate form on the home page's
   Contact section — olive, not bronze, so it reads as a distinct "this one
   is different" block rather than a second copy of the form card, matching
   the storm bar's color language used for every other emergency touchpoint. */
.form-card--emergency {
  border-top-color: var(--olive);
  background: var(--paper-alt);
}

.field-grid { display: grid; gap: 1.15rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.field-grid > .field--full { grid-column: 1 / -1; }
@media (max-width: 640px) { .field-grid { grid-template-columns: minmax(0, 1fr); } }

/* min-width: 0 defeats the grid blowout. Grid items default to
   `min-width: auto`, which means they refuse to shrink below the intrinsic
   width of their content — and <input>/<select> carry a default intrinsic
   width (roughly `size=20`) regardless of `width: 100%`. Without this, the
   form pushed the whole page ~5px wider than a 375px viewport. */
.field { display: flex; flex-direction: column; gap: 0.42rem; min-width: 0; }
.field-grid > *, .choices > * { min-width: 0; }
.field input, .field select, .field textarea { min-width: 0; }

.field label,
.fieldset__legend {
  font-family: var(--font-head);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink);
}
.field .req { color: var(--bronze-ink); }

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.85rem 1rem;
  background: var(--warm-white);
  border: 1px solid rgba(30,30,30,.18);
  border-radius: 2px;
  font-size: 0.9688rem;
  color: var(--ink);
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease), background-color 0.25s var(--ease);
}
.field textarea { min-height: 150px; resize: vertical; }

.field input::placeholder, .field textarea::placeholder { color: #9A9A92; }

.field input:hover, .field select:hover, .field textarea:hover { border-color: rgba(30,30,30,.34); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  background: var(--paper);
  border-color: var(--bronze);
  box-shadow: 0 0 0 3px var(--bronze-glow);
}
/* Keep the keyboard ring for users who tab in. */
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  outline: 3px solid var(--bronze);
  outline-offset: 2px;
}

.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%231E1E1E' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 12px;
  padding-right: 2.6rem;
}

.field__hint { font-size: 0.8125rem; color: var(--ink-muted); }

.fieldset { border: 0; padding: 0; margin: 0; }
.fieldset__legend { padding: 0; margin-bottom: 0.7rem; }

/* min(190px, 100%) so the track never demands more width than the container
   has, which would otherwise overflow on narrow phones. */
.choices { display: grid; gap: 0.55rem; grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); }
.choice {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0.9rem;
  background: var(--warm-white);
  border: 1px solid rgba(30,30,30,.18);
  border-radius: 2px;
  font-size: 0.9062rem;
  cursor: pointer;
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.choice:hover { border-color: var(--bronze); }
.choice input { width: 1.05rem; height: 1.05rem; accent-color: var(--bronze); flex: none; }
.choice:has(input:checked) { border-color: var(--bronze); background: #FBF7F1; }

/* Netlify honeypot — visually hidden but reachable by bots. */
.hp { position: absolute; left: -9999px; opacity: 0; height: 0; overflow: hidden; }

/* --- SMS opt-in consent ----------------------------------------------------
   Deliberately NOT a .choice (that's for the required Service/Contact-Method
   groups). This one is optional, unchecked by default, and carries a full
   paragraph of A2P 10DLC disclosure text rather than a short label — see
   HANDOFF.md for why the checkbox and the language are both required as
   written, not just "nice to have" boilerplate. */
.consent {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.9rem 1rem;
  background: var(--paper-alt);
  border: 1px solid rgba(30,30,30,.14);
  border-radius: 2px;
  cursor: pointer;
}
.consent input {
  margin-top: 0.2rem;
  width: 1.15rem; height: 1.15rem;
  accent-color: var(--bronze);
  flex: none;
}
.consent__text { font-size: 0.8125rem; line-height: 1.6; color: var(--ink-muted); }
.consent__text a { color: var(--bronze-ink); }

/* --- Contact detail list ------------------------------------------------- */
.detail { display: grid; gap: 1.5rem; }
.detail__item { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 1rem; align-items: start; }
.detail__icon {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  background: var(--bronze);
  color: #fff;
  border-radius: 2px;
  flex: none;
}
.detail__icon svg { width: 20px; height: 20px; }
.detail__label {
  font-family: var(--font-head);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bronze);
  margin-bottom: 0.15rem;
}
/* Same unbreakable-email reasoning as .footer__contact a. */
.detail__value { font-size: 1.0625rem; line-height: 1.5; color: var(--warm-white); overflow-wrap: anywhere; }
.detail__value a { color: var(--warm-white); text-decoration: none; }
.detail__value a:hover { color: var(--bronze); }
.section--paper .detail__value, .section--alt .detail__value { color: var(--ink); }
/* .detail was originally built for a dark contact-info band; --bronze on
   warm-white/paper (3.59:1) fails AA there, same failure mode as the
   .btn--primary fix above. --bronze-ink is the light-background-safe shade
   already used everywhere else this pairing comes up (.eyebrow, links). */
.section--paper .detail__label, .section--alt .detail__label { color: var(--bronze-ink); }
.section--paper .detail__value a, .section--alt .detail__value a { color: var(--ink); }

/* ==========================================================================
   14. FAQ / ACCORDION
   ========================================================================== */

.faq { border-top: 1px solid var(--rule-light); }
.faq__item { border-bottom: 1px solid var(--rule-light); }

.faq__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1.35rem 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  font-family: var(--font-head);
  font-size: clamp(1.15rem, 1.05rem + 0.45vw, 1.4rem);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink);
  transition: color 0.25s var(--ease);
}
.faq__q:hover { color: var(--bronze-ink); }

.faq__sign { position: relative; width: 18px; height: 18px; flex: none; }
.faq__sign::before, .faq__sign::after {
  content: "";
  position: absolute;
  background: var(--bronze);
  transition: transform 0.35s var(--ease);
}
.faq__sign::before { inset: 8px 0 auto 0; height: 2px; }
.faq__sign::after  { inset: 0 auto 0 8px; width: 2px; }
.faq__q[aria-expanded="true"] .faq__sign::after { transform: scaleY(0); }

/* Height animation via grid-template-rows so no JS measurement is needed. */
.faq__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s var(--ease);
}
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { padding-bottom: 1.5rem; max-width: 72ch; font-size: 0.9688rem; }

/* ==========================================================================
   15. FOOTER
   ========================================================================== */

.footer { background: var(--char-950); color: rgba(247,246,242,.72); }

.footer__top {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1.3fr;
  gap: clamp(2rem, 1.2rem + 3vw, 3.5rem);
  padding-block: clamp(3rem, 2rem + 3.5vw, 5rem);
}
@media (max-width: 980px) { .footer__top { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 560px) { .footer__top { grid-template-columns: minmax(0,1fr); } }

/* Larger here than in the header: the footer has the room, and the badge's
   illustrated detail is the strongest brand asset on the page. */
.footer__logo { height: 104px; width: auto; margin-bottom: 1rem; }

.footer__wordmark {
  display: flex;
  flex-direction: column;
  line-height: 1;
  font-family: var(--font-head);
  text-transform: uppercase;
  color: var(--warm-white);
  margin-bottom: 1.15rem;
}
.footer__wordmark-name { font-size: 1.55rem; font-weight: 700; letter-spacing: 0.05em; }
.footer__wordmark-sub {
  display: flex; align-items: center; gap: 0.5rem; margin-top: 0.35rem;
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.28em; color: var(--bronze);
}
.footer__wordmark-sub::before { content: ""; width: 18px; height: 2px; background: var(--bronze); flex: none; }
.footer__blurb { font-size: 0.9375rem; line-height: 1.75; max-width: 34ch; }

.footer__tagline {
  margin-top: 1.1rem;
  font-family: var(--font-head);
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--bronze);
}

.footer__title {
  font-family: var(--font-head);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--warm-white);
  margin-bottom: 1.15rem;
  padding-bottom: 0.65rem;
  border-bottom: 2px solid var(--bronze);
  display: inline-block;
}

.footer__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.6rem; }
.footer__list a {
  font-size: 0.9375rem;
  color: rgba(247,246,242,.72);
  text-decoration: none;
  transition: color 0.25s var(--ease), padding-left 0.25s var(--ease);
}
.footer__list a:hover { color: var(--bronze); padding-left: 0.28rem; }

.footer__contact { display: grid; gap: 0.9rem; font-size: 0.9375rem; }
.footer__contact-row { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 0.7rem; align-items: start; }
.footer__contact-row svg { width: 1.05rem; height: 1.05rem; color: var(--bronze); margin-top: 0.32rem; flex: none; }
.footer__contact a {
  color: rgba(247,246,242,.85);
  text-decoration: none;
  /* An email address is a single unbreakable token. At 320px the 30-character
     address is wider than its grid column and pushed the page sideways, so it
     is allowed to break mid-word rather than overflow. */
  overflow-wrap: anywhere;
}
.footer__contact a:hover { color: var(--bronze); }

.footer__cta { margin-top: 1.4rem; }

/* Service-area city list. Sits between the footer columns and the legal row
   on every page. Uses --bronze-lift for the label rather than --bronze for
   the same reason .shot__meta does — plain bronze does not clear 4.5:1
   against the footer's dark ground. */
.footer__areas {
  border-top: 1px solid var(--rule-dark);
  padding-block: 1.3rem;
  font-size: 0.875rem;
  line-height: 1.7;
}

.footer__areas-label {
  font-family: var(--font-head);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bronze-lift);
  margin-right: 0.5ch;
}

.footer__bottom {
  border-top: 1px solid var(--rule-dark);
  padding-block: 1.6rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.85rem 1.5rem;
  font-size: 0.8125rem;
}
.footer__legal { display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; }
.footer__legal a { color: rgba(247,246,242,.6); text-decoration: none; }
.footer__legal a:hover { color: var(--bronze); }

.footer__credit { color: rgba(247,246,242,.55); }
.footer__credit a {
  color: var(--bronze);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s var(--ease);
}
.footer__credit a:hover { border-bottom-color: var(--bronze); }

/* ==========================================================================
   16. SCROLL REVEAL
   ---------------------------------------------------------------------------
   Scoped to html.js so the page renders fully visible when scripting is off.
   ========================================================================== */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}
.js [data-reveal].is-in { opacity: 1; transform: none; }

/* Stagger children of a revealed group. */
.js [data-reveal-group] > * {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}
.js [data-reveal-group].is-in > * { opacity: 1; transform: none; }
.js [data-reveal-group].is-in > *:nth-child(1) { transition-delay: 0s; }
.js [data-reveal-group].is-in > *:nth-child(2) { transition-delay: .08s; }
.js [data-reveal-group].is-in > *:nth-child(3) { transition-delay: .16s; }
.js [data-reveal-group].is-in > *:nth-child(4) { transition-delay: .24s; }
.js [data-reveal-group].is-in > *:nth-child(5) { transition-delay: .32s; }
.js [data-reveal-group].is-in > *:nth-child(6) { transition-delay: .40s; }
.js [data-reveal-group].is-in > *:nth-child(7) { transition-delay: .48s; }
.js [data-reveal-group].is-in > *:nth-child(8) { transition-delay: .56s; }

/* ==========================================================================
   17. UTILITIES
   ========================================================================== */

.u-center { text-align: center; }
.u-mt-0 { margin-top: 0; }
.u-mt-1 { margin-top: 1rem; }
.u-mt-2 { margin-top: 2rem; }
.u-mt-3 { margin-top: 3rem; }
.u-mb-2 { margin-top: 0; margin-bottom: 2rem; }
.u-maxw { max-width: 62ch; }

/* Bronze rule used as a standalone divider. */
.rule-cut {
  width: 68px;
  height: 3px;
  background: var(--bronze);
  border: 0;
  margin: 0 0 1.5rem;
}
.rule-cut--center { margin-inline: auto; }

/* ==========================================================================
   18. MOTION & PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Reveal elements must not stay invisible if their transition is nulled. */
  .js [data-reveal],
  .js [data-reveal-group] > * { opacity: 1 !important; transform: none !important; }
  .btn:hover, .svc:hover, .icard:hover { transform: none; }
}

@media print {
  .header, .drawer, .stormbar, .burger, .lightbox, .cta, .footer__cta { display: none !important; }
  body { background: #fff; color: #000; }
  .hero { min-height: auto; padding-top: 2rem; }
  .hero__media, .hero__scrim { display: none; }
  .hero__title, .hero__tagline, .hero__text { color: #000 !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.8em; }
}
