/* ==========================================================================
   Viva Roofing Inc — site stylesheet (from tools/website_starter)

   Header style: DARK by default (standards §4: match-legacy-else-dark).

   ── COLOR CONTRACT — fill this in, do not delete it ─────────────────────────
   scaffold.py writes --primary / --accent / --accent-hover from config.json's
   brand block. Every DERIVED token below (--primary-deep, --accent-ink,
   --on-dark, --muted-on-dark, --on-accent) is a claim about a contrast ratio:
   COMPUTE it for this brand and write the number beside it. Do not transcribe
   the previous client's numbers. Rules that decided the values on the last
   build, all in docs/website_build_standards.md Rule 12:
     - an accent-on-dark token is calibrated for ONE ground; name the ground
     - hover must never be worse than resting
     - white on a saturated brand color usually FAILS AA; the fix is a dark
       label (--on-accent = --ink), never darkening the brand until it is brown.
       If the operator overrides that, document it here as an ACCEPTED EXCEPTION
       with the measured ratio, so the QA gate's contrast nodes can be read.
   ========================================================================== */

:root {
  /* Viva Roofing, computed 2026-10-03 (WCAG relative luminance). Brand purple #a860fc and
     orange #f09c60 from the logo; the old Topline site was dark chrome with purple accents,
     so the dark grounds are deep purples rather than slate. */
  --primary: #2B1A4A;         /* deep brand purple ground; white on it 15.56:1 */
  --primary-dark: #24153F;    /* hero overlay ground */
  --primary-deep: #1C1033;    /* trust bar, CTA band, stats, panels; white 17.93:1 */
  --footer-bg: #140B26;       /* one step below deep; --muted-on-dark 11.6:1, --on-dark 9.66:1 */

  --accent: #f09c60;          /* brand orange — FILLS only (brand.accent_color) */
  --on-accent: #111827;       /* DARK label on orange: 8.13:1 (white would be 2.18:1, fails) */
  --accent-hover: #F6B98C;    /* lighter orange; dark label 10.34:1, so hover beats resting (Rule 12) */
  --accent-ink: #7B3FD6;      /* purple TEXT on white — links, icons, stars: 5.96:1 (5.56 on --surface) */
  --accent-ink-dark: #6431B5;
  --accent-tint: #F3ECFE;     /* pale purple ground */
  --on-dark: #F4A86F;         /* orange text on --primary-deep 9.12:1, on --header-bg 8.64:1 */
  --brand-purple-on-dark: #C9A6FF; /* purple text on --primary-deep 8.86:1 */
  --muted-on-dark: #CFC6E2;   /* secondary text on deep 10.95:1 */
  --warm: #F7F1EA;

  --ink: #23272A;
  --body: #3F464B;
  --muted: #5C646A;
  --line: #E1E4E6;
  --surface: #F6F7F8;
  --surface-2: #ECEEF0;
  --white: #ffffff;

  /* DARK header. The rebuild SOP's rule is "header match-legacy-else-dark" and
     the client's legacy Hugo site is the brand slate, so dark is the default
     here, not a preference. The estate runs both (mnz #111111, lasim #0F1729
     dark; latorre, triumph, sunstate light) — the tiebreak is the legacy site.
     Contrast: white on #4E5255 is 7.89:1. */
  --header-bg: #22143D;   /* white 17.0:1 */
  --header-text: #ffffff;
  --header-line: #3A2860;
  /* the mobile slide-in panel is white too — see the mobile block below, where
     every inherited dark-ground color has to be restated or the submenu links
     render white-on-white. This is the light/dark header port trap, and it is
     NOT fixable with a :root swap. */
  /* The slide-in panel is #2F3234, NOT the #4E5255 header it slides out of.
     Two reasons, both measured. It gives the panel its own ground so it reads
     as a surface rather than a continuation of the header; and --on-dark
     (#F29326) is calibrated for #2F3234, where it is 5.52:1 — on #4E5255 it is
     3.37:1 and fails AA for normal text. Every other dark surface on this site
     (trust bar, footer, stats bar, CTA band, dark sidebar card) is already
     #2F3234, so this is the panel joining them, not a new value. */
  --panel-bg: #1C1033;

  --font-head: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --wrap: 1180px;
  --radius: 14px;
  --shadow: 0 1px 2px rgba(35,39,42,.05), 0 8px 24px rgba(35,39,42,.07);
  --shadow-lg: 0 2px 4px rgba(35,39,42,.05), 0 22px 50px rgba(35,39,42,.16);
}

/* ── reset ───────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  color: var(--body);
  background: var(--white);
}
img { max-width: 100%; height: auto; display: block; }
h1, h2, h3, h4 { font-family: var(--font-head); color: var(--ink); line-height: 1.2; margin: 0 0 .55em; }
h1 { font-size: clamp(2.1rem, 4.6vw, 3.35rem); font-weight: 800; letter-spacing: -.025em; }
h2 { font-size: clamp(1.65rem, 3.1vw, 2.35rem); font-weight: 700; letter-spacing: -.018em; text-wrap: balance; }
h3 { font-size: 1.2rem; font-weight: 700; }
p { margin: 0 0 1.1em; }
a { color: var(--accent-ink); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 3px solid var(--accent-ink); outline-offset: 2px; border-radius: 3px;
}
.wrap { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }
.section { padding: clamp(3.5rem, 7vw, 6rem) 0; }
.section-alt { background: var(--surface); }
.section-sub { max-width: 64ch; color: var(--muted); font-size: 1.06rem; margin-bottom: 2.4rem; }
.icon { flex: none; vertical-align: -.18em; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--white); color: var(--accent-ink); padding: .8rem 1.2rem; font-weight: 600;
}
.skip-link:focus { left: 0; }

/* ── buttons ──────────────────────────────────────────────────────────────
   Rule 12: base colors carry NO !important, so a container can restyle a
   button by specificity rather than by fighting it. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font-family: var(--font-head); font-weight: 700; font-size: 1rem;
  padding: .95rem 1.7rem; border-radius: 999px; border: 2px solid transparent;
  text-decoration: none; cursor: pointer; transition: background-color .15s, color .15s, border-color .15s;
}
.btn-accent { background: var(--accent); color: var(--on-accent); }
.btn-accent:hover, .btn-accent:focus-visible { background: var(--accent-hover); color: var(--on-accent); }
.btn-outline { background: transparent; color: var(--accent-ink); border-color: var(--accent-ink); }
.btn-outline:hover, .btn-outline:focus-visible { background: var(--accent-ink); color: var(--white); }
/* on slate grounds: a white-outlined button, since copper fails there */
.btn-ondark { background: transparent; color: var(--white); border-color: rgba(255,255,255,.75); }
.btn-ondark:hover, .btn-ondark:focus-visible { background: var(--white); color: var(--primary); border-color: var(--white); }
.btn-block { width: 100%; }

/* ── trust bar ────────────────────────────────────────────────────────────── */
.trust-bar { background: var(--primary-deep); color: var(--muted-on-dark); font-size: .875rem; }
.trust-bar-inner { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem 1.6rem; padding: .55rem 0; }
.trust-item { display: inline-flex; align-items: center; gap: .4rem; }
.trust-item .icon { color: var(--on-dark); }
.trust-call { margin-left: auto; color: var(--white); font-weight: 600; text-decoration: none; }
.trust-call:hover { text-decoration: underline; }
@media (max-width: 720px) { .trust-bar { display: none; } }

/* ── header ───────────────────────────────────────────────────────────────── */
header {
  position: sticky; top: 0; z-index: 100;
  background: var(--header-bg); border-bottom: 1px solid var(--header-line);
  box-shadow: 0 1px 3px rgba(35,39,42,.05);
}
.header-inner { display: flex; align-items: center; justify-content: space-between; gap: 1.2rem; padding: .6rem 0; min-height: 76px; }
.logo { display: block; flex: none; }
.logo img { width: auto; height: 44px; }

