/*
  SkilledMob shared design system.
  Extracted from the approved index.html homepage. Do not add new colors or fonts —
  every generated page (hub, service, guide, state, city, combo) includes this one file.
*/
:root{
  /* Brand */
  --purple:#2B124C;
  /* Header-only, deliberately darker than --purple (2026-08-13) — fixes the
     header/inner-hero blend on service+state, combo, and future state/city
     hub pages. Scoped to .site-header's background only; every other purple
     surface (hero sections, footer, buttons) stays on --purple. */
  --purple-header:#22103F;
  --purple-light:#3D1E68;
  --orange:#FF6A21;
  --orange-hover:#E85A15;
  --teal:#17B890;
  --white:#FFFFFF;
  /* Neutrals */
  --bg-section:#F7F7F9;
  --border:#E5E7EB;
  --gray-secondary:#6B7280;
  --gray-disabled:#9CA3AF;
  --danger:#D93B3B;
  --text-dark:#25252B;
  --radius:12px;
  --max-w:1280px;
}
*{margin:0;padding:0;box-sizing:border-box;}
/* Site-wide horizontal-overflow safety net (2026-08-22 mobile audit fix)
   — html AND body both get overflow-x:hidden (some browsers only honor it
   reliably on one or the other) plus max-width:100% on body, so a single
   oversized element anywhere on the page (the header CTA button was this
   time; a future one could be anything) can never again inflate the whole
   document wider than the viewport and drag every other section's
   width:100% along with it. This does not fix any specific element's
   sizing — see the header CTA fix below and fragments/header.js for the
   actual cause this time — it's a defensive backstop only. */
html{scroll-behavior:smooth;overflow-x:hidden;}
body{
  font-family:'Inter',sans-serif;
  color:var(--text-dark);
  background:var(--white);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
  max-width:100%;
}
h1,h2,h3,.font-display{font-family:'Sora',sans-serif;}
a{text-decoration:none;color:inherit;}
img{max-width:100%;display:block;}
ul{list-style:none;}
button{font-family:inherit;cursor:pointer;}
.wrap{max-width:var(--max-w);margin:0 auto;padding:0 24px;}
:focus-visible{outline:3px solid var(--teal);outline-offset:2px;}

/* ===== BACK TO TOP (2026-08-14) =====
   Global, fixed, hidden until JS adds .is-visible (see fragments/
   backToTop.js — scroll past 300px). Square with a shared card-radius
   corner (var(--radius), same language as the site's cards), not circular
   and not sharp. 48x48 floor matches the .btn min-height accessibility
   target elsewhere. Orange hover is a DELIBERATE, CONFIRMED exception to
   orange-is-call-actions-only (same category as the state-chip tint
   exception) — do not flag or revert. bottom:100px (2026-08-14, was 200px)
   keeps clear of the .lower-cta-wrap CTA strip that ends most pages;
   z-index:90 stays below the sticky header's 100 (defensive — they never
   actually overlap spatially, since one pins to the top and this pins near
   the bottom). */
.back-to-top{
  position:fixed;right:24px;bottom:100px;z-index:90;
  width:48px;height:48px;border-radius:var(--radius);
  background:var(--teal);border:none;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.18);
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity .2s,transform .2s,background .15s;
}
.back-to-top.is-visible{opacity:1;visibility:visible;transform:translateY(0);}
.back-to-top:hover{background:var(--orange);}
.back-to-top svg{width:22px;height:22px;}

/* ===== BUTTONS ===== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:14px 26px;border-radius:var(--radius);font-weight:700;font-size:15px;
  border:none;min-height:48px;transition:background .15s,transform .1s;
}
.btn svg{width:18px;height:18px;flex-shrink:0;}
.btn-call{background:var(--orange);color:#fff;}
.btn-call:hover{background:var(--orange-hover);}
.btn-call:active{transform:scale(.98);}
.btn-outline-purple{background:#fff;color:var(--purple);border:1.5px solid var(--purple);}
.btn-outline-purple:hover{background:var(--purple);color:#fff;}
/* Bottom CTA's call button (2026-08-14) — same default look as
   .btn-outline-purple, but scoped so ONLY this button hovers to orange
   instead of purple (every other .btn-outline-purple on the site keeps its
   purple hover). Icon uses stroke="currentColor" (see renderCallCta's
   'outline' variant), so it follows `color` automatically — no separate
   icon rule needed. */
