/* ==========================================================================
   Florida Gulf Roofing — site stylesheet
   Header style: DARK — the brand slate #4E5255, matching the legacy Hugo site.
   Fonts: Plus Jakarta Sans (headings) + Inter (body), carried over from the
   legacy site so the rebuild still reads as the same company.

   ── COLOR CONTRACT — READ BEFORE CHANGING ANY ORANGE ────────────────────────
   The brand orange #F08100 is USABLE, but only as a FILL WITH A DARK LABEL.
   The instinct is white-on-orange; that is the one combination that fails.
   Measured:

       ink #23272A on #F08100 .......... 5.62:1   PASS  <- the primary button
       white on #F08100 ................ 2.68:1   FAIL  <- never do this
       #F08100 as text on white ........ 2.68:1   FAIL
       #F08100 as text on slate ........ 2.95:1   FAIL
       #F08100 as text on #2F3234 ...... 4.82:1   pass (deep ground only)

   So: orange is a GROUND, not an ink, everywhere except the deep slate. Do not
   darken it to make white text work — that is how it turns brown.

     --accent        #F08100  the real brand orange. Button and badge FILLS,
                              borders, dividers. Always with --on-accent on top.
     --on-accent     #ffffff  WHITE. See the accepted exception below.
     --accent-hover  #FF9420  hover.

   ── ACCEPTED ACCESSIBILITY EXCEPTION — DO NOT "FIX" THIS ─────────────────────
   White on #F08100 measures 2.68:1 and FAILS WCAG AA (needs 4.5:1). This is a
   deliberate, operator-approved decision taken on 2026-09-01 after seeing the
   alternatives rendered side by side, NOT an oversight.

   The alternatives and why they were rejected:
     dark  #23272A on #F08100 ... 5.62:1 passes, but the label is not white
     white on #C06700 .......... 4.05:1 still fails, and already duller
     white on #B15F00 .......... 4.66:1 passes, but visibly muddy
     white on #A85A00 .......... 5.09:1 passes, and reads brown

   White text simply cannot sit on a true brand orange and pass. The operator
   chose brand fidelity over the AA floor for the CTA.

   CONSEQUENCE, so nobody is surprised: axe reports a `serious` color-contrast
   violation on every orange-filled element, and the site therefore CANNOT pass
   Rule 30's zero-violations gate. That is expected. When reviewing a QA run,
   confirm the ONLY violations are this one rule on these elements — any other
   axe finding is still a real defect and must be fixed.

   Reverting is one line: set --on-accent back to #23272A.
     --accent-ink    #A85A00  orange TEXT on white — links, meaningful icons,
                              anything the bright orange cannot carry. 5.09:1.
     --on-dark       #F29326  orange text on the DEEP ground #2F3234. 5.52:1,
                              and still reads properly orange. On the lighter
                              slate #4E5255 it fails, which is why every surface
                              carrying orange text uses --primary-deep.
     --muted-on-dark #C2C6C8  secondary text on dark grounds. 7.50:1 on deep.
   ========================================================================== */

:root {
  --primary: #4E5255;         /* brand slate — header, footer, dark grounds */
  --primary-dark: #3E4144;    /* hero overlay ground; white on it is 10.27:1 */
  --primary-deep: #2F3234;
  --footer-bg: #1F2224;       /* one step below --primary-deep, so the footer
                                 reads as a separate band from the CTA banner
                                 that sits on --primary-deep directly above it.
                                 Every footer text token is measured on it:
                                 --muted-on-dark 9.30:1, --white 16.0:1,
                                 --on-dark 6.84:1 — all higher than on deep. */

  --accent: #F08100;          /* brand orange — FILLS, with --on-accent on top */
  --on-accent: #ffffff;       /* WHITE label on orange — see the ACCEPTED
                                 EXCEPTION note in the contract above (2.68:1) */
  --accent-hover: #C76B00;    /* hover goes DARKER. White on it is 3.80:1 — still
                                 under AA, but strictly better than the approved
                                 resting 2.68:1. The previous #FF9420 was 2.21:1
                                 under white, i.e. hovering made the label HARDER
                                 to read, while the comment beside it claimed
                                 6.40:1 (that figure is --ink on it, not white).
                                 This is the plan's own copper-dark token. */
  --accent-ink: #A85A00;      /* orange TEXT on white — links, icons (5.09:1) */
  --accent-ink-dark: #8E4C00;
  --accent-tint: #FDF2E5;     /* pale orange ground */
  --on-dark: #F29326;         /* orange text on --primary-deep (5.52:1) */
  --muted-on-dark: #C2C6C8;   /* secondary text ON slate grounds */
  --warm: #D1D3C0;            /* brand warm-white */

  --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: #4E5255;
  --header-text: #ffffff;
  --header-line: #5E6367;
  /* 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: #2F3234;

  --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); }
/* Specificity note: .site-footer a:not(.btn):hover (0,3,1) beat the old .footer-social a:hover (0,2,1),
   forcing the icon white on a white tile — invisible on hover. Anchored under .site-footer so it wins. */
.site-footer .footer-social a:hover, .site-footer .footer-social a:focus-visible { background: var(--white); color: var(--primary-deep); border-color: var(--white); text-decoration: none; }
.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 fgr_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; }