.nav-desktop { display: flex; align-items: center; gap: .25rem; list-style: none; margin: 0; padding: 0; }
/* Rule 12 again: :not(.btn) sits on BOTH the base rule and the hover rule.
   Without it on the base rule, .nav-call's resting label inherits this color.

   ── THE `> li >` IS LOAD-BEARING. DO NOT FLATTEN IT BACK TO A DESCENDANT. ───
   This rule is for TOP-LEVEL links only. Written as a descendant selector it
   also matched every link inside .sub, and it BEAT both submenu rules on
   specificity, because :not() contributes its argument's weight:

     .nav-desktop a:not(.btn):not(.nav-call):not(.nav-quote)   (0,4,1)  WON
     .nav-desktop .sub a:not(.btn)                             (0,3,1)  lost
     .nav-desktop .sub-all a                                   (0,2,1)  lost

   So every dropdown link took --header-text (white) and rendered white-on-white
   on the .sub card: both desktop dropdowns were BLANK, sitewide. Nothing caught
   it, and nothing was going to — the dropdown is visibility:hidden at rest, so
   axe never measures it, and mobile masks it because white on the slate panel
   is perfectly readable. Only hovering it on desktop shows the bug.

   The child combinator is the fix rather than more :not()s: these links are not
   in .sub, so the rule should never have reached them in the first place. */
.nav-desktop > li > a:not(.btn):not(.nav-call):not(.nav-quote) {
  display: block; padding: .6rem .8rem; border-radius: 8px;
  color: var(--header-text); text-decoration: none; font-weight: 600; font-size: .97rem;
}
.nav-desktop > li > a:not(.btn):not(.nav-call):not(.nav-quote):hover,
.nav-desktop > li > a:not(.btn):not(.nav-call):not(.nav-quote):focus-visible { background: rgba(255,255,255,.12); }
/* The call button is excluded from BOTH rules above rather than overriding them
   with !important. A hover-only exclusion would leave its RESTING label taking
   the nav link color — the failure mode that reads fine on screen and fails
   axe at the base state. */
.nav-cta { margin-left: .35rem; }
/* outlined quote button, then the filled phone button — the estate's pair */
.nav-desktop a.nav-quote { display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--white); border: 1.5px solid rgba(255,255,255,.55);
  padding: .62rem 1.15rem; border-radius: 8px; text-decoration: none; font-weight: 700; font-size: .95rem; }
.nav-desktop a.nav-quote:hover, .nav-desktop a.nav-quote:focus-visible {
  background: rgba(255,255,255,.14); border-color: var(--white); color: var(--white); }
.nav-desktop a.nav-call { display: inline-flex; align-items: center; gap: .45rem;
  background: var(--accent); color: var(--on-accent); padding: .62rem 1.15rem; border-radius: 8px;
  text-decoration: none; font-weight: 700; font-size: .95rem; }
.nav-desktop a.nav-call:hover, .nav-desktop a.nav-call:focus-visible { background: var(--accent-hover); color: var(--on-accent); }

.has-sub { position: relative; }
.sub {
  position: absolute; left: 0; top: 100%; min-width: 250px;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); list-style: none; margin: 0; padding: .4rem;
  opacity: 0; visibility: hidden; transform: translateY(6px); transition: opacity .15s, transform .15s, visibility .15s;
}
.has-sub:hover > .sub, .has-sub:focus-within > .sub { opacity: 1; visibility: visible; transform: translateY(0); }
/* These now style themselves completely: the base rule above no longer
   reaches them, so display, text-decoration and radius have to be restated
   here or the dropdown renders as underlined inline text. */
.nav-desktop .sub a:not(.btn) { display: block; padding: .55rem .7rem; border-radius: 8px;
  color: var(--body); text-decoration: none; font-weight: 500; font-size: .97rem; }
.nav-desktop .sub a:not(.btn):hover,
.nav-desktop .sub a:not(.btn):focus-visible { background: var(--surface); color: var(--accent-ink); }
/* :not(.btn) here only to match the specificity of .sub a:not(.btn) above —
   at (0,3,1) they tie and this one wins on source order. Without it this rule
   is (0,2,1) and the emphasis link silently takes the ordinary link color. */
.nav-desktop .sub-all a:not(.btn) { font-weight: 700; color: var(--accent-ink); border-top: 1px solid var(--line); margin-top: .25rem; }

/* Border at .55 not .40: composited over the #4E5255 header, .40 gives
   #959799 = 2.69:1 against it, under the 3:1 that WCAG 1.4.11 wants for a
   control boundary. .55 gives #AFB1B2 = 3.66:1, and matches .nav-quote. */
.hamburger { display: none; flex-direction: column; justify-content: center; gap: 5px; width: 46px; height: 42px; margin-left: auto; padding: 0 10px; background: transparent; border: 1px solid rgba(255,255,255,.55); border-radius: 10px; cursor: pointer; }
.hamburger span { display: block; height: 2px; background: var(--white); border-radius: 2px; transition: transform .2s, opacity .2s; }

/* ── mobile nav (Rule 25) ─────────────────────────────────────────────────── */
@media (max-width: 980px) {
  .hamburger { display: flex; }
  .nav {
    position: fixed; inset: 0 0 0 auto; width: min(86vw, 360px);
    background: var(--panel-bg); border-left: 1px solid var(--header-line);
    padding: 5.5rem 1.1rem 2rem; overflow-y: auto;
    /* the closed state */
    transform: translateX(100%); transition: transform .25s ease; z-index: 120;
  }
  /* Rule 25: EVERY state resets the transform explicitly — never rely on the
     desktop rule not having applied. */
  body.nav-open .nav { transform: translateX(0); }
  .nav-desktop { flex-direction: column; align-items: stretch; gap: .15rem; }
  .nav-desktop > li > a:not(.btn) { padding: .85rem .7rem; font-size: 1.05rem; }
  .nav-cta { margin-left: 0; }
  .nav-desktop a.nav-quote, .nav-desktop a.nav-call { width: 100%; margin-top: .6rem; padding: .8rem 1rem; }

  /* submenus fold rather than float */
  .sub {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: 0; border-left: 2px solid var(--header-line);
    border-radius: 0; background: transparent; margin: 0 0 .4rem .7rem; padding: 0 0 0 .5rem;
    display: none;
  }
  .has-sub.open > .sub { display: block; }
  .has-sub:hover > .sub, .has-sub:focus-within > .sub { transform: none; }
  /* submenu links sit on the SLATE panel here, not on white — the desktop rule
     above sets them to --body, which is invisible on slate. This is the exact
     bug a light-to-dark header port leaves behind. */
  /* The desktop submenu rule sets these links to --body, which is invisible
     on a dark panel, so each color is restated here for the dark ground rather
     than swapped at :root. Measured on --panel-bg #2F3234: --muted-on-dark
     7.50:1, --white on the hover ground 8.80:1, --on-dark 5.52:1.
     (The previous note here claimed --on-dark was 4.51:1 on #4E5255. It is
     3.37:1. That number was never true, and it was the reason the panel ground
     looked safe.) */
  .nav-desktop .sub a:not(.btn) { color: var(--muted-on-dark); }
  .nav-desktop .sub a:not(.btn):hover,
  .nav-desktop .sub a:not(.btn):focus-visible { background: rgba(255,255,255,.12); color: var(--white); }
  .nav-desktop .sub-all a:not(.btn) { color: var(--on-dark); border-top-color: var(--header-line); }

  /* The panel is z-index 120 and the header only 100, so the burger was BURIED
     under the open panel — the X was unclickable and Escape was the only way
     out. Lift it above the panel while open. Rule 25 wants burger -> X, and an
     X you cannot press is not a close control. */
  body.nav-open .hamburger { position: relative; z-index: 130; border-color: rgba(255,255,255,.55); background: var(--primary); }
  body.nav-open .hamburger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  body.nav-open .hamburger span:nth-child(2) { opacity: 0; }
  body.nav-open .hamburger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
  body.nav-open { overflow: hidden; }
}

