/*
  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;}
html{scroll-behavior:smooth;}
body{
  font-family:'Inter',sans-serif;
  color:var(--text-dark);
  background:var(--white);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
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:#2E6B4F;border-color:#2E6B4F;}
.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;}
.logo .pin{width:16px;height:16px;margin:0 1px;}
.main-nav{display:flex;align-items:center;gap:30px;}
.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;}
.header-actions{display:flex;align-items:center;gap:16px;}
.hamburger{display:none;background:none;border:none;padding:8px;}
.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-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:#E3EEE8;}
.other-service-card.is-compact.accent-forest .other-service-icon svg{stroke:#2E6B4F;}

/* 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:#D8CDEB;}
.other-service-cta.is-strip .btn{align-self:center;flex-shrink:0;}
.other-service-cta.accent-forest{background:#2E6B4F;}

/* 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:#E7F2ED;}
.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:#2E6B4F;width:18px;height:18px;}
.quick-answer-box.accent-forest h2{color:#2E6B4F;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:#2E6B4F;font-weight:700;text-decoration:none;}
.quick-answer-box a.inline-phone-link.accent-forest:hover{color:#245a41;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:#2E6B4F;}
.prose a.inline-phone-link.accent-forest:hover{color:#245a41;}
/* 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:#2E6B4F;}
.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 own Forest Green #2E6B4F 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. #EDF5F0 is a ~92%-white tint of #2E6B4F, 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
   green cast next to the white cards, just subtler than the original
   #EDF5F0. 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. */
.service-type-card.is-compact:nth-child(even){background:#F5FAF8;}

/* 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;}
}