.btn-outline-purple.lower-cta-call-btn:hover{background:var(--orange);border-color:var(--orange);color:#fff;}
.btn-purple{background:var(--purple);color:#fff;border:1.5px solid var(--purple);transition:background .15s,border-color .15s,transform .1s;}
.btn-purple:hover{background:var(--orange);border-color:var(--orange);}
.btn-purple:active{transform:scale(.98);}
/* Forest Green accent (2026-08-13) — opt-in via .accent-forest
   (hub.accentColor:"forest"), for the combo page's "Local note" fact-box
   button (templates/comboPage.js) — an embedded/decorative call element,
   so it takes the vertical accent same as everywhere else Forest Green
   shows up on this vertical. Hover still resolves to orange, same as the
   base .btn-purple:hover above (restated explicitly here rather than
   relying on source order, since both rules share the same 0,0,2,0
   specificity) — every actionable button on the site hovers to orange
   regardless of its resting color, that affordance stays intact. Dumpster
   Rental has no accentColor, so its fact-box button is unaffected.*/
.btn-purple.accent-forest{background:#927c00;border-color:#927c00;}
.btn-purple.accent-forest:hover{background:var(--orange);border-color:var(--orange);}
.btn-disabled{
  background:var(--bg-section);color:var(--gray-disabled);width:100%;
  display:inline-flex;align-items:center;justify-content:center;padding:14px 26px;
  border-radius:var(--radius);font-weight:700;font-size:14px;border:1px solid var(--border);
  cursor:default;
}

/* ===== HEADER ===== */
/* Hairline divider (2026-08-13) — subtle light border, not orange (orange
   stays reserved for call actions only). Solid 1px, matching the site's
   existing thin-solid-border language. Part of the shared header component,
   so it renders consistently on every page — purple .inner-hero pages
   (fixes the header/hero blend) and white .category-hero pages alike. */
.site-header{background:var(--purple-header);border-bottom:1px solid rgba(255,255,255,.12);position:sticky;top:0;z-index:100;height:78px;}
.header-inner{
  max-width:var(--max-w);margin:0 auto;padding:0 24px;height:78px;
  display:flex;align-items:center;justify-content:space-between;gap:24px;
}
.logo{display:flex;align-items:center;font-family:'Sora',sans-serif;font-weight:700;font-size:22px;color:#fff;gap:1px;flex-shrink:0;}
.logo .pin{width:16px;height:16px;margin:0 1px;}
.main-nav{display:flex;align-items:center;gap:30px;min-width:0;}
.main-nav a{color:#EDE7F5;font-size:14.5px;font-weight:500;display:flex;align-items:center;gap:5px;transition:color .15s;}
.main-nav a:hover{color:#fff;}
/* min-width:0 (2026-08-22 mobile audit fix) — flex items default to
   min-width:auto, which refuses to shrink below its content's natural
   width. .header-actions never had this, so its child .btn-call (the
   header call button) could never shrink to fit, and since nothing
   shrank, it — and the hamburger after it — overflowed .header-inner
   instead of wrapping. This is the structural half of the fix; the
   below-500px icon-only swap further down is the other half, since a
   flex item that CAN shrink to 0 still isn't the same as one that's
   actually sized sensibly for a phone-width header. */
.header-actions{display:flex;align-items:center;gap:16px;min-width:0;}
.hamburger{display:none;background:none;border:none;padding:8px;flex-shrink:0;}
.hamburger svg{width:24px;height:24px;stroke:#fff;}

/* ===== NAV DROPDOWN (2026-08-15) =====
   Targeted nav update — 3 of the 4 top-level items are dropdowns (Home
   stays a plain link, no chevron). Trigger is a real <button> (not an <a
   href="#">), so it's keyboard-focusable/activatable by default with no
   extra ARIA plumbing beyond aria-expanded/aria-haspopup. Opens on hover
   (desktop, via :hover/:focus-within) AND on click (.is-open, toggled by
   fragments/callScript.js's renderNavDropdownScript — also the only way it
   opens on mobile, see the 860px breakpoint below). The ::after pseudo-
   element bridges the visual gap between trigger and menu so hover doesn't
   drop when the cursor crosses it. */
.nav-dropdown{position:relative;}
.nav-dropdown::after{content:'';position:absolute;top:100%;left:0;right:0;height:14px;}
.nav-dropdown-trigger{
  background:none;border:none;padding:0;cursor:pointer;font-family:inherit;
  color:#EDE7F5;font-size:14.5px;font-weight:500;display:flex;align-items:center;gap:5px;
  transition:color .15s;
}
.nav-dropdown-trigger:hover{color:#fff;}
.nav-dropdown-trigger svg{transition:transform .15s;}
.nav-dropdown-trigger[aria-expanded="true"] svg{transform:rotate(180deg);}
/* Mega-menu (2026-08-15) — 2x2 icon-tile grid instead of a plain stacked
   list (each of the 3 dropdowns already has exactly 4 items, so a fixed
   2-col grid always fills evenly). display is "grid" when open, not
   "block" — see the open-state rule below. */
.nav-dropdown-menu{
  display:none;position:absolute;top:calc(100% + 14px);left:50%;transform:translateX(-50%);width:360px;
  grid-template-columns:repeat(2,1fr);gap:8px;
  background:#fff;border:1px solid var(--border);border-radius:var(--radius);
  box-shadow:0 12px 28px rgba(0,0,0,.16);padding:10px;z-index:110;
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu,
.nav-dropdown-menu.is-open{display:grid;}
/* Live and coming-soon items look identical (same Deep Purple text/icon,
   same card treatment) — non-interactivity alone communicates status, no
   dimming, no badge, per explicit direction. Only the hover feedback
   differs: a real link gets the light-gray hover, an inert item gets none,
   since hovering something that does nothing shouldn't look interactive.
   Card language (border + radius) matches the site's existing tile/card
   components (.tile-link, .service-type-card), not a one-off style. */
.nav-dropdown-item{
  display:flex;align-items:center;gap:9px;
  border:1px solid var(--border);border-radius:var(--radius);
  padding:11px 10px;font-size:13px;font-weight:700;color:var(--purple);
  transition:background .15s,border-color .15s;
}
.nav-dropdown-item svg{width:19px;height:19px;stroke:var(--purple);flex-shrink:0;}
/* Fix (2026-08-15): the real <a> tile (Dumpster Rental) was nearly
   invisible — .main-nav a{color:#EDE7F5} (pale lavender, meant for links
   directly on the dark header) has higher specificity (element+class) than
   the plain .nav-dropdown-item class rule above, so it was winning for the
   one item that's an <a> instead of a <span>. This matches it in
   specificity (element+class) so Deep Purple wins instead. */
a.nav-dropdown-item{color:var(--purple);}
/* Hover redesign (2026-08-15) — orange bg, white text/icon, per explicit
   direction. Deliberate, confirmed exception to orange-is-call-actions-only
   (same category as the state-chip tint and back-to-top hover) — do not
   flag or revert. Scoped to real links only (a.nav-dropdown-item); inert
   items still get zero hover change, per the standing "don't make
   non-interactive things look interactive" rule for this menu. */
a.nav-dropdown-item:hover{background:var(--orange);border-color:var(--orange);color:#fff;}
a.nav-dropdown-item:hover svg{stroke:#fff;}
.nav-dropdown-item.is-inert{cursor:default;}

/* ===== HERO ===== */
.hero{background:var(--white);padding:64px 0 0;overflow:hidden;}
.hero-grid{display:grid;grid-template-columns:1.05fr 1fr;gap:40px;align-items:center;}
.hero-copy h1{font-size:clamp(34px,4.6vw,52px);line-height:1.08;font-weight:800;margin-bottom:18px;}
.hero-copy h1 .c-purple{color:var(--purple);}
.hero-copy h1 .c-orange{color:var(--orange);}
.hero-copy p.lead{font-size:16px;color:var(--gray-secondary);max-width:460px;margin-bottom:26px;}
.hero-benefits{display:flex;gap:26px;flex-wrap:wrap;margin-bottom:32px;}
.hero-benefit{display:flex;align-items:center;gap:10px;}
.hero-benefit .icon-circle{width:38px;height:38px;background:#F1EAFA;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.hero-benefit .icon-circle svg{width:18px;height:18px;stroke:var(--purple);}
.hero-benefit b{display:block;font-size:13.5px;color:var(--text-dark);}
.hero-benefit span{font-size:12px;color:var(--gray-secondary);}
/* Hero-benefit icon accents (2026-08-21) — opt-in via the same
   accentClass already flowing through templates/verticalHubPage.js for
   call-cta-top/service-grid/CTA-strip. Piloted on Pest Control alone
   first, then rolled out to HVAC, Appliance Repair, Electrician, Garage
   Doors, and Locksmith once approved — each value below is copied
   verbatim from that vertical's own already-established compact
   service-grid icon rule (.service-type-card.is-compact.accent-{key}
   .cat-icon, further down this file), not re-derived, so the hero icons
   and the service-grid icons always match exactly. Dumpster Rental has no
   accentColor at all (hub.accentColor unset in its manifest), so its
   accentClass is '' and it falls through to the base rule above
   (#F1EAFA/purple) — confirmed intentional and permanent, not just
   pending rollout. HVAC's pairing (#E0F7FC/#02aee4) measures only ~2.3:1
   icon-vs-circle contrast, below the ~3:1 WCAG guideline for graphical
   objects — flagged, not fixed, since it's the exact pairing already
   live on HVAC's own service grid on this same page; reusing it here
   keeps it consistent rather than introducing a second, different value
   for the same vertical. */
.hero-benefit.accent-forest .icon-circle{background:#F4F2E6;}
.hero-benefit.accent-forest .icon-circle svg{stroke:#927c00;}
.hero-benefit.accent-hvac .icon-circle{background:#E0F7FC;}
.hero-benefit.accent-hvac .icon-circle svg{stroke:#02aee4;}
.hero-benefit.accent-appliance-repair .icon-circle{background:#E8EDF1;}
.hero-benefit.accent-appliance-repair .icon-circle svg{stroke:#4F6D8A;}
.hero-benefit.accent-electrician .icon-circle{background:#FAE3E3;}
.hero-benefit.accent-electrician .icon-circle svg{stroke:#B71C1C;}
.hero-benefit.accent-garage-doors .icon-circle{background:#F2EFEC;}
.hero-benefit.accent-garage-doors .icon-circle svg{stroke:#7A5A44;}
.hero-benefit.accent-locksmith .icon-circle{background:#F3F3F3;}
.hero-benefit.accent-locksmith .icon-circle svg{stroke:#000000;}
.hero-benefit.accent-landscaping .icon-circle{background:#EDF3EA;}
.hero-benefit.accent-landscaping .icon-circle svg{stroke:#4F8A2F;}
.hero-benefit.accent-moving .icon-circle{background:#ECEFFA;}
.hero-benefit.accent-moving .icon-circle svg{stroke:#3F63C8;}
.hero-benefit.accent-plumbing .icon-circle{background:#E8F2F2;}
.hero-benefit.accent-plumbing .icon-circle svg{stroke:#167D7F;}
.hero-benefit.accent-roofing .icon-circle{background:#EFF0F1;}
.hero-benefit.accent-roofing .icon-circle svg{stroke:#5F6670;}
.hero-benefit.accent-water-damage .icon-circle{background:#EAF9F8;}
.hero-benefit.accent-water-damage .icon-circle svg{stroke:#2EC4B6;}
.hero-visual{position:relative;}
.hero-img-wrap{
  position:relative;border-radius:24px;overflow:hidden;aspect-ratio:4/3.1;
  background:linear-gradient(135deg,#3D1E68,#2B124C);
}
.hero-img-wrap img{width:100%;height:100%;object-fit:cover;}
.hero-img-wrap::before{
  content:'';position:absolute;left:-30px;top:10%;bottom:10%;width:70px;
  background:var(--purple);border-radius:40px;z-index:0;
}
.hero-card{
  position:absolute;left:-24px;bottom:-24px;background:var(--purple);color:#fff;
  border-radius:16px;padding:18px 22px;display:flex;gap:14px;align-items:flex-start;
  max-width:300px;box-shadow:0 12px 30px rgba(43,18,76,.28);
}
.hero-card .icon-circle{width:36px;height:36px;background:rgba(255,255,255,.14);border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.hero-card .icon-circle svg{width:16px;height:16px;stroke:#fff;}
.hero-card b{display:block;font-size:14px;margin-bottom:3px;}
.hero-card span{font-size:12.5px;color:#D8CDEB;line-height:1.5;}

/* ===== INNER HERO (every page type EXCEPT the top-level vertical hub) =====
   Confirmed 2026-08-12: purple hero is the general pattern for every non-hub
   page — service, guide, state hub, city hub, and combo.
   Only /{vertical}/ itself (.category-hero) keeps the white/photo treatment.
   Renamed from .service-hero once this was confirmed as general, not
   service-page-specific — use THIS class for any new non-hub page type.
   Use renderBreadcrumbs() as-is here; the base .breadcrumbs rules below are
   already styled for a purple background, no scoped override needed.

   UNIVERSAL FIXED STANDARD (2026-08-16) — replaces the 2026-08-13 graduated
   3-tier density system (baseline/tier2/tier3), which was retired entirely.
   Every inner page now gets ONE hero size, no modifier class needed —
   values below are what used to be "tier3" (the combo page's density),
   promoted to be the only size, since a single consistent hero height
   across every inner page type read better than three different depths.
   Deliberate consequence: the service page (previously 100% baseline) and
   the state hub (previously reverted back to full baseline after being
   flagged as "too much empty") both shrink to this same smaller size now —
   both are intentional under this standard, not a regression.
   .is-tier2/.is-tier3 modifier classes and their markup usage
   (templates/serviceStateHubPage.js, templates/comboPage.js) were removed
   — every inner-page template now renders plain `<section class="inner-hero">`
   with no modifier.
   No literal height:Xpx here on purpose — a fixed pixel height risks
   clipping dynamically-generated H1/description text that runs longer than
   expected (e.g. "Concrete / Heavy Debris in Texas"). Visual height instead
   comes from these fixed padding/gap/font values alone, with line-clamp:2 +
   ellipsis on the description below as a safety net so a longer description
   is truncated cleanly (whole words, "…") rather than ever wrapping to a
   3rd line and growing the hero.

   min-height (2026-08-16) — Playwright measurement (getBoundingClientRect,
   not code inspection) showed real, expected variance depending on content:
   223.8px for a 1-line description, 248.59375px for a 2-line description,
   186px for the guide page's hero (no description paragraph at all — every
   other field on this page has real content, so this is a MINIMUM, not a
   fixed height: nothing here can push a hero taller than 248.59375px given
   the H1 clamp + description line-clamp above, so min-height floors every
   shorter case up to the tallest real one instead of capping/clipping
   anything. Confirmed via the same Playwright method afterward: all 8
   sampled inner-page types render exactly 248.59375px. */
.inner-hero{background:var(--purple);padding:26px 0 24px;min-height:248.59px;}
.inner-hero .wrap{color:#fff;}
.inner-hero .breadcrumbs{margin-bottom:9px;}
.inner-hero h1{font-size:clamp(20px,2.7vw,30px);font-weight:800;margin-bottom:7px;}
.inner-hero p{
  font-size:15.5px;color:#D8CDEB;max-width:640px;margin-bottom:13px;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;text-overflow:ellipsis;
}

/* "Available In" location pills — kept for potential reuse elsewhere, no
   longer used on the service page as of 2026-08-13 (see .state-chip below,
   which replaced it there). */
.location-pills{display:flex;flex-wrap:wrap;gap:16px;}
.location-pill{display:inline-flex;align-items:center;gap:7px;font-size:13.5px;font-weight:600;color:var(--purple);background:#fff;border:1.5px solid var(--border);border-radius:100px;padding:10px 18px;transition:background .15s,border-color .15s;}
.location-pill svg{width:15px;height:15px;stroke:var(--purple);flex-shrink:0;}
.location-pill:hover{background:#F1EAFA;border-color:rgba(43,18,76,.25);}

/* State chips — service page's "Available In" section (2026-08-13). Wide,
   short boxes (more horizontal than the square service-grid cards), 5-color
   rotating tint cycling in DOM order via :nth-child, deep-purple text/icon
   on every variant regardless of tint. #FFF1E8 (tint 2) is a confirmed,
   deliberate exception to "orange stays reserved for call actions" — this
   is a light background tint, not the call-action orange itself, and the
   exception is scoped to exactly this component. Not a status system (no
   live/soon meaning) — purely visual variety across genuinely-available
   states, unlike the hub's .cat-badge live/soon treatment. */
.state-chip-grid{display:flex;flex-wrap:wrap;gap:12px;}
.state-chip{
  display:inline-flex;align-items:center;gap:8px;
  padding:14px 22px;border-radius:var(--radius);
  font-size:14px;font-weight:700;color:var(--purple);
  transition:transform .15s,box-shadow .15s;
}
.state-chip svg{width:15px;height:15px;stroke:var(--purple);flex-shrink:0;}
.state-chip:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(43,18,76,.08);}
.state-chip:nth-child(5n+1){background:#F1EAFA;}
.state-chip:nth-child(5n+2){background:#FFF1E8;}
.state-chip:nth-child(5n+3){background:#E4F8F2;}
.state-chip:nth-child(5n+4){background:#FFFFFF;border:1px solid var(--border);}
.state-chip:nth-child(5n+5){background:#F7F7F9;}

/* Town label (2026-08-12) — some states' real top-10-by-population list mixes
   chartered cities with larger towns (New England especially). Rather than
   let a .state-chip silently imply every entry is a city, entries flagged
   locationType:'town' in stateHubPage.js get this small uppercase tag
   inline after the name. Muted/secondary, not a color-coded status —
   informational only, same spirit as the chip grid's tint rotation. */
.chip-type-tag{
  font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--gray-secondary);background:rgba(0,0,0,.06);
  padding:2px 6px;border-radius:4px;margin-left:2px;
}

/* Tile grid — horizontal icon+title+chevron cards, used for "Other Services"
   and "Helpful Guides" on the full-width service page layout. */
.tile-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;}
.tile-link{display:flex;align-items:center;gap:14px;background:#fff;border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px;transition:transform .15s,box-shadow .15s;}
.tile-link:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(43,18,76,.08);}

/* Tinted tile grid (2026-08-15) — state hub's "Browse Services" grid only
   (templates/stateHubPage.js), base for every state page since it's the
   shared template. First 3 tints match .state-chip's established rotation
   (light purple/orange/teal) above. Tint 4 is a new light-blue addition
   (2026-08-15) — the white slot from .state-chip's rotation read as a "gap"
   once every card in this grid needed real color, so it's replaced here
   with a soft blue that rounds out the purple/orange/teal triad rather than
   reusing white. Tint 5 stays the same light neutral gray. Deep-purple
   icon/text on every variant, same as .state-chip. Scoped under
   .tile-grid-tinted so the service page's plain white "Helpful
   Guides"/"Other Services" tile grids stay untouched. */
.tile-grid-tinted .tile-link{border:none;}
.tile-grid-tinted .tile-link:nth-child(5n+1){background:#F1EAFA;}
.tile-grid-tinted .tile-link:nth-child(5n+2){background:#FFF1E8;}
.tile-grid-tinted .tile-link:nth-child(5n+3){background:#E4F8F2;}
.tile-grid-tinted .tile-link:nth-child(5n+4){background:#E8F0FE;}
.tile-grid-tinted .tile-link:nth-child(5n+5){background:#F7F7F9;}
.tile-icon{flex-shrink:0;width:32px;height:32px;display:flex;align-items:center;justify-content:center;}
.tile-icon svg{width:26px;height:26px;stroke:var(--purple);stroke-width:1.6;}
.tile-link.is-guide .tile-icon svg{stroke:var(--teal);}
.tile-title{flex:1;font-size:14.5px;font-weight:700;color:var(--text-dark);line-height:1.3;}
.tile-link .chevron{flex-shrink:0;stroke:var(--gray-disabled);}

/* ===== OTHER SERVICES GRID (2026-08-15, tightened twice same day) =====
   Redesign of the service page's "Other {vertical} Services" section only
   — .tile-grid/.tile-link above stays exactly as it was for "Helpful
   Guides", untouched, this is a separate component. 3x2 grid: one card per
   sibling service (real title/description reused from the manifest's
   existing hubTitle/hubBlurb — same fields the vertical hub's category
   grid already uses, not new copy) plus a purple call-out card filling the
   last grid slot. Icons reused from icons.SERVICE_ICONS, same set already
   used elsewhere for these exact services.

   Icon+title now sit side by side in .other-service-head (was icon-above-
   title, stacked) with a smaller icon — removes a full row of vertical
   space per card. .other-service-card and .other-service-cta share the
   same min-height so all 6 boxes match regardless of row (CSS grid only
   equalizes height WITHIN a row by default, not across the two rows here,
   since each row's auto height is independent) — .other-service-cta gets
   `flex:1` on its <p> so its button still anchors to the bottom instead of
   leaving a gap when its content is shorter than the shared min-height. */
/* grid-auto-rows:1fr (not just min-height on the cards) is what actually
   forces the two rows to match — min-height alone is only a floor, so a
   shorter row still ends up shorter than a row whose tallest item (usually
   the CTA card) needs more than that floor. 1fr rows on an auto-height grid
   equalize every row to the tallest content across all of them. */
.other-services-grid{display:grid;grid-template-columns:repeat(3,1fr);grid-auto-rows:1fr;gap:20px;}
.other-service-card,.other-service-cta{
  display:flex;flex-direction:column;min-height:150px;
  border-radius:16px;padding:20px;
}
.other-service-card{background:#fff;border:1px solid var(--border);transition:transform .15s,box-shadow .15s,border-color .15s;}
.other-service-card:hover{transform:translateY(-3px);box-shadow:0 10px 24px rgba(43,18,76,.1);border-color:rgba(43,18,76,.15);}
.other-service-head{display:flex;align-items:center;gap:12px;margin-bottom:10px;}
.other-service-icon{
  width:40px;height:40px;border-radius:50%;background:#F1EAFA;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
}
.other-service-icon svg{width:20px;height:20px;stroke:var(--purple);stroke-width:1.8;}
.other-service-card h3{font-size:16px;font-weight:800;color:var(--purple);margin:0;line-height:1.25;}
.other-service-card p{font-size:13.5px;color:var(--gray-secondary);line-height:1.5;}
/* Call-out card — fills the grid's last slot, real call button (same
   renderCallCta/data-call-cta mechanism as every other call action on the
   site, not a static button). */
.other-service-cta{background:var(--purple);color:#fff;}
.other-service-cta .other-service-icon{background:transparent;border:1.5px solid rgba(255,255,255,.4);}
.other-service-cta .other-service-icon svg{stroke:#fff;width:18px;height:18px;}
.other-service-cta h3{font-size:16px;font-weight:800;margin:0;line-height:1.25;}
.other-service-cta p{font-size:13px;color:#D8CDEB;line-height:1.5;margin-bottom:14px;flex:1;}
.other-service-cta .btn{align-self:flex-start;}

/* Compact sibling-grid variant (2026-08-13) — opt-in via a vertical's
   hub.compactServiceGrid flag, same flag already driving the vertical hub's
   .service-type-card.is-compact. Icon-left, title+description stacked to
   its right, white background only (no tint rotation — that pattern is the
   hub's category grid, not this sibling grid). Additive .is-compact rules
   layered on the base .other-service-card selectors above; without the
   class (Dumpster Rental) nothing changes. Deliberately doesn't redefine
   .other-services-grid's column count — inherits the existing responsive
   breakpoints below for free. grid-auto-rows reverts to auto here (instead
   of the base rule's 1fr) since compact cards are short enough that forcing
   every row to match the tallest no longer reads right with 23 of them. */
.other-services-grid.is-compact{grid-auto-rows:auto;}
.other-service-card.is-compact{
  flex-direction:row;align-items:center;gap:12px;min-height:0;padding:16px 18px;
}
.other-service-card.is-compact .other-service-icon{width:38px;height:38px;}
.other-service-card.is-compact .other-service-icon svg{width:18px;height:18px;}
.other-service-card.is-compact .other-service-text{min-width:0;}
.other-service-card.is-compact h3{font-size:14.5px;margin:0 0 3px;}
.other-service-card.is-compact p{font-size:12.5px;margin:0;line-height:1.4;}
/* Forest Green icon accent (2026-08-13) — opt-in via .accent-forest
   (hub.accentColor:"forest"), same light-tint-circle + solid-stroke
   combination already used for the hub's live category icons
   (.cat-card.is-live.accent-forest .cat-icon, index.html). Replaces the
   base .other-service-icon's light-purple circle + purple stroke above for
   this vertical only — Dumpster Rental has no accentColor, so its icons
   stay purple. */
.other-service-card.is-compact.accent-forest .other-service-icon{background:#F4F2E6;}
.other-service-card.is-compact.accent-forest .other-service-icon svg{stroke:#927c00;}

/* Full-width CTA strip (2026-08-13) — opt-in via hub.compactServiceGrid,
   replacing the boxed .other-service-cta grid-cell above for verticals
   using the compact sibling grid (it doesn't need to compete for space with
   23+ cards). Sits below .other-services-grid as its own block, not inside
   it. Forest Green via .accent-forest, same flag/reasoning as the hub's
   call-cta-top box; without that class this would fall back to the base
   .other-service-cta purple above, though every vertical using is-strip so
   far also sets accentColor:"forest". */
.other-service-cta.is-strip{
  flex-direction:row;align-items:center;justify-content:space-between;flex-wrap:wrap;
  gap:18px;min-height:0;margin-top:20px;
}
.other-service-cta.is-strip .other-service-cta-info{display:flex;align-items:center;gap:14px;}
.other-service-cta.is-strip .other-service-cta-text h3{margin:0 0 3px;}
.other-service-cta.is-strip .other-service-cta-text p{margin:0;color:#FFFFFF;}
.other-service-cta.is-strip .btn{align-self:center;flex-shrink:0;}
.other-service-cta.accent-forest{background:#927c00;}
/* HVAC accent (2026-08-19) — same opt-in mechanism as accent-forest above,
   scoped to its own modifier class so Pest Control's is-strip CTA
   (accent-forest) is untouched. */
.other-service-cta.accent-hvac{background:#02aee4;}
/* HVAC-specific white subtext override (2026-08-20) removed 2026-08-22 —
   the base .other-service-cta.is-strip .other-service-cta-text p rule
   above was changed from light-lavender #D8CDEB to #FFFFFF for every
   vertical (direct instruction), making this override identical to the
   base and redundant. */
/* Appliance Repair accent (2026-08-20) — same opt-in mechanism as
   accent-forest/accent-hvac above. */
.other-service-cta.accent-appliance-repair{background:#4F6D8A;}
/* Electrician accent (2026-08-20, recolored 2026-08-21 from #F4C430 to
   #B71C1C) — same opt-in mechanism as accent-forest/accent-hvac above.
   #B71C1C is dark, so no purple substitution is needed the way the
   original yellow required — reverted to the standard white-text pattern. */
.other-service-cta.accent-electrician{background:#B71C1C;}
/* Garage Doors accent (2026-08-21) — same opt-in mechanism as
   accent-forest/accent-hvac above. #7A5A44 is dark (~6.2:1 against white),
   so it uses the same plain-white-text pattern as Appliance Repair and
   Electrician. */
.other-service-cta.accent-garage-doors{background:#7A5A44;}
/* Locksmith accent (2026-08-21) — same opt-in mechanism as
   accent-forest/accent-hvac above. #000000 is pure black (21:1 against
   white, the maximum possible contrast ratio), so it uses the same
   plain-white-text pattern as every dark accent. */
.other-service-cta.accent-locksmith{background:#000000;}
/* Landscaping accent (2026-08-22) — same opt-in mechanism as the accents
   above. #4F8A2F measures ~4.19:1 against white — below the ~4.5:1 AA
   threshold for normal text (flagged explicitly, not assumed-fine), but
   above the ~3:1 threshold for large/bold text and UI graphics. Kept as
   plain white text/icon anyway, consistent with every non-critical-fail
   accent on this site (a mild, borderline case, not a severe fail like
   HVAC's original #02aee4 at ~2.57:1, the only accent that actually got a
   text-color substitution). */
.other-service-cta.accent-landscaping{background:#4F8A2F;}
/* Moving accent (2026-08-22) — same opt-in mechanism as the accents
   above. #3F63C8 measures ~5.48:1 against white, checked independently
   (not assumed from HVAC's different, failing blue #02aee4) — comfortably
   clears the ~4.5:1 AA threshold, so it uses the standard plain-white-
   text pattern, no substitution needed. */
.other-service-cta.accent-moving{background:#3F63C8;}
/* Plumbing accent (2026-08-22) — same opt-in mechanism as the accents
   above. #167D7F measures ~4.91:1 against white, checked independently —
   comfortably clears the ~4.5:1 AA threshold, so it uses the standard
   plain-white-text pattern, no substitution needed. */
.other-service-cta.accent-plumbing{background:#167D7F;}
/* Roofing accent (2026-08-22) — same opt-in mechanism as the accents
   above. #5F6670 measures ~5.80:1 against white, checked independently —
   comfortably clears the ~4.5:1 AA threshold, so it uses the standard
   plain-white-text pattern, no substitution needed. */
.other-service-cta.accent-roofing{background:#5F6670;}
/* Water Damage accent (2026-08-22) — same opt-in mechanism as the accents
   above. #2EC4B6 measures ~2.17:1 against white, known in advance to be
   low contrast (lower than HVAC's already-accepted ~2.6:1 exception).
   Reviewed and accepted — uses the same plain-white-text pattern as every
   other accent rather than blocking on it or auto-correcting the hex. */
.other-service-cta.accent-water-damage{background:#2EC4B6;}

/* Quick Answer box (2026-08-13) — new component, guide pages only. Opt-in
   via guideContent.quickAnswer (content-driven, not a flag) — see
   guidePage.js. Purely informational, not a call action: no orange
   anywhere, no button, just a short direct answer with an inline phone
   mention. accent-forest (hub.accentColor) sets the light Forest Green
   background/heading/icon — no non-forest variant exists yet since only
   Pest Control uses this box so far, but the base .quick-answer-box rule
   stays separate from .accent-forest so a future vertical could add its
   own accent color the same way. */
.quick-answer-box{border-radius:16px;padding:22px 24px;}
.quick-answer-box.accent-forest{background:#F4F2E6;}
.quick-answer-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;}
.quick-answer-icon{width:34px;height:34px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;}
.quick-answer-box.accent-forest .quick-answer-icon{background:#fff;}
.quick-answer-box.accent-forest .quick-answer-icon svg{stroke:#927c00;width:18px;height:18px;}
.quick-answer-box.accent-forest h2{color:#837000;font-size:17px;margin:0;}
.quick-answer-box p{font-size:14.5px;color:var(--text-dark);line-height:1.6;margin:0;max-width:75ch;}
.quick-answer-box a.inline-phone-link.accent-forest{color:#837000;font-weight:700;text-decoration:none;}
.quick-answer-box a.inline-phone-link.accent-forest:hover{color:#756300;text-decoration:underline;}

/* State grid — full 50-state listing on the vertical hub's "Browse by
   State" in-page section. Reuses .cat-badge/.cat-badge.live/.cat-badge.soon
   as-is (already generic) for the live/coming-soon distinction, matching
   the homepage category grid. (The standalone /{vertical}/locations/
   directory page that also used to reuse this component was removed
   2026-08-15 — this section is now the only place it's used.) */
.state-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:14px;}
.state-card{
  background:#fff;border:1px solid var(--border);border-radius:var(--radius);
  padding:16px 14px;text-align:center;transition:transform .15s,box-shadow .15s;
}
.state-card.is-live{border-color:rgba(23,184,144,.35);}
.state-card.is-live:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(43,18,76,.08);}
.state-card.is-soon{background:var(--bg-section);}
.state-card .cat-badge{margin-bottom:8px;}
.state-card h3{font-size:13.5px;font-weight:700;color:var(--text-dark);}
.state-card.is-soon h3{color:var(--gray-secondary);}
/* Not-available state (2026-08-14) — e.g. Alaska: no page generated (service
   isn't offered there), so this renders as a plain non-interactive div, not
   an <a> — no hover lift, no link to a page that doesn't exist. */
.state-card.is-unavailable{background:var(--bg-section);border-color:rgba(217,59,59,.25);cursor:default;}
.state-card.is-unavailable h3{color:var(--gray-secondary);}

/* ===== BREADCRUMBS ===== */
.breadcrumbs{display:flex;flex-wrap:wrap;align-items:center;gap:6px;font-size:12.5px;color:#D8CDEB;margin-bottom:16px;}
.breadcrumbs a{color:#D8CDEB;}
.breadcrumbs a:hover{color:#fff;text-decoration:underline;}
.breadcrumbs .sep{color:#8B6FAE;}
.breadcrumbs .current{color:#fff;font-weight:600;}

/* ===== CATEGORIES ===== */
.categories{padding:80px 0 60px;}
.section-title{text-align:center;font-size:clamp(24px,3vw,32px);font-weight:700;color:var(--purple);margin-bottom:40px;}
.cat-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:16px;}
.cat-card{
  background:#fff;border:1px solid var(--border);border-radius:var(--radius);
  padding:22px 16px;text-align:center;transition:transform .15s,box-shadow .15s;
}
.cat-card.is-live{border-color:rgba(23,184,144,.35);}
.cat-card.is-live:hover{transform:translateY(-3px);box-shadow:0 10px 24px rgba(43,18,76,.1);}
.cat-card.is-soon{background:var(--bg-section);}
.cat-badge{
  display:inline-block;font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;
  padding:3px 9px;border-radius:100px;margin-bottom:12px;
}
.cat-badge.live{background:#E4F8F2;color:var(--teal);}
.cat-badge.soon{background:#EEEFF1;color:var(--gray-disabled);}
.cat-badge.unavailable{background:#FBEAEA;color:var(--danger);}
.cat-icon{width:52px;height:52px;border-radius:12px;margin:0 auto 12px;display:flex;align-items:center;justify-content:center;}
.cat-card.is-live .cat-icon{background:#F1EAFA;}
.cat-card.is-live .cat-icon svg{stroke:var(--purple);}
.cat-card.is-soon .cat-icon{background:#E9EAEC;}
.cat-card.is-soon .cat-icon svg{stroke:var(--gray-disabled);}
.cat-icon svg{width:24px;height:24px;}
.cat-card h3{font-size:14.5px;font-weight:700;color:var(--text-dark);margin-bottom:3px;}
.cat-card.is-soon h3{color:var(--gray-secondary);}
.cat-card p{font-size:11.5px;color:var(--gray-secondary);}
.cat-legend{display:flex;justify-content:center;gap:26px;margin-top:26px;font-size:13px;color:var(--gray-secondary);}
.cat-legend span{display:flex;align-items:center;gap:7px;}
.dot{width:9px;height:9px;border-radius:50%;}
.dot.teal{background:var(--teal);}
.dot.gray{background:var(--gray-disabled);}

/* ===== HOW IT WORKS ===== */
.how{padding:70px 0 0;}
.how-steps{display:flex;align-items:flex-start;justify-content:center;gap:0;margin-bottom:52px;}
.how-step{display:flex;gap:14px;max-width:230px;}
.step-num-icon{position:relative;flex-shrink:0;}
.step-circle{
  width:56px;height:56px;border-radius:50%;background:#F1EAFA;
  display:flex;align-items:center;justify-content:center;
}
.step-circle svg{width:22px;height:22px;stroke:var(--purple);}
.step-badge{
  position:absolute;top:-4px;right:-4px;width:22px;height:22px;border-radius:50%;
  background:var(--purple);color:#fff;font-size:11px;font-weight:700;
  display:flex;align-items:center;justify-content:center;
}
.how-step h3{font-size:15.5px;margin:2px 0 4px;color:var(--text-dark);}
.how-step p{font-size:13px;color:var(--gray-secondary);}
.how-arrow{display:flex;align-items:center;padding:0 18px;margin-top:26px;}
.how-arrow svg{width:44px;height:14px;stroke:var(--border);}

/* ===== TRUST STRIP ===== */
.trust-strip{background:var(--purple);border-radius:20px;padding:30px;display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-bottom:80px;}
.trust-item{display:flex;gap:13px;align-items:flex-start;color:#fff;}
.trust-item .icon-circle{width:38px;height:38px;background:rgba(255,255,255,.12);border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.trust-item .icon-circle svg{width:17px;height:17px;stroke:#fff;}
.trust-item.teal-icon .icon-circle svg{stroke:var(--teal);}
.trust-item b{display:block;font-size:14px;margin-bottom:3px;}
.trust-item span{font-size:12px;color:#D8CDEB;line-height:1.5;}

/* ===== FEATURED ===== */
.featured{padding:0 0 80px;}
.feat-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px;}
.feat-card{background:#fff;border:1px solid var(--border);border-radius:16px;overflow:hidden;}
.feat-body{padding:26px;}
.feat-pill{
  display:inline-block;background:var(--purple);color:#fff;font-size:10.5px;font-weight:700;
  letter-spacing:.5px;text-transform:uppercase;padding:4px 11px;border-radius:100px;margin-bottom:14px;
}
.feat-content{display:grid;grid-template-columns:1fr 1fr;}
.feat-text h3{font-size:19px;margin-bottom:8px;}
.feat-text p.desc{font-size:13.5px;color:var(--gray-secondary);margin-bottom:14px;}
.feat-list{display:flex;flex-direction:column;gap:7px;margin-bottom:0;}
.feat-list li{font-size:13px;color:var(--text-dark);display:flex;gap:8px;align-items:flex-start;}
.feat-list li svg{width:14px;height:14px;stroke:var(--teal);flex-shrink:0;margin-top:2px;}
.feat-img{position:relative;border-radius:10px;overflow:hidden;min-height:150px;background:var(--bg-section);}
.feat-img img{width:100%;height:100%;object-fit:cover;position:absolute;inset:0;}
.feat-cta{padding:16px 26px;}
.feat-cta .btn{width:100%;}

/* ===== LOWER CTA ===== */
.lower-cta-wrap{padding:0 0 80px;}
.lower-cta{
  background:var(--purple);border-radius:20px;padding:28px 34px;
  display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap;color:#fff;
}
.lower-cta-left{display:flex;align-items:center;gap:18px;}
.lower-cta-icon{
  width:54px;height:54px;border-radius:50%;background:var(--orange);
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
.lower-cta-icon svg{width:24px;height:24px;stroke:#fff;}
.lower-cta-left b{font-size:17px;display:block;margin-bottom:3px;}
.lower-cta-left span{font-size:13px;color:#D8CDEB;}

/* ===== FOOTER (2026-08-15 rebuild) =====
   5 columns: Brand, Property & Exterior, Home Repair & Systems, Moving &
   Specialty, Hours — same 3 category groupings as the header nav's
   mega-menu, so the site uses one consistent taxonomy everywhere. No
   "(Live)"/"Coming Soon" labels — plain links only, same rule as the nav;
   Dumpster Rental is a real link, everything else (including HVAC) is a
   plain non-interactive <span>, no href, same "coming soon" pattern used
   sitewide. Company column dropped entirely (confirmed, not needed right
   now). Legal column (Privacy/Terms/Disclaimer links) removed outright
   (2026-08-15) — bottom bar is just "© 2026 SkilledMob" (white, centered,
   see .foot-legal-line) followed by the disclaimer paragraph, no links. */
.site-footer{background:var(--purple);color:#D8CDEB;padding:56px 0 0;}
.foot-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr 1fr;gap:28px;padding-bottom:40px;}
.foot-col h4{color:#fff;font-size:13.5px;margin-bottom:15px;}
.foot-col li{margin-bottom:9px;font-size:13px;}
.foot-col a:hover{color:#fff;}
.foot-brand .logo{color:#fff;margin-bottom:12px;}
.foot-brand p{font-size:13px;line-height:1.6;max-width:230px;}
.foot-talk{display:flex;align-items:center;gap:8px;margin-top:14px;font-size:13px;color:#fff;font-weight:600;}
.foot-talk svg{width:15px;height:15px;stroke:var(--orange);}
.foot-bottom{border-top:1px solid rgba(255,255,255,.12);padding:20px 0;text-align:center;}
.foot-legal-line{font-size:12px;color:#fff;font-weight:600;margin-bottom:10px;}
.foot-bottom p{font-size:11.5px;color:#B9A9D1;max-width:820px;margin:0 auto;line-height:1.6;}

/* ===== INTERIOR / CONTENT PAGES (service, guide, state, city, combo) =====
   New components built for Batch 1. Reuse existing tokens only — no new colors/fonts. */

.content-section{padding:56px 0;}
.content-section + .content-section{padding-top:0;}
.two-col{display:grid;grid-template-columns:2.1fr 1fr;gap:40px;align-items:start;}

/* Prose (guide articles, intro copy) */
.prose h2{font-size:22px;color:var(--purple);margin:34px 0 14px;}
.prose h2:first-child{margin-top:0;}
.prose h3{font-size:17px;margin:22px 0 10px;}
.prose p{font-size:15px;color:var(--text-dark);margin-bottom:14px;max-width:70ch;}
.prose ul,.prose ol{list-style:disc;padding-left:22px;margin-bottom:14px;}
.prose ol{list-style:decimal;}
.prose li{font-size:15px;margin-bottom:6px;}
.prose a{color:var(--purple);text-decoration:underline;text-underline-offset:2px;}
/* Inline clickable phone number within body copy — orange (call-action
   color), distinct from the purple used for regular prose links. Selector
   is deliberately ".prose a.inline-phone-link" (not just ".inline-phone-link")
   so it out-specifies the ".prose a" rule above, which would otherwise win
   and force it purple. */
.prose a.inline-phone-link{color:var(--orange);font-weight:700;text-decoration:none;}
.prose a.inline-phone-link:hover{color:var(--orange-hover);text-decoration:underline;}
/* Forest Green accent (2026-08-13) — opt-in via a vertical's hub.accentColor
   manifest flag, scoped to this modifier so Dumpster Rental's orange inline
   phone link above is untouched. Same specificity reasoning as the base rule
   (".prose a.inline-phone-link" beats ".prose a"); this needs one more class
   to also beat that base rule. */
.prose a.inline-phone-link.accent-forest{color:#927c00;}
.prose a.inline-phone-link.accent-forest:hover{color:#756300;}
/* Bug fix 2026-08-16: same specificity collision as .prose a.inline-phone-link
   above — the combo page's fact-box CTA button (.btn-purple, a real <a>) sits
   inside .prose, so ".prose a" (element+class) was beating ".btn-purple"
   (single class), turning the white button label into purple-on-purple
   (invisible) with an underline, only becoming legible on hover once
   .btn-purple:hover's orange background gave the purple text contrast. Same
   out-specify fix: ".prose a.btn-purple" wins over ".prose a". */
.prose a.btn-purple{color:#fff;text-decoration:none;}
.prose table{width:100%;border-collapse:collapse;margin:14px 0 20px;font-size:14px;}
.prose th,.prose td{border:1px solid var(--border);padding:10px 12px;text-align:left;}
.prose th{background:var(--bg-section);font-weight:700;}

/* Sidebar card (used on guide/service/combo pages) */
.side-card{background:var(--bg-section);border:1px solid var(--border);border-radius:var(--radius);padding:22px;margin-bottom:20px;}
.side-card h4{font-size:14px;color:var(--purple);margin-bottom:12px;}
.side-card ul{display:flex;flex-direction:column;gap:9px;}
.side-card li a{font-size:13.5px;color:var(--text-dark);display:flex;gap:8px;align-items:flex-start;}
.side-card li a:hover{color:var(--purple);text-decoration:underline;}
/* Bug fix 2026-08-12: this svg had no width/height anywhere (attribute or
   CSS). An unsized inline <svg> falls back to the browser's replaced-element
   default (~300x150px), which was inflating every <li> to that height —
   the "huge broken gaps" were actually each icon rendering enormous, not
   real spacing. Same icons.check() call is used with no size issue elsewhere
   (e.g. .feat-list, .coverage-highlights) only because those already had
   an explicit svg rule; this component never did. */
.side-card li a svg{width:14px;height:14px;stroke:var(--teal);flex-shrink:0;margin-top:2px;}
.side-card .btn{width:100%;margin-top:6px;}

/* Link grid (state hub -> city hubs, city hub -> combo pages, nearby cities).
   Gap and card padding matched to the service page's density (2026-08-13):
   16px grid gap standard, padding matched to .service-type-card's weight. */
.link-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;}
.link-card{
  background:#fff;border:1px solid var(--border);border-radius:var(--radius);
  padding:24px 20px;transition:transform .15s,box-shadow .15s,border-color .15s;
}
.link-card:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(43,18,76,.08);border-color:rgba(43,18,76,.25);}
.link-card b{display:block;font-size:15px;color:var(--text-dark);margin-bottom:4px;}
.link-card span{font-size:12.5px;color:var(--gray-secondary);}

/* Tinted link grid (2026-08-16) — city hub's "Browse Services" grid only
   (templates/cityHubPage.js). Same 5-color light-tint rotation as
   .tile-grid-tinted above (purple/orange/teal/blue/gray) — reused for
   consistency rather than a new palette. Scoped under .link-grid-tinted so
   the state hub's plain white "Cities We Cover" .link-grid stays untouched. */
.link-grid-tinted .link-card{border:none;}
.link-grid-tinted .link-card:nth-child(5n+1){background:#F1EAFA;}
.link-grid-tinted .link-card:nth-child(5n+2){background:#FFF1E8;}
.link-grid-tinted .link-card:nth-child(5n+3){background:#E4F8F2;}
.link-grid-tinted .link-card:nth-child(5n+4){background:#E8F0FE;}
.link-grid-tinted .link-card:nth-child(5n+5){background:#F7F7F9;}

/* ===== VERTICAL HUB ONLY =====
   Everything below is used exclusively by templates/verticalHubPage.js.
   Photo hero is intentionally reserved for hub pages — every other interior
   template (service/guide/state/city/combo/service-state) uses the purple
   .inner-hero above instead. */

/* Photo hero — independent grid/copy/visual classes (not the homepage's
   .hero-grid/.hero-copy) so the locked homepage hero is never entangled with
   hub-page changes. .hero-benefits/.hero-benefit are reused as-is since
   they're a generic sub-component already, not core hero identity. */
.category-hero{background:var(--white);padding:40px 0 0;overflow:hidden;}
.category-hero .breadcrumbs{color:var(--gray-secondary);margin-bottom:18px;}
.category-hero .breadcrumbs a{color:var(--gray-secondary);}
.category-hero .breadcrumbs a:hover{color:var(--purple);}
.category-hero .breadcrumbs .sep{color:var(--border);}
.category-hero .breadcrumbs .current{color:var(--text-dark);}
.category-hero-grid{display:grid;grid-template-columns:1.05fr 1fr;gap:40px;align-items:center;padding-bottom:8px;}
.category-hero-copy h1{font-size:clamp(34px,4.6vw,52px);font-weight:800;color:var(--purple);line-height:1.08;margin-bottom:14px;}
.category-hero-copy p.lead{font-size:16px;color:var(--gray-secondary);max-width:480px;margin-bottom:26px;}
.category-hero-copy .hero-benefits{margin-bottom:30px;}
/* Value-prop icons scoped to the hub hero only — bumped up from the base
   .hero-benefit 38px/18px sizing (locked, shared with the homepage) to
   ~58px/26px per the approved hub mockup. Does not touch .hero-copy, so the
   homepage is unaffected. */
.category-hero-copy .hero-benefits .icon-circle{width:58px;height:58px;}
.category-hero-copy .hero-benefits .icon-circle svg{width:26px;height:26px;stroke-width:2;}
.category-hero-visual{position:relative;}
.category-hero-img-wrap{position:relative;border-radius:24px;overflow:hidden;aspect-ratio:4/3.1;background:var(--bg-section);}
.category-hero-img-wrap img{width:100%;height:100%;object-fit:cover;}

/* Intro + call-cta card, two columns below the hero */
.category-intro{padding:44px 0 56px;}
.category-intro-grid{display:grid;grid-template-columns:2fr 1fr;gap:40px;align-items:start;}
.category-intro-grid h2{font-size:23px;color:var(--purple);margin-bottom:14px;}
.category-intro-grid .prose p{max-width:none;font-size:15.5px;}

.call-cta{background:var(--bg-section);border:1px solid var(--border);border-radius:16px;overflow:hidden;}
.call-cta-top{background:var(--purple);color:#fff;padding:22px;display:flex;gap:14px;align-items:flex-start;}
.call-cta-top .icon-circle{width:42px;height:42px;background:rgba(255,255,255,.18);border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.call-cta-top .icon-circle svg{width:20px;height:20px;stroke:#fff;stroke-width:2;}
.call-cta-top b{display:block;font-size:16px;margin-bottom:3px;}
.call-cta-top span{font-size:13px;color:rgba(255,255,255,.9);line-height:1.5;}
/* Forest Green accent (2026-08-13) — opt-in via a vertical's hub.accentColor
   manifest flag, scoped to this modifier class so the default purple box
   above is untouched for every other vertical (Dumpster Rental, HVAC). */
.call-cta-top.accent-forest{background:#927c00;}
/* HVAC accent (2026-08-19) — same opt-in mechanism as accent-forest above. */
.call-cta-top.accent-hvac{background:#02aee4;}
/* Appliance Repair accent (2026-08-20) — same opt-in mechanism as
   accent-forest/accent-hvac above. */
.call-cta-top.accent-appliance-repair{background:#4F6D8A;}
/* Electrician accent (2026-08-20, recolored 2026-08-21 from #F4C430 to
   #B71C1C) — same opt-in mechanism as the three accents above. #B71C1C is
   dark (~6.6:1 contrast against white), so it uses the same plain-white
   text/icon-stroke pattern as Forest/HVAC/Appliance Repair — no purple
   substitution needed the way the original yellow required. */
.call-cta-top.accent-electrician{background:#B71C1C;}
/* Garage Doors accent (2026-08-21) — same opt-in mechanism as the four
   accents above. #7A5A44 is dark (~6.2:1 contrast against white), so it
   uses the same plain-white text/icon-stroke pattern, no substitution
   needed. */
.call-cta-top.accent-garage-doors{background:#7A5A44;}
/* Locksmith accent (2026-08-21) — same opt-in mechanism as the five
   accents above. #000000 is pure black (21:1 contrast against white, the
   maximum possible ratio), so it uses the same plain-white text/icon-
   stroke pattern, no substitution needed. */
.call-cta-top.accent-locksmith{background:#000000;}
/* Landscaping accent (2026-08-22) — same opt-in mechanism as the six
   accents above. #4F8A2F measures ~4.19:1 against white, a mild,
   borderline fail below the ~4.5:1 AA text threshold (flagged explicitly)
   but above the ~3:1 large-text/UI-graphics threshold — kept as plain
   white text/icon, consistent with every other non-critical-fail accent. */
.call-cta-top.accent-landscaping{background:#4F8A2F;}
/* Moving accent (2026-08-22) — same opt-in mechanism as the accents
   above. #3F63C8 measures ~5.48:1 against white, checked independently —
   comfortably clears the ~4.5:1 AA threshold, so plain white text/icon,
   no substitution needed. */
.call-cta-top.accent-moving{background:#3F63C8;}
/* Plumbing accent (2026-08-22) — same opt-in mechanism as the accents
   above. #167D7F measures ~4.91:1 against white, checked independently —
   comfortably clears the ~4.5:1 AA threshold, so plain white text/icon,
   no substitution needed. */
.call-cta-top.accent-plumbing{background:#167D7F;}
/* Roofing accent (2026-08-22) — same opt-in mechanism as the accents
   above. #5F6670 measures ~5.80:1 against white, checked independently —
   comfortably clears the ~4.5:1 AA threshold, so plain white text/icon,
   no substitution needed. */
.call-cta-top.accent-roofing{background:#5F6670;}
/* Water Damage accent (2026-08-22) — same opt-in mechanism as the accents
   above. #2EC4B6 measures ~2.17:1 against white, known in advance to be
   low contrast (lower than HVAC's already-accepted ~2.6:1 exception).
   Reviewed and accepted — plain white text/icon, same as every other
   accent, not blocked on or auto-corrected. */
.call-cta-top.accent-water-damage{background:#2EC4B6;}
.call-cta-status{display:flex;align-items:center;gap:7px;padding:14px 22px;font-size:13px;color:var(--teal);font-weight:600;}

/* 6-card service-type grid */
.service-type-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;}
.service-type-card{background:#fff;border:1px solid var(--border);border-radius:var(--radius);padding:24px 20px;text-align:center;transition:transform .15s,box-shadow .15s;}
.service-type-card:hover{transform:translateY(-3px);box-shadow:0 10px 24px rgba(43,18,76,.1);}
.service-type-card .cat-icon{width:58px;height:58px;border-radius:50%;background:#F1EAFA;}
.service-type-card .cat-icon svg{width:26px;height:26px;stroke:var(--purple);stroke-width:2;}
.service-type-card h3{font-size:15.5px;font-weight:700;margin-bottom:6px;}
.service-type-card p{font-size:13px;color:var(--gray-secondary);}

/* Compact service-grid variant (2026-08-13) — icon-left, title+description
   stacked to its right, smaller card overall. Opt-in via a vertical's
   hub.compactServiceGrid config flag (see verticalHubPage.js) — currently
   just Pest Control, whose 24-card grid read too tall repeated that many
   times with the original icon-on-top layout. Deliberately does NOT
   redefine .service-type-grid's grid-template-columns — inherits the
   existing 3/2/1-column responsive breakpoints below for free, so there's
   no specificity fight with those media queries. Everything here is an
   additive .is-compact rule layered on the base .service-type-card
   selector above; without that class (Dumpster Rental) nothing changes. */
.service-type-card.is-compact{
  display:flex;align-items:center;gap:12px;text-align:left;padding:14px 16px;
}
.service-type-card.is-compact .cat-icon{width:42px;height:42px;flex-shrink:0;margin:0;}
.service-type-card.is-compact .cat-icon svg{width:19px;height:19px;}
.service-type-card.is-compact .service-type-text{min-width:0;}
.service-type-card.is-compact h3{font-size:13.5px;margin-bottom:2px;}
.service-type-card.is-compact p{font-size:11.5px;text-align:left;margin:0;line-height:1.35;}
/* Alternating white/forest-tint (2026-08-13, updated same day — was gray via
   --bg-section, replaced per direction with a very light tint of Pest
   Control's then-accent color instead of the generic gray) — every
   other card in DOM order, not a row/column pattern, so it stays a simple
   1-2-1-2 stripe regardless of how the 3/2/1-column responsive grid
   reflows. Originally a ~92%-white tint, deliberately pale (not the
   stronger --forest-tint used for icon circles elsewhere) since this
   covers the whole card, not just a small badge. Lightened further
   (2026-08-13, same day) to #F5FAF8, a ~96%-white tint — still a visible
   color cast next to the white cards, just subtler than the original.
   Odd cards keep the base .service-type-card white — only even
   ones get the override. Scoped to .is-compact, so Dumpster Rental's grid
   is unaffected. This was Pest Control's original, deliberately different
   treatment (see the HVAC comment below, written at the time) — since
   superseded (2026-08-21) by the .accent-forest override immediately
   below, which brings Pest Control in line with every vertical built
   after it. Left in place only as the fallback for a hypothetical future
   compact-grid vertical with no accentColor at all. #F5FAF8 itself was
   never updated during the 2026-08-22 gold recolor since this rule is
   already dead for Pest Control (fully cancelled by the accent-forest
   override below) — see that recolor's audit notes. */
.service-type-card.is-compact:nth-child(even){background:#F5FAF8;}
/* Pest Control icon accent (2026-08-21, recolored 2026-08-22 from Forest
   Green #2E6B4F to gold #927c00) — brings Pest Control's service
   grid in line with every vertical built after it (HVAC onward below),
   which all use white cards with a colored icon circle instead of this
   page's original alternating-tint-stripe/purple-icon treatment. #F4F2E6
   is the same icon-circle tint already established for the accent
   elsewhere (.other-service-card.is-compact.accent-forest, this file, and
   the hero-benefit icons), reused verbatim rather than re-derived. The
   nth-child override cancels the inherited stripe from the rule above, so
   every Pest Control card stays white — same mechanism as accent-hvac
   immediately below. */
.service-type-card.is-compact.accent-forest .cat-icon{background:#F4F2E6;}
.service-type-card.is-compact.accent-forest .cat-icon svg{stroke:#927c00;}
.service-type-card.is-compact.accent-forest:nth-child(even){background:#fff;}
/* HVAC icon accent (2026-08-19) — opt-in via .accent-hvac (hub.accentColor:
   "hvac"), white cards with a light-cyan icon-circle + solid #02aee4 stroke,
   same white-cards-with-colored-icons pattern Pest Control's own grid was
   brought in line with above (2026-08-21) — the nth-child override below
   cancels the inherited stripe so every HVAC card stays white. Scoped to
   .accent-hvac, so Dumpster Rental's grid (no accentColor) is unaffected. */
.service-type-card.is-compact.accent-hvac .cat-icon{background:#E0F7FC;}
.service-type-card.is-compact.accent-hvac .cat-icon svg{stroke:#02aee4;}
.service-type-card.is-compact.accent-hvac:nth-child(even){background:#fff;}
/* Appliance Repair icon accent (2026-08-20) — same opt-in mechanism and
   same white-cards-with-colored-icons reasoning as accent-hvac above. */
.service-type-card.is-compact.accent-appliance-repair .cat-icon{background:#E8EDF1;}
.service-type-card.is-compact.accent-appliance-repair .cat-icon svg{stroke:#4F6D8A;}
.service-type-card.is-compact.accent-appliance-repair:nth-child(even){background:#fff;}
/* Electrician icon accent (2026-08-20, recolored 2026-08-21 from #F4C430
   to #B71C1C) — same opt-in mechanism and same white-cards-with-colored-
   icons reasoning as accent-hvac above. #B71C1C is dark enough at the
   standard 1.8px stroke-width that the stroke-width bump the original
   yellow needed is no longer necessary — reverted to match the standard
   pattern used by every other accent. */
.service-type-card.is-compact.accent-electrician .cat-icon{background:#FAE3E3;}
.service-type-card.is-compact.accent-electrician .cat-icon svg{stroke:#B71C1C;}
.service-type-card.is-compact.accent-electrician:nth-child(even){background:#fff;}
/* Garage Doors icon accent (2026-08-21) — same opt-in mechanism and same
   white-cards-with-colored-icons reasoning as accent-hvac above. #7A5A44
   is dark enough at the standard 1.8px stroke-width, no bump needed. */
.service-type-card.is-compact.accent-garage-doors .cat-icon{background:#F2EFEC;}
.service-type-card.is-compact.accent-garage-doors .cat-icon svg{stroke:#7A5A44;}
.service-type-card.is-compact.accent-garage-doors:nth-child(even){background:#fff;}
/* Locksmith icon accent (2026-08-21) — same opt-in mechanism and same
   white-cards-with-colored-icons reasoning as accent-hvac above. Icon
   circle uses #F3F3F3 (plain light gray, per explicit direction — black
   has no hue to derive a tint from, unlike every other accent's tinted
   circle) with a solid #000000 stroke; #D9D9D9/#666666 reserved for any
   secondary border/hover needs but not required here. */
.service-type-card.is-compact.accent-locksmith .cat-icon{background:#F3F3F3;}
.service-type-card.is-compact.accent-locksmith .cat-icon svg{stroke:#000000;}
.service-type-card.is-compact.accent-locksmith:nth-child(even){background:#fff;}
/* Landscaping icon accent (2026-08-22) — same opt-in mechanism and same
   white-cards-with-colored-icons reasoning as accent-hvac above. #4F8A2F
   is legible enough at the standard 1.8px stroke-width for a small icon
   (this pairing is icon-on-light-tint, not text-on-solid, so the ~4.19:1
   text-contrast concern noted elsewhere doesn't apply the same way here). */
.service-type-card.is-compact.accent-landscaping .cat-icon{background:#EDF3EA;}
.service-type-card.is-compact.accent-landscaping .cat-icon svg{stroke:#4F8A2F;}
.service-type-card.is-compact.accent-landscaping:nth-child(even){background:#fff;}
/* Moving icon accent (2026-08-22) — same opt-in mechanism and same
   white-cards-with-colored-icons reasoning as accent-hvac above. #3F63C8
   is well legible at the standard 1.8px stroke-width. */
.service-type-card.is-compact.accent-moving .cat-icon{background:#ECEFFA;}
.service-type-card.is-compact.accent-moving .cat-icon svg{stroke:#3F63C8;}
.service-type-card.is-compact.accent-moving:nth-child(even){background:#fff;}
/* Plumbing icon accent (2026-08-22) — same opt-in mechanism and same
   white-cards-with-colored-icons reasoning as accent-hvac above. #167D7F
   is well legible at the standard 1.8px stroke-width. */
.service-type-card.is-compact.accent-plumbing .cat-icon{background:#E8F2F2;}
.service-type-card.is-compact.accent-plumbing .cat-icon svg{stroke:#167D7F;}
.service-type-card.is-compact.accent-plumbing:nth-child(even){background:#fff;}
/* Roofing icon accent (2026-08-22) — same opt-in mechanism and same
   white-cards-with-colored-icons reasoning as accent-hvac above. #5F6670
   is well legible at the standard 1.8px stroke-width. */
.service-type-card.is-compact.accent-roofing .cat-icon{background:#EFF0F1;}
.service-type-card.is-compact.accent-roofing .cat-icon svg{stroke:#5F6670;}
.service-type-card.is-compact.accent-roofing:nth-child(even){background:#fff;}
/* Water Damage icon accent (2026-08-22) — same opt-in mechanism and same
   white-cards-with-colored-icons reasoning as accent-hvac above. #2EC4B6
   is well legible at the standard 1.8px stroke-width against the light
   #EAF9F8 tint background — the low text-contrast concern noted above
   applies to white text on the accent itself, not to this icon-on-tint
   pattern. */
.service-type-card.is-compact.accent-water-damage .cat-icon{background:#EAF9F8;}
.service-type-card.is-compact.accent-water-damage .cat-icon svg{stroke:#2EC4B6;}
.service-type-card.is-compact.accent-water-damage:nth-child(even){background:#fff;}

/* FAQ grid (2026-08-14) — always-visible, no accordion. Same border/
   padding/radius language as .service-type-card above, left-aligned since
   this is read text rather than an icon-first nav card. Hub page: 3x2 (6
   FAQs), default below. .faq-grid-2col modifier: 2x2 (4 FAQs) — service page
   and other deeper page types, per the standing per-page-type FAQ count. */
.faq-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;}
.faq-grid.faq-grid-2col{grid-template-columns:repeat(2,1fr);}
.faq-card{background:#fff;border:1px solid var(--border);border-radius:var(--radius);padding:24px 20px;}
.faq-card h3{font-size:15px;font-weight:700;color:var(--purple);margin-bottom:8px;line-height:1.35;}
.faq-card p{font-size:13.5px;color:var(--gray-secondary);line-height:1.55;}

/* Coverage + guides combined panel */
.coverage-panel{background:var(--bg-section);border:1px solid var(--border);border-radius:16px;padding:0;display:grid;grid-template-columns:1.4fr 1fr 1fr;}
.coverage-panel > div{padding:28px 26px;}
.coverage-panel > div + div{border-left:1px solid var(--border);}
.coverage-panel-info{display:flex;gap:14px;align-items:flex-start;}
.coverage-panel-info .icon-circle{width:48px;height:48px;background:#F1EAFA;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.coverage-panel-info .icon-circle svg{width:22px;height:22px;stroke:var(--purple);stroke-width:2;}
.coverage-panel-info h4{font-size:15px;margin-bottom:6px;}
.coverage-panel-info p{font-size:13px;color:var(--gray-secondary);}
.coverage-highlights{display:flex;flex-direction:column;gap:9px;margin-top:14px;}
.coverage-highlights li{display:flex;gap:9px;align-items:flex-start;font-size:13px;color:var(--text-dark);}
.coverage-highlights li svg{width:14px;height:14px;stroke:var(--teal);flex-shrink:0;margin-top:2px;}
.coverage-panel-expand p{font-size:13px;color:var(--gray-secondary);margin-bottom:14px;}

.guide-list h4{font-size:14.5px;color:var(--purple);margin-bottom:14px;}
.guide-list{display:flex;flex-direction:column;gap:2px;}
.guide-link{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 0;font-size:13.5px;color:var(--text-dark);border-bottom:1px solid var(--border);}
.guide-link:last-child{border-bottom:none;}
.guide-link:hover{color:var(--purple);}
.guide-link svg:last-child{stroke:var(--gray-disabled);flex-shrink:0;}

/* FAQ */
.faq-item{border-bottom:1px solid var(--border);padding:18px 0;}
.faq-item:first-child{padding-top:0;}
.faq-item h3{font-size:15.5px;margin-bottom:8px;color:var(--text-dark);}
.faq-item p{font-size:14px;color:var(--gray-secondary);}

/* Nearby cities / related links strip */
.related-strip{display:flex;flex-wrap:wrap;gap:10px;margin-top:8px;}
.related-strip a{
  font-size:12.5px;color:var(--purple);background:var(--bg-section);border:1px solid var(--border);
  border-radius:100px;padding:7px 14px;
}
.related-strip a:hover{background:#F1EAFA;}

/* Local facts callout — flex row (2026-08-16) so a CTA button can sit on
   the right of the text instead of stacked below it; the text itself stays
   in .fact-box-text so it remains one flex item, not two. */
.fact-box{background:#F1EAFA;border-radius:var(--radius);padding:18px 20px;margin:20px 0;display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;}
.fact-box-text b{display:block;color:var(--purple);font-size:13px;margin-bottom:4px;}
.fact-box-text p{font-size:13.5px;color:var(--text-dark);margin:0;}
.fact-box .btn{flex-shrink:0;}

/* ===== RESPONSIVE ===== */
@media(max-width:1024px){
  .cat-grid{grid-template-columns:repeat(4,1fr);}
  .state-grid{grid-template-columns:repeat(4,1fr);}
  .foot-grid{grid-template-columns:1fr 1fr;}
  .trust-strip{grid-template-columns:1fr 1fr;}
  .two-col{grid-template-columns:1fr;}
  .link-grid{grid-template-columns:repeat(2,1fr);}
  .service-type-grid{grid-template-columns:repeat(2,1fr);}
  .tile-grid{grid-template-columns:repeat(2,1fr);}
  .other-services-grid{grid-template-columns:repeat(2,1fr);}
  .faq-grid{grid-template-columns:repeat(2,1fr);}
  .coverage-panel{grid-template-columns:1fr;}
  .coverage-panel > div + div{border-left:none;border-top:1px solid var(--border);}
}
@media(max-width:860px){
  .main-nav{
    display:none;flex-direction:column;align-items:stretch;gap:2px;
    position:absolute;top:78px;left:0;right:0;background:var(--purple-header);
    padding:14px 24px 20px;border-bottom:1px solid rgba(255,255,255,.12);
    max-height:calc(100vh - 78px);overflow-y:auto;
  }
  .hamburger{display:block;}
  /* Mobile nav (2026-08-15) — same 4 items, same link/inert data, just
     restructured as a stacked accordion instead of a horizontal hover bar
     (hover doesn't really exist on touch). Click/tap is the only way to
     open a group here — the desktop :hover rule still matches technically
     but nothing on a touchscreen triggers it, so .is-open (JS) does all the
     work at this width. */
  .main-nav > a,.nav-dropdown-trigger{width:100%;padding:12px 4px;font-size:15px;}
  .nav-dropdown-trigger{justify-content:space-between;}
  /* Same 2x2 icon-tile grid as desktop, just static-positioned (part of the
     accordion flow) instead of floating, and recolored for the dark
     accordion panel instead of the white desktop dropdown. */
  .nav-dropdown-menu{
    position:static;left:auto;transform:none;display:none;width:auto;background:transparent;border:none;
    box-shadow:none;padding:4px 0;margin:2px 0 4px;
  }
  .nav-dropdown-menu.is-open{display:grid;}
  .nav-dropdown-item{color:#fff;border-color:rgba(255,255,255,.16);padding:10px;}
  .nav-dropdown-item svg{stroke:#fff;}
  a.nav-dropdown-item{color:#fff;}
  a.nav-dropdown-item:hover{background:var(--orange);border-color:var(--orange);color:#fff;}
  a.nav-dropdown-item:hover svg{stroke:#fff;}
  .hero-grid{grid-template-columns:1fr;}
  .hero-visual{order:-1;}
  .hero-card{position:static;margin-top:16px;max-width:none;}
  .hero-img-wrap::before{display:none;}
  .feat-grid{grid-template-columns:1fr;}
  .feat-content{grid-template-columns:1fr;}
  .feat-img{order:-1;}
  .how-steps{flex-direction:column;gap:22px;}
  .how-arrow{display:none;}
}
@media(max-width:600px){
  .cat-grid{grid-template-columns:repeat(2,1fr);}
  .state-grid{grid-template-columns:repeat(2,1fr);}
  .trust-strip{grid-template-columns:1fr;}
  .header-inner{padding:0 16px;}
  .wrap{padding:0 16px;}
  .lower-cta{flex-direction:column;align-items:flex-start;}
  .lower-cta .btn{width:100%;}
  .fact-box{flex-direction:column;align-items:flex-start;}
  .fact-box .btn{width:100%;}
  .link-grid{grid-template-columns:1fr;}
  .service-type-grid{grid-template-columns:1fr;}
  .tile-grid{grid-template-columns:1fr;}
  /* auto, not 1fr, at single-column mobile — with only one card per "row"
     there's no sibling to match height to, so forcing 1fr here would just
     stretch every short card to match the CTA card's height for no reason,
     leaving a lot of dead space in a stacked single-column list. */
  .other-services-grid{grid-template-columns:1fr;grid-auto-rows:auto;}
  .faq-grid{grid-template-columns:1fr;}
  .faq-grid.faq-grid-2col{grid-template-columns:1fr;}
  .category-intro-grid{grid-template-columns:1fr;}
  .location-pills{gap:10px;}
  .back-to-top{right:16px;}
}
/* Header call-CTA goes icon-only below 500px (2026-08-22 mobile audit
   fix). 500px is a tested value, not a round-number guess — the header's
   min-width:0 fix above lets the button shrink, but the full
   "Call (XXX) XXX-XXXX" label plus the hamburger genuinely doesn't fit
   next to the logo below this width on real content: 480px still clips
   the hamburger, 490px only shows a sliver of it, and it's not fully
   visible with normal spacing until 500-510px. At 500px and up the
   existing full-text button is untouched. Scoped to
   .header-actions .btn-call specifically, so no other .btn-call on the
   page (hero CTA, CTA strips, footer, etc.) is affected — this is the
   sticky header's button only. Still a fully functional tel: link at
   every width; only the visible text label is hidden. */
@media(max-width:499px){
  .header-actions .btn-call{width:48px;height:48px;min-height:48px;padding:0;justify-content:center;flex-shrink:0;}
  .header-actions .btn-call [data-call-label]{display:none;}
}