/* ── hero ─────────────────────────────────────────────────────────────────── */
.hero { position: relative; background: var(--primary-deep); overflow: hidden; }
.hero-bg { position: absolute; inset: 0; }
.hero-bg img { width: 100%; height: 100%; object-fit: cover; }
/* Directional veil. Stops chosen from measurement, not taste: at 0.72 over the
   photo's BRIGHTEST pixel white still reads 6.16:1, and over the roof itself
   11.5:1. It then falls to 0.18 on the form side, where no text sits, so the
   photograph is actually visible. A flat 0.9 wash — the first attempt here —
   makes the hero a gray box and wastes the only asset a competitor cannot copy. */
.hero-overlay { position: absolute; inset: 0; background:
  linear-gradient(100deg,
    rgba(47,50,52,.88) 0%,
    rgba(47,50,52,.78) 34%,
    rgba(47,50,52,.46) 62%,
    rgba(47,50,52,.20) 100%); }
/* bottom scrim so the trust row stays legible over a bright lower edge */
.hero-overlay::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(35,38,40,.55) 0%, transparent 34%); }

.hero-inner { position: relative; z-index: 1; display: grid; grid-template-columns: 1.02fr .98fr;
  gap: clamp(2rem, 4.5vw, 4rem); align-items: center; padding: clamp(3rem, 6vw, 5.5rem) 0; }
.hero h1 { color: var(--white); line-height: 1.04; letter-spacing: -.03em;
  font-size: clamp(2.4rem, 5.2vw, 4rem); text-wrap: balance; }
.hero-sub { color: #EDEFF0; font-size: 1.16rem; line-height: 1.62; max-width: 48ch; }

/* pill eyebrow badge on a white chip, like the rest of the estate */
.eyebrow-chip { display: inline-flex; align-items: center; gap: .5rem; background: var(--white);
  border: 1px solid var(--line); border-radius: 999px; padding: .5rem 1rem; margin-bottom: 1.4rem;
  font-family: var(--font-head); font-weight: 700; font-size: .8rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--accent-ink); box-shadow: 0 1px 3px rgba(35,39,42,.06); }
.eyebrow-chip .icon { color: var(--accent-ink); }

.hero-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.8rem; }
.hero .btn-outline { color: var(--white); border-color: rgba(255,255,255,.7); background: transparent; }
.hero .btn-outline:hover, .hero .btn-outline:focus-visible { background: var(--white); color: var(--primary-deep); border-color: var(--white); }
/* trust row reads as checked facts, not as a list of badges */
.hero-checks { display: flex; flex-wrap: wrap; gap: .6rem 1.8rem; list-style: none; margin: 1.8rem 0 0; padding: 0;
  color: #EDEFF0; font-size: .95rem; font-weight: 500; }
.hero-checks li { display: inline-flex; align-items: center; gap: .5rem; }
.hero-checks .icon { color: var(--on-dark); }

@media (max-width: 900px) { .hero-inner { grid-template-columns: 1fr; } }

/* ── forms ────────────────────────────────────────────────────────────────── */
.form-card { background: var(--white); border: 1px solid var(--line); border-radius: 18px; padding: 1.6rem; box-shadow: var(--shadow-lg); color: var(--body); }
.hero .form-card { border: 1px solid rgba(35,39,42,.07); }
.form-card h2 { font-size: 1.3rem; margin-bottom: .4rem; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
.form-stack { display: grid; gap: .8rem; }
@media (max-width: 560px) { .form-row { grid-template-columns: 1fr; } }
.field { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .8rem; }
.field label { font-size: .88rem; font-weight: 600; color: var(--ink); }
.field input, .field select, .field textarea {
  font-family: inherit; font-size: 1rem; color: var(--ink);
  padding: .7rem .8rem; border: 1px solid #C9CED2; border-radius: 8px; background: var(--white);
}
.field textarea { resize: vertical; }
.field-check { flex-direction: row; align-items: center; gap: .5rem; }
.field-check label { font-weight: 500; }
.form-note { font-size: .87rem; color: var(--muted); margin: .4rem 0 0; font-weight: 400; }
.form-error { background: #FDECEC; border-left: 3px solid #B3261E; color: #8C1D18; padding: .7rem .9rem; border-radius: 6px; font-size: .92rem; }
.form-consent { display: flex; gap: .55rem; align-items: flex-start; font-size: .8rem; color: var(--muted); margin: .9rem 0 0; line-height: 1.5; }
.form-consent input { margin-top: .25rem; flex: none; }
/* Rule 8 honeypot — display:none, neutral name. Never rename to a
   profile-shaped field (website/url/company/address): Chrome autofills those
   regardless of autocomplete=off and a filled honeypot silently drops a REAL
   lead, with the visitor still seeing the thank-you page. */
.hp-field { display: none !important; }
.form-compact .form-note:first-of-type { display: none; }

/* ── cards, grids ─────────────────────────────────────────────────────────── */
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.4rem; }
/* Explicit counts, because auto-fit strands an orphan row whenever the item
   count does not divide by the column count — 8 cards in 3 columns leaves 2
   marooned, which reads as broken layout rather than as a grid. */
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.3rem; }
.grid-2-up { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.6rem; }
@media (max-width: 1080px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .grid-4, .grid-2-up { grid-template-columns: 1fr; } }
.card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.5rem; box-shadow: var(--shadow); }
.card h3 { margin-bottom: .4rem; }
.card p { color: var(--muted); font-size: .96rem; margin-bottom: .8rem; }
.card-link { font-weight: 700; text-decoration: none; }
.card-link:hover { text-decoration: underline; }
.card-media { border-radius: var(--radius) var(--radius) 0 0; margin: -1.5rem -1.5rem 1.1rem; overflow: hidden; }
.icon-badge { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; border-radius: 12px; background: var(--accent); color: var(--on-accent); margin-bottom: 1rem; }

/* Rule 14: the stat bar stays ONE row at every viewport — it shrinks rather
   than wrapping, because a wrapped stat bar reads as broken layout. */
.stats-bar { background: var(--primary-deep); color: var(--white); }
/* Rule 14: repeat(4,1fr) at EVERY breakpoint. Fonts shrink; the row never wraps.
   Cells separate with a hairline rather than by whitespace, which is what keeps
   four narrow columns legible on a phone. Every colour restated: this sits on
   --primary-deep, and the number, label and sub each choose their own. */
.stats-bar-inner { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; padding: clamp(1.6rem, 3.5vw, 2.6rem) 0; text-align: center; }
.stat { min-width: 0; padding: .2rem clamp(.35rem, 1.5vw, 1.2rem); border-left: 1px solid var(--header-line); }
.stat:first-child { border-left: 0; }
.stat-num { display: block; font-family: var(--font-head); font-weight: 800; letter-spacing: -.03em; line-height: 1; font-size: clamp(1.6rem, 4.6vw, 3rem); color: var(--white); }
.stat-label { display: block; margin-top: .45rem; font-family: var(--font-head); font-weight: 700; font-size: clamp(.72rem, 1.5vw, .98rem); line-height: 1.25; color: var(--white); }
.stat-sub { display: block; margin-top: .3rem; font-size: clamp(.72rem, 1.3vw, .88rem); line-height: 1.35; color: var(--muted-on-dark); }
@media (max-width: 480px) { .stat-sub { display: none; } }

/* ── two-column body + sticky sidebar ─────────────────────────────────────── */
.content-wrap { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: clamp(2rem, 4vw, 3.5rem); }
/* Rule 13: a sticky child in a CSS grid needs align-self:start, or the stretched
   grid item is already full-height and `position:sticky` can never engage. */
.sidebar-cta { align-self: start; position: sticky; top: 96px; }
@media (max-width: 980px) { .content-wrap { grid-template-columns: 1fr; } .sidebar-cta { position: static; } }

/* ── reviews ──────────────────────────────────────────────────────────────── */
.review-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 1.4rem; }
.rev-card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.4rem; margin: 0; box-shadow: var(--shadow); }
.rev-card blockquote { margin: .6rem 0 .9rem; }
.rev-card p { color: var(--body); font-size: .96rem; margin: 0; }
.rev-card figcaption { font-weight: 700; color: var(--ink); font-family: var(--font-head); font-size: .95rem; }
/* Stars are inline SVG (Rule 22) — never the character U+2605, which renders as
   a yellow color-emoji on iOS and ignores `color`. */
.stars { display: inline-flex; gap: 2px; color: var(--accent-ink); }
.stars .icon { fill: currentColor; }
.reviews-cta { margin-top: 1.8rem; }

/* ── FAQ ──────────────────────────────────────────────────────────────────── */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); padding: .3rem 0; }
.faq summary { cursor: pointer; font-family: var(--font-head); font-weight: 700; color: var(--ink); padding: 1rem 2rem 1rem 0; position: relative; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: ""; position: absolute; right: .4rem; top: 1.5rem; width: 9px; height: 9px; border-right: 2px solid var(--accent-ink); border-bottom: 2px solid var(--accent-ink); transform: rotate(45deg); transition: transform .18s; }
.faq details[open] summary::after { transform: rotate(-135deg); }
.faq details p { color: var(--muted); margin: 0 0 1rem; }

/* ── CTA band ─────────────────────────────────────────────────────────────── */
.cta-banner { background: var(--primary-deep); color: var(--white); }
.cta-banner-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.5rem; padding: clamp(2rem, 4vw, 3rem) 0; }
.cta-banner h2 { color: var(--white); margin-bottom: .3rem; }
.cta-banner p { color: var(--muted-on-dark); margin: 0; max-width: 52ch; }
.cta-banner-actions { display: flex; flex-wrap: wrap; gap: .8rem; }

/* ── footer ───────────────────────────────────────────────────────────────── */
.site-footer { background: var(--footer-bg); color: var(--muted-on-dark); font-size: .95rem; }
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: 2.5rem; padding: clamp(2.5rem, 5vw, 4rem) 0 2rem; }
@media (max-width: 900px) { .footer-grid { grid-template-columns: 1fr 1fr; gap: 2rem; } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-brand img { width: auto; height: 52px; margin-bottom: 1.1rem; }
.footer-brand p { max-width: 42ch; }
.footer-license { display: flex; align-items: center; gap: .45rem; color: var(--white); font-weight: 600; }
.footer-license .icon { color: var(--on-dark); }
.footer-h { font-size: 1rem; color: var(--white); margin-bottom: .9rem; }
.footer-links, .footer-contact, .footer-social, .footer-legal { list-style: none; margin: 0; padding: 0; }
.footer-links li, .footer-contact li { margin-bottom: .55rem; }
.footer-contact li { display: flex; gap: .6rem; align-items: flex-start; }
.footer-contact .icon { color: var(--on-dark); margin-top: .28rem; }
.footer-office { display: block; font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted-on-dark); }
/* :not(.btn) on BOTH rules — see the color contract, trap 2. */
.site-footer a:not(.btn) { color: var(--muted-on-dark); text-decoration: none; }
.site-footer a:not(.btn):hover, .site-footer a:not(.btn):focus-visible { color: var(--white); text-decoration: underline; }
.footer-social { display: flex; gap: .6rem; margin-top: 1.1rem; }
.footer-social a { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border: 1px solid var(--header-line); border-radius: 8px; color: var(--muted-on-dark); }
.footer-social a:hover { background: var(--white); color: var(--primary-deep); border-color: var(--white); }
.footer-bottom { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .8rem; padding: 1.3rem 0 1.6rem; border-top: 1px solid var(--header-line); font-size: .88rem; }
.footer-bottom p { margin: 0; }
.footer-legal { display: flex; flex-wrap: wrap; gap: 1.2rem; }

/* ── mobile sticky bar (Rules 10 + 24) ────────────────────────────────────── */
.sticky-bar { display: none; }
.sticky-clearance { display: none; }
@media (max-width: 780px) {
  /* EXACTLY two elements: quote + phone (Rule 10). */
  .sticky-bar {
    display: grid; grid-template-columns: 1fr 1fr;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 110;
    background: var(--primary-deep); border-top: 1px solid var(--header-line);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .sticky-bar a { display: inline-flex; align-items: center; justify-content: center; gap: .45rem; padding: .95rem .5rem; font-family: var(--font-head); font-weight: 700; font-size: 1rem; text-decoration: none; }
  .sticky-quote { background: var(--accent); color: var(--on-accent); }
  .sticky-call { color: var(--white); }
  .sticky-call:hover { background: rgba(255,255,255,.12); }
  /* Rule 24: clearance is its own element in the SAME color as the footer, plus
     the safe-area inset — padding on the footer alone leaves a white strip under
     the bar on a notched device. */
  .sticky-clearance { display: block; height: calc(58px + env(safe-area-inset-bottom)); background: var(--primary-deep); }
}

/* ── utilities ────────────────────────────────────────────────────────────── */
.visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.breadcrumb { font-size: .87rem; color: var(--muted); padding: 1rem 0 0; }
.breadcrumb ol { display: flex; flex-wrap: wrap; gap: .4rem; list-style: none; margin: 0; padding: 0; }
.breadcrumb li::after { content: "/"; margin-left: .4rem; color: var(--line); }
.breadcrumb li:last-child::after { content: ""; }
.prose > h2 { margin-top: 2.2rem; }
.prose > h3 { margin-top: 1.6rem; }
.prose ul { padding-left: 1.2rem; }
.prose li { margin-bottom: .45rem; }
/* Rule 2: .page-hero carries NO background-image here — layout only. Each page
   supplies its own contextual image plus a BRAND-TINTED (not plain black)
   gradient via the inline multi-background shorthand. No ::before image layer,
   no var() on a pseudo-element. --primary-deep #2F3234 is rgb(47,50,52). */
.page-hero { position: relative; overflow: hidden; color: var(--white); padding: clamp(2.5rem, 5vw, 4rem) 0 clamp(2.5rem, 5vw, 3.5rem); }
.page-hero h1 { color: var(--white); margin-top: .6rem; }
.page-hero p { max-width: 62ch; color: #E8EAEB; margin: 0; font-size: 1.06rem; }
.page-hero .breadcrumb { color: var(--muted-on-dark); padding-top: 0; }
.page-hero .breadcrumb a { color: var(--muted-on-dark); }
.page-hero .breadcrumb a:hover { color: var(--white); }
.page-hero .breadcrumb li::after { color: rgba(255,255,255,.35); }

/* ── homepage: service link row + service-area list ───────────────────────── */
.more-services { margin-top: 1.6rem; color: var(--muted); font-size: .97rem; }
.more-services a { font-weight: 600; }
.area-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: .6rem 1.2rem; list-style: none; margin: 0; padding: 0; }
.area-list a { display: inline-flex; align-items: center; gap: .45rem; padding: .55rem .2rem; text-decoration: none; font-weight: 600; }
.area-list a:hover { text-decoration: underline; }
.area-list .icon { color: var(--accent-ink); }

/* ── contact list ─────────────────────────────────────────────────────────── */
.contact-list { list-style: none; margin: 0; padding: 0; }
.contact-list li { display: flex; gap: .8rem; align-items: flex-start; padding: .9rem 0; border-bottom: 1px solid var(--line); }
.contact-list li:last-child { border-bottom: 0; }
.contact-list .icon { color: var(--accent-ink); margin-top: .3rem; }
.contact-list strong { display: block; font-family: var(--font-head); color: var(--ink); font-size: .95rem; }
.contact-phone { display: inline-block; font-family: var(--font-head); font-weight: 700; font-size: 1.2rem; text-decoration: none; margin: .15rem 0; }
.contact-phone:hover { text-decoration: underline; }
.contact-note { display: block; font-size: .89rem; color: var(--muted); }

/* ── thank-you / 404 ──────────────────────────────────────────────────────── */
.thanks { max-width: 62ch; }
.thanks-mark { display: inline-flex; align-items: center; justify-content: center; width: 76px; height: 76px; border-radius: 50%; background: var(--accent); color: var(--on-accent); margin-bottom: 1.3rem; }
.thanks-lead { font-size: 1.12rem; color: var(--body); }
.thanks-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin: 1.6rem 0 2.4rem; }
.thanks-next { border-top: 1px solid var(--line); padding-top: 1.8rem; }
.thanks-next ol, .thanks-next ul { padding-left: 1.2rem; }
.thanks-next li { margin-bottom: .6rem; }

/* ── sidebar three-card pattern (§6) ──────────────────────────────────────────
   Every sub-page carries the same three cards: a dark phone CTA, a form CTA to
   /contact/, and a related-page card that ROTATES BY PAGE TYPE to spread
   internal-link equity rather than pointing every page at the same target. */
.sidebar-card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.4rem; margin-bottom: 1.1rem; box-shadow: var(--shadow); }
.sidebar-card h3 { font-size: 1.08rem; margin-bottom: .5rem; }
.sidebar-card p { color: var(--muted); font-size: .94rem; margin-bottom: 1rem; }
.sidebar-card .btn { width: 100%; }
.sidebar-card.dark { background: var(--primary-deep); border-color: var(--primary-deep); color: var(--muted-on-dark); }
.sidebar-card.dark h3 { color: var(--white); }
.sidebar-card.dark p { color: var(--muted-on-dark); }
.phone-big { display: block; font-family: var(--font-head); font-weight: 800; font-size: 1.6rem; color: var(--on-dark); text-decoration: none; margin: .2rem 0 .6rem; }
.phone-big:hover { text-decoration: underline; }

/* ── service / why cards (capture.py clips on these selectors) ────────────── */
.svc-card, .why-card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.5rem; box-shadow: var(--shadow); }
.svc-card h3, .why-card h3 { margin-bottom: .4rem; }
.svc-card p, .why-card p { color: var(--muted); font-size: .96rem; margin-bottom: .8rem; }
.why-card p:last-child { margin-bottom: 0; }

/* ── feature list ─────────────────────────────────────────────────────────── */
.feature-list { list-style: none; margin: 1.2rem 0; padding: 0; }
.feature-list li { display: flex; gap: .6rem; align-items: flex-start; margin-bottom: .7rem; }
.feature-list .icon { color: var(--accent-ink); margin-top: .28rem; flex: none; }

/* ── FAQ (documented markup: .faq-item / .faq-q / .faq-a) ─────────────────── */
.faq-item { border-bottom: 1px solid var(--line); padding: .3rem 0; }
.faq-item:first-child { border-top: 1px solid var(--line); }
.faq-q { cursor: pointer; font-family: var(--font-head); font-weight: 700; color: var(--ink); padding: 1rem 2rem 1rem 0; position: relative; list-style: none; }
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after { content: ""; position: absolute; right: .4rem; top: 1.5rem; width: 9px; height: 9px; border-right: 2px solid var(--accent-ink); border-bottom: 2px solid var(--accent-ink); transform: rotate(45deg); transition: transform .18s; }
.faq-item[open] .faq-q::after { transform: rotate(-135deg); }
.faq-a { color: var(--muted); margin: 0 0 1rem; }

/* ── in-body photo (Rule 32) ──────────────────────────────────────────────── */
.photo-frame { border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); margin: 1.8rem 0; }
.photo-frame img { width: 100%; }
.photo-frame figcaption { background: var(--surface); color: var(--muted); font-size: .87rem; padding: .7rem 1rem; }
.photo-inline { border-radius: var(--radius); overflow: hidden; margin: 1.6rem 0; }

/* ── section heading helper ───────────────────────────────────────────────── */
.section-h { margin-bottom: .5rem; }
/* Section eyebrow. --accent-ink at 12px uppercase reads near-black rather than
   orange, so on light grounds the eyebrow becomes an orange CHIP (fill + dark
   label, 5.62:1) to match the hero's, instead of dark-orange text nobody reads
   as orange. On dark grounds it stays text in --on-dark, which is genuinely
   orange there. */
.eyebrow { display: inline-flex; align-items: center; gap: .4rem;
  background: var(--accent); color: var(--on-accent); border-radius: 999px;
  padding: .38rem .8rem; font-family: var(--font-head); font-weight: 700;
  font-size: .76rem; letter-spacing: .09em; text-transform: uppercase; margin-bottom: .9rem; }
.hero .eyebrow, .cta-banner .eyebrow, .work .eyebrow {
  background: transparent; color: var(--on-dark); padding: 0; font-size: .9rem; }
.review-featured { background: var(--white); border: 1px solid var(--line); border-left: 4px solid var(--accent); border-radius: var(--radius); padding: 1.6rem; margin-bottom: 1.4rem; box-shadow: var(--shadow); }
.review-by { font-weight: 700; color: var(--ink); font-family: var(--font-head); font-size: .95rem; margin: .6rem 0 0; }
.review-by span { font-weight: 500; color: var(--muted); }
.reviews-note { color: var(--muted); margin-bottom: 1.8rem; }

/* ── .content-wrap = .content-main + aside.sidebar-cta (§6) ───────────────── */
.content-main > h2:first-child { margin-top: 0; }
.content-main > h2 { margin-top: 2.2rem; }
.content-main > h3 { margin-top: 1.6rem; }
.content-main ul:not(.feature-list):not(.area-list) { padding-left: 1.2rem; }
.content-main li { margin-bottom: .45rem; }

/* ── footer column + reviews band ─────────────────────────────────────────── */
.footer-col { min-width: 0; }
.reviews { background: var(--surface); }

/* ── recent-work photo band (Rule 32) ─────────────────────────────────────────
   Nine authentic drone job photos exist and the page was using one. This puts
   the rest to work: it is the only thing on the page a competitor cannot copy,
   and it is the reason to trust the copy above it. */
.work { background: var(--primary-deep); color: var(--muted-on-dark); }
.work h2 { color: var(--white); }
.work .section-sub, .work .section-head p { color: var(--muted-on-dark); }
/* The work band is a DARK ground dropped into a page of light sections, so every
   color set for the light ground has to be restated here. .section-head p and
   .eyebrow both inherited --muted (2.14:1 on this ground) — the same light/dark
   trap as the header port, this time inside my own new section. */
.work .eyebrow .icon { color: var(--on-dark); }
.work-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.work-item { position: relative; margin: 0; border-radius: var(--radius); overflow: hidden; background: var(--primary); }
.work-item img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .4s ease; }
.work-item:hover img { transform: scale(1.04); }
@media (max-width: 900px) { .work-grid { grid-template-columns: repeat(2, 1fr); } }
@media (prefers-reduced-motion: reduce) { .work-item:hover img { transform: none; } }

/* ── section eyebrow label, used to lead a section rather than a bare H2 ───── */
.section-head { max-width: 64ch; margin-bottom: 2.4rem; }
.section-head .eyebrow { margin-bottom: .5rem; }
.section-head h2 { margin-bottom: .5rem; }
.section-head p { color: var(--muted); font-size: 1.06rem; margin: 0; }

/* ── svc-card: give the copper somewhere real to live ─────────────────────── */
.svc-card { position: relative; transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease; }
.svc-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--accent); border-radius: var(--radius) 0 0 var(--radius); opacity: 0; transition: opacity .18s ease; }
.svc-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); border-color: #D6D9DB; }
.svc-card:hover::before { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .svc-card, .svc-card:hover { transform: none; transition: none; } }

/* stat unit sits smaller and copper beside the numeral */

/* ── photo-led service cards (Rule 32) ────────────────────────────────────────
   The whole card is one <a>, so the inner "heading" and copy are spans styled
   to look like a heading rather than real h3/p — nesting block elements or a
   heading inside an anchor is invalid and axe flags the heading-order. */
.svc-card { display: flex; flex-direction: column; padding: 0; overflow: hidden; text-decoration: none; color: inherit; }
.svc-card .pic { display: block; overflow: hidden; background: var(--surface-2); }
.svc-card .pic img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; transition: transform .45s ease; }
.svc-card:hover .pic img { transform: scale(1.05); }
.svc-card .icon-badge { margin: 1.5rem 1.5rem 0; }
.svc-card .body { display: flex; flex-direction: column; gap: .45rem; padding: 1.25rem 1.5rem 1.5rem; }
.svc-card .h3 { font-family: var(--font-head); font-weight: 700; font-size: 1.15rem; color: var(--ink); line-height: 1.25; }
.svc-card .blurb { color: var(--muted); font-size: .95rem; line-height: 1.55; }
.svc-card .more { display: inline-flex; align-items: center; gap: .35rem; margin-top: .35rem;
  font-family: var(--font-head); font-weight: 700; font-size: .93rem; color: var(--accent-ink); }
.svc-card:hover .more { color: var(--accent-ink-dark); }
.svc-card:hover .more .icon { transform: translateX(3px); }
.svc-card .more .icon { transition: transform .18s ease; }
/* the copper edge only makes sense on the icon variant; a photo card already
   has its own top-edge weight */
.svc-card.has-pic::before { display: none; }
@media (prefers-reduced-motion: reduce) {
  .svc-card:hover .pic img, .svc-card:hover .more .icon { transform: none; }
}

/* Fallback panel for a service with no honest photo yet. Same 16/10 block as a
   real photo so a mixed grid keeps its rhythm, but visibly not a photograph. */
.svc-card .pic-placeholder { display: flex; align-items: center; justify-content: center;
  aspect-ratio: 16 / 10; background:
    linear-gradient(135deg, var(--primary) 0%, var(--primary-deep) 100%);
  color: var(--on-dark); }
.svc-card:hover .pic-placeholder { color: var(--accent); }

/* ── owner portraits (real photos, recovered from the legacy site) ─────────── */
.owner { float: left; margin: .4rem 1.4rem .8rem 0; text-align: center; }
.owner img { width: 132px; height: 132px; border-radius: 50%; object-fit: cover; border: 3px solid var(--accent); }
.owner figcaption { font-family: var(--font-head); font-weight: 700; font-size: .92rem; color: var(--ink); margin-top: .55rem; }
.owner figcaption span { display: block; font-weight: 500; font-size: .8rem; color: var(--muted); }
.content-main h3 { clear: none; }
@media (max-width: 560px) { .owner { float: none; margin: 0 auto 1rem; } }



/* ── process steps ────────────────────────────────────────────────────────────
   An ordered sequence, not a card grid. Own component because .svc-card now
   carries padding:0 for the photo layout — anything reusing it without a .body
   wrapper loses its inset entirely, which is exactly what happened here. */
.step-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.3rem; list-style: none; margin: 0; padding: 0; counter-reset: step; }
.step-card { position: relative; background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 2.4rem 1.5rem 1.6rem; box-shadow: var(--shadow); }
.step-num { position: absolute; top: -18px; left: 1.5rem;
  display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px;
  border-radius: 12px; background: var(--accent); color: var(--on-accent);
  font-family: var(--font-head); font-weight: 800; font-size: 1.15rem; box-shadow: var(--shadow); }
.step-card h3 { font-size: 1.08rem; margin: .35rem 0 .45rem; }
.step-card p { color: var(--muted); font-size: .95rem; line-height: 1.55; margin: 0; }
/* the connecting rule between steps, desktop only */
.step-card::after { content: ""; position: absolute; top: 4px; right: -1.3rem; width: 1.3rem; height: 1px; background: var(--line); }
.step-card:last-child::after { display: none; }
@media (max-width: 1080px) { .step-grid { grid-template-columns: repeat(2, 1fr); row-gap: 2.4rem; } .step-card::after { display: none; } }
@media (max-width: 620px)  { .step-grid { grid-template-columns: 1fr; row-gap: 2.4rem; } }

/* The eyebrow is a <p> inside .section-head, and `.section-head p` (0,1,1) is
   declared later than `.eyebrow` (0,1,0), so it silently won and painted the
   chip label --muted — gray on orange at 2.25:1. Restated at (0,2,0) so the
   eyebrow's own color holds regardless of the container it sits in. */
.section-head .eyebrow { color: var(--on-accent); }
.work .section-head .eyebrow,
.hero .section-head .eyebrow,
.cta-banner .section-head .eyebrow { color: var(--on-dark); }

/* ── location cards (/locations/) ───────────────────────────────────────────
   A TEXT card, not a photo card, and that is a content-integrity decision
   rather than a design one — see the comment above site_city_card().

   Every color is restated on the card's own children rather than inherited.
   This build has already had four incidents where a rule on a CONTAINER
   silently repainted a component that had chosen its own color, and these
   cards sit on BOTH grounds: .section (white) in one block and .section-alt
   (--surface) in the other. Inheriting would make them diverge the first time
   either ground changes. */
.loc-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.2rem; }
@media (max-width: 900px) { .loc-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .loc-grid { grid-template-columns: 1fr; } }

.loc-card {
  display: flex; flex-direction: column; position: relative;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.35rem; box-shadow: var(--shadow); text-decoration: none;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.loc-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--accent); border-radius: var(--radius) 0 0 var(--radius);
  opacity: 0; transition: opacity .18s ease; }
.loc-card:hover, .loc-card:focus-visible { transform: translateY(-2px); box-shadow: var(--shadow-lg); border-color: #D6D9DB; }
.loc-card:hover::before, .loc-card:focus-visible::before { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .loc-card, .loc-card:hover { transform: none; transition: none; } }

.loc-card .county { display: inline-flex; align-items: center; gap: .35rem;
  font-size: .73rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  color: var(--accent-ink); margin-bottom: .55rem; }
.loc-card .county .icon { color: var(--accent-ink); }
.loc-card .h3 { display: block; font-family: var(--font-head); font-weight: 700;
  font-size: 1.14rem; line-height: 1.25; color: var(--ink); margin-bottom: .45rem; }
.loc-card .blurb { display: block; color: var(--muted); font-size: .94rem; line-height: 1.55;
  margin-bottom: 1rem; }
.loc-card .more { display: inline-flex; align-items: center; gap: .35rem; margin-top: auto;
  font-weight: 700; font-size: .92rem; color: var(--accent-ink); }
.loc-card .more .icon { color: var(--accent-ink); }
.loc-card:hover .more { text-decoration: underline; }

/* ── city-page service block (includes/city_render.php) ─────────────────────
   Three or four services chosen FOR that city, each with copy written for that
   market. It replaces the legacy eleven-service grid, which was identical on
   all eleven city pages and hardcoded to Sarasota.
   Every color restated rather than inherited — this block sits inside
   .content-main on a white ground, and .content-main sets its own p color. */
.city-svc { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.1rem; margin: 1.4rem 0 .4rem; }
@media (max-width: 640px) { .city-svc { grid-template-columns: 1fr; } }
.city-svc-item { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.15rem 1.25rem; }
.city-svc-item h3 { margin: 0 0 .4rem; font-size: 1.06rem; color: var(--ink); }
.city-svc-item h3 a { color: var(--accent-ink); text-decoration: none; }
.city-svc-item h3 a:hover, .city-svc-item h3 a:focus-visible { text-decoration: underline; }
.city-svc-item p { margin: 0; color: var(--muted); font-size: .95rem; line-height: 1.6; }

/* A phone number is one token. Inside running prose the inline tel link was
   wrapping mid-number at 390px on /locations/ and /privacy-policy/. */
.content-main a[href^="tel:"], .prose a[href^="tel:"], .contact-list a[href^="tel:"],
.sidebar-card a[href^="tel:"], .cta-banner a[href^="tel:"] { white-space: nowrap; }

/* ── Viva integration fixes (2026-10-03) ──────────────────────────────────────
   Phone links inside an orange .eyebrow badge (service-areas hub group headings)
   inherited --accent-ink purple: 2.73:1 on --accent. They take the dark label,
   --on-accent on --accent = 8.13:1, and never wrap mid-number (QA §5). */
.eyebrow a { color: var(--on-accent); white-space: nowrap; }
.eyebrow a:hover, .eyebrow a:focus-visible { color: var(--on-accent); text-decoration-thickness: 2px; }
/* Homepage areas-band county map (tools/website_starter/county_map.py emits class nc-map). */
.nc-map { display: block; width: 100%; height: auto; }

/* ── Ported 2026-10-03 from arolite-group as the house template (Max) ───────── */
/* ── "Areas We Serve" band (Pisgah-style county list + highlighted map) ─────
   Dark ground; every colour restated for it (the light/dark trap). County cards
   on --primary, pins and the served counties in brand orange, the rest of the state in a
   quiet outline so the three counties read at a glance. */
.areas-band { background: var(--primary-deep); color: var(--muted-on-dark); }
.areas-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
@media (max-width: 980px) { .areas-grid { grid-template-columns: 1fr; } }
.areas-band .eyebrow { background: transparent; color: var(--on-dark); padding: 0; font-size: .9rem; margin-bottom: .4rem; }
.areas-band h2 { color: var(--white); margin-bottom: .6rem; }
.areas-band > .wrap > div > p, .areas-lead { color: var(--muted-on-dark); max-width: 52ch; }
.county-card { background: var(--primary); border: 1px solid var(--header-line); border-radius: var(--radius); padding: 1rem 1.2rem; margin-bottom: .8rem; }
.county-card h3 { color: var(--white); font-size: 1rem; margin: 0 0 .5rem; display: flex; align-items: center; gap: .45rem; }
.county-card h3 .icon { color: var(--on-dark); }
.county-card h3 a { color: var(--white); text-decoration: none; }
.county-card h3 a:hover, .county-card h3 a:focus-visible { color: var(--on-dark); text-decoration: underline; }
.pin-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: .3rem 1rem; list-style: none; margin: 0; padding: 0; font-size: .95rem; }
@media (max-width: 480px) { .pin-list { grid-template-columns: 1fr; } }
.pin-list li { display: flex; align-items: center; gap: .4rem; color: var(--muted-on-dark); }
.pin-list .icon { color: var(--on-dark); flex: none; }
.pin-list a { color: var(--white); text-decoration: none; font-weight: 600; padding: .25rem 0; display: inline-block; }
.pin-list a:hover, .pin-list a:focus-visible { text-decoration: underline; color: var(--on-dark); }
.areas-actions { margin-top: 1.2rem; display: flex; flex-wrap: wrap; gap: .8rem; }
.areas-map { display: block; }
.nc-map .c { fill: #2B1A4A; stroke: #4A3873; stroke-width: .9; vector-effect: non-scaling-stroke; }
.nc-map .c.served { fill: var(--accent); stroke: var(--white); stroke-width: 1.4; }
.map-note { font-size: .85rem; color: var(--muted-on-dark); margin: .8rem 0 0; text-align: center; }

/* ── hero badge strip (Pisgah-style rotating seals, asked for 2026-10-01) ──────
   A white card that overlaps the hero's bottom edge and scrolls a row of badges
   continuously (CSS marquee, duplicated list, pauses on hover, static under
   reduced motion). Pisgah fills theirs with manufacturer and BBB logos; this one
   carries only CHECKABLE facts until the client proves a certification (Rule 27),
   and each badge is drawn as an inline SVG seal so nothing is a fake logo. */
/* The wrap straddles the seam: its top 2.6rem is transparent (the hero photo shows
   through), the rest is the stats bar's dark ground, so the white card reads as a
   card and the stats bar continues beneath it with no white gap. */
.hero-badges-wrap { position: relative; z-index: 2; margin-top: -2.6rem; width: 100%; max-width: none; padding: 0 1.25rem 1.6rem;
  background: linear-gradient(to bottom, transparent 2.6rem, var(--primary-deep) 2.6rem); }
.badge-set { display: contents; }
/* the strip overlaps the dark stats bar below it, so the bar opens with room for it */
.hero-badges { background: var(--white); border-radius: 18px; box-shadow: var(--shadow-lg); overflow: hidden;
  padding: .55rem 0; max-width: 980px; margin: 0 auto;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent); }
.badge-track { display: flex; gap: 2.2rem; width: max-content; padding: 0 1.1rem;
  animation: badge-scroll 34s linear infinite; }
.hero-badges:hover .badge-track, .hero-badges:focus-within .badge-track { animation-play-state: paused; }
@keyframes badge-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.badge { display: inline-flex; align-items: center; gap: .7rem; padding: .55rem .4rem; white-space: nowrap; color: var(--ink); text-decoration: none; }
.badge-seal { flex: none; width: 52px; height: 52px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  background: var(--primary); color: var(--on-dark); border: 3px solid var(--accent); }
.badge-seal.gold { background: var(--accent); color: var(--on-accent); border-color: var(--accent-hover); }
.badge-big { display: block; font-family: var(--font-head); font-weight: 800; font-size: 1.05rem; line-height: 1.1; color: var(--ink); }
.badge-small { display: block; font-size: .8rem; color: var(--muted); line-height: 1.2; margin-top: .15rem; }
a.badge:hover .badge-big, a.badge:focus-visible .badge-big { color: var(--accent-ink); text-decoration: underline; }
@media (prefers-reduced-motion: reduce) {
  .badge-track { animation: none; width: auto; flex-wrap: wrap; justify-content: center; gap: 1rem 1.6rem; padding: .3rem .8rem; }
  .badge-track [aria-hidden="true"] { display: none; }
  .hero-badges { -webkit-mask-image: none; mask-image: none; }
}
@media (max-width: 780px) { .hero-badges-wrap { margin-top: -1.6rem; background: linear-gradient(to bottom, transparent 1.6rem, var(--primary-deep) 1.6rem); } .badge-track { animation-duration: 26s; } }

/* Towns THREE across (two under 560px): two columns left each card half-empty (Max, UTD 2026-10-03). */
.pin-list { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 560px) { .pin-list { grid-template-columns: repeat(2, 1fr); } }

/* Max 2026-10-03: no edge fade on the badge strip, and no stats bar under it, so the strip
   sits on the white section below instead of a dark band. */
.hero-badges { -webkit-mask-image: none; mask-image: none; }
.hero-badges-wrap { background: linear-gradient(to bottom, transparent 2.6rem, var(--white) 2.6rem); }
@media (max-width: 780px) { .hero-badges-wrap { background: linear-gradient(to bottom, transparent 1.6rem, var(--white) 1.6rem); } }

/* ── Ported from arolite-group 2026-10-03: homepage carousel, timeline, reviews over photo, financing band ── */
/* ── photo band variants (Arolite) ───────────────────────────────────────────
   Jeff's one explicit ask from the demo: a big background photograph with the
   reviews sitting over it. The section keeps the white review cards; only the
   ground changes. The veil is measured for white heading text over the
   brightest photo in the library (sky in the underlayment shot): 0.74 floor. */
.reviews.reviews-photo { background-color: var(--primary-deep); background-size: cover; background-position: center; color: var(--muted-on-dark); }
.reviews-photo h2 { color: var(--white); }
.reviews-photo .section-sub { color: var(--muted-on-dark); }
.reviews-photo .btn-outline { color: var(--white); border-color: rgba(255,255,255,.7); }
.reviews-photo .btn-outline:hover, .reviews-photo .btn-outline:focus-visible { background: var(--white); color: var(--primary-deep); border-color: var(--white); }

/* Financing / offer band: gold-tinted light ground with an ink heading. */
.band-tint { background: var(--accent-tint); }
.band-tint h2 { color: var(--ink); }

/* ── homepage service carousel (Pisgah-style photo tiles, asked for 2026-10-01) ──
   Native scroll-snap, three tiles per view on desktop, two on tablet, a peek of
   the next one on phones. Arrows scroll by one tile; a gentle auto-advance runs
   until the visitor touches it, and never under reduced motion. Tiles with no
   honest photo keep the branded icon panel (Rule 27/32), same shape as a photo.
   Title sits on a scrim that reaches rgba(20,11,38,.88) at the baseline, so
   white on it is >= 12:1 over the brightest photo in the library. */
.svc-head { text-align: center; max-width: 64ch; margin: 0 auto 2rem; }
.svc-head p { color: var(--muted); font-size: 1.06rem; margin: 0; }
/* .svc-head p (0,1,1) outranks .eyebrow (0,1,0): restate the chip label colour or it
   paints gray on gold (axe caught it on staging 2026-10-01, 2 nodes). */
.svc-head .eyebrow { color: var(--on-accent); font-size: .76rem; margin-bottom: .9rem; }
.car { position: relative; }
.car-track { display: flex; gap: 1.1rem; list-style: none; margin: 0; padding: .25rem .25rem 1rem;
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.car-track::-webkit-scrollbar { display: none; }
.car-item { flex: 0 0 calc((100% - 2.2rem) / 3); scroll-snap-align: start; }
@media (max-width: 980px) { .car-item { flex-basis: calc((100% - 1.1rem) / 2); } }
@media (max-width: 600px) { .car-item { flex-basis: 84%; } }
.tile { position: relative; display: block; aspect-ratio: 4 / 3; border-radius: var(--radius); overflow: hidden;
  background: var(--primary-deep); text-decoration: none; color: var(--white); box-shadow: var(--shadow); }
.tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .5s ease; }
.tile:hover img, .tile:focus-visible img { transform: scale(1.05); }
.tile-panel { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--primary) 0%, var(--primary-deep) 100%); color: var(--on-dark); }
.tile-cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 3.2rem 1.3rem 1.2rem;
  background: linear-gradient(to top, rgba(20,11,38,.92) 0%, rgba(20,11,38,.72) 45%, rgba(20,11,38,0) 100%); }
.tile-title { display: block; font-family: var(--font-head); font-weight: 800; font-size: 1.35rem; line-height: 1.15; color: var(--white); letter-spacing: -.01em; }
.tile-more { display: inline-flex; align-items: center; gap: .35rem; margin-top: .45rem; font-family: var(--font-head);
  font-weight: 700; font-size: .9rem; color: var(--on-dark); opacity: 0; transform: translateY(4px); transition: opacity .2s, transform .2s; }
.tile:hover .tile-more, .tile:focus-visible .tile-more { opacity: 1; transform: none; }
@media (hover: none) { .tile-more { opacity: 1; transform: none; } }
.tile:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.car-btn { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; width: 46px; height: 46px; border-radius: 50%;
  border: 0; background: var(--accent); color: var(--on-accent); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-lg); }
.car-btn:hover, .car-btn:focus-visible { background: var(--accent-hover); color: var(--on-accent); }
.car-btn.prev { left: -23px; } .car-btn.next { right: -23px; }
@media (max-width: 1240px) { .car-btn.prev { left: 6px; } .car-btn.next { right: 6px; } }
.car-dots { display: flex; justify-content: center; gap: .45rem; margin: .4rem 0 1.6rem; }
.car-dots span { width: 8px; height: 8px; border-radius: 50%; background: var(--line); }
.car-dots span.on { background: var(--accent-ink); }
.svc-cta { text-align: center; }
@media (prefers-reduced-motion: reduce) { .car-track { scroll-behavior: auto; } .tile img, .tile:hover img { transform: none; transition: none; } }

/* ── process timeline (shape of the client's previous site, asked for 2026-10-01) ─
   Five steps in a row: an outlined gold circle holding the icon, a big faint
   number beside it, a thin rule linking the circles, title and one line under.
   On phones the steps stack and the rule goes away. Colours: the faint number is
   decorative (aria-hidden) and deliberately low-contrast, like the original; the
   title and copy carry the content at full contrast. */
.timeline { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1.4rem; list-style: none; margin: 2.6rem 0 0; padding: 0; counter-reset: tl; }
.tl-step { position: relative; text-align: center; padding: 0 .4rem; }
.tl-mark { position: relative; display: flex; align-items: center; justify-content: center; gap: .6rem; height: 64px; margin-bottom: 1.1rem; }
.tl-icon { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; width: 60px; height: 60px; border-radius: 50%;
  background: var(--white); border: 2px solid var(--accent); color: var(--accent-ink); }
/* The faint number is pure decoration, so it is drawn by CSS from a data attribute
   rather than placed in the DOM as text: screen readers never meet it and the
   contrast rules (which it fails on purpose, like the original) do not apply. */
.tl-num::before { content: attr(data-num); font-family: var(--font-head); font-weight: 800; font-size: 2.4rem; line-height: 1; color: var(--accent); opacity: .55; letter-spacing: -.02em; }
/* the connecting rule: drawn on each step from its circle to the next step's circle */
.tl-step::before { content: ""; position: absolute; top: 31px; left: 50%; width: 100%; height: 2px; background: var(--line); }
.tl-step:last-child::before { display: none; }
.tl-step h3 { font-size: 1.06rem; margin: 0 0 .45rem; color: var(--ink); }
.tl-step p { color: var(--muted); font-size: .95rem; line-height: 1.55; margin: 0; }
@media (max-width: 1080px) { .timeline { grid-template-columns: repeat(3, 1fr); row-gap: 2.4rem; } .tl-step:nth-child(3n)::before { display: none; } }
@media (max-width: 680px) {
  .timeline { grid-template-columns: 1fr; row-gap: 2.2rem; }
  .tl-step::before { display: none; }
}

/* ── financing block (shape of the reference site's three-step cards, 2026-10-01) ─
   Three light cards on the gold-tint band, each with a square icon badge hanging
   off its top-left corner, a title and one line; one button beneath. The badge
   sits half outside the card, so the list gets top room for it. */
.fin-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; list-style: none; margin: 2.8rem 0 0; padding: 1.6rem 0 0; }
.fin-card { position: relative; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 3.2rem 1.6rem 1.6rem; box-shadow: var(--shadow); }
.fin-badge { position: absolute; top: -1.6rem; left: 1.6rem; width: 64px; height: 64px; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center;
  background: var(--primary); color: var(--on-dark); border: 2px solid var(--accent); box-shadow: var(--shadow); }
.fin-card h3 { font-size: 1.12rem; margin: 0 0 .5rem; color: var(--ink); }
.fin-card p { color: var(--muted); font-size: .97rem; line-height: 1.55; margin: 0; }
.fin-section .svc-cta { margin-top: 2rem; }
.fin-note { text-align: center; color: var(--muted); font-size: .85rem; margin: 1rem auto 0; max-width: 60ch; }
@media (max-width: 980px) { .fin-steps { grid-template-columns: 1fr; gap: 2.6rem; } }
.reviews-photo .rev-card figcaption { color: var(--ink); }

/* Max 2026-10-03: the pale-purple financing band read pink; neutral grey ground instead. */
.band-tint { background: var(--surface-2); }
