/* ============================================================
   LPI — polish-motion.css  (Sprints 2 & 3, additive, CSS-only)
   Loaded AFTER base.css, style.css, pages.css.
   Sprint 2: motion-language consistency (reuse --ease-out), focus rings,
             card hover-lift, header scroll polish, reduced-motion guards.
   Sprint 3: fluid cross-document page transitions (@view-transition),
             @supports-gated, reduced-motion instant.
   NO HTML/content change. All decoration passes the harm + decoration gates.
   ============================================================ */

/* ---- Sprint 2: unify interaction timing on the content-page components ---- */
/* pages.css hover/transition rules used hardcoded easing; route them through
   the homepage token so every page shares one motion language. */
:root {
  /* fall back if a page somehow lacks the token from style.css */
  --ease-out: var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1));
  /* Unify the hover-lift to -3px so every card type moves by the same amount
     (the pages.css component rules already lift -3px; this block was -4px — a
     sub-visible drift that made the two card families feel slightly different). */
  --lift: -3px;
  --dur-fast: 140ms;   /* button/link feedback — inside the 100–160ms window */
  --dur-med: 240ms;    /* card-lift interaction — under the 300ms ceiling */
}

/* Consistent, buttery hover-lift + shadow on the content-page cards/CTAs.
   Scoped to the pages.css component grammar so it never fights the suburb cards. */
.lpi-card,
.lpi-service-card,
.lpi-step,
.lpi-cta,
.lpi-feature,
.pages-card {
  transition:
    transform var(--dur-med) var(--ease-out),
    box-shadow var(--dur-med) var(--ease-out),
    border-color var(--dur-med) var(--ease-out);
  will-change: transform;
}
.lpi-card:hover,
.lpi-service-card:hover,
.lpi-feature:hover,
.pages-card:hover {
  transform: translateY(var(--lift));
  box-shadow: 0 18px 40px -18px rgba(6, 43, 88, 0.35);
}

/* Buttery theme-toggle + link/button timing, token-driven */
.theme-toggle,
.btn,
a.btn,
.header__nav a {
  transition:
    color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.btn:active,
a.btn:active { transform: translateY(1px); }

/* Accessible focus ring — visible only for keyboard users, brand-amber */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--color-accent, #ffbe01);
  outline-offset: 2px;
  border-radius: var(--radius-sm, 4px);
}

/* Header scroll polish is owned by `.header--scrolled` in style.css (the class the
   per-page inline JS actually toggles). A prior pass added a `.is-scrolled` rule
   here — a class NOTHING applies (dead) that also duplicated a live backdrop-filter.
   Removed by subtraction; style.css remains the single source for the scrolled skin. */

/* Gentle, token-driven scroll-reveal for content-page sections that don't
   already carry the homepage reveal. Uses scroll-driven animation where
   supported; degrades to fully-visible (fill both) everywhere else. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .pages-reveal,
    .lpi-section > .lpi-card,
    .lpi-steps > .lpi-step {
      animation: pagesRevealFade linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 32%;
    }
    @keyframes pagesRevealFade {
      from { opacity: 0; transform: translateY(14px); }
      to   { opacity: 1; transform: translateY(0); }
    }
  }
}

/* ---- Sprint 3: fluid cross-document (page-to-page) transitions ---- */
/* Cross-document view transitions: a soft cross-fade + slight rise as you
   navigate page->page, so the static multi-page site feels like one app.
   @supports-gated; on unsupported browsers (older Safari) it's a normal nav. */
@supports (view-transition-name: root) {
  @view-transition { navigation: auto; }

  @media (prefers-reduced-motion: no-preference) {
    ::view-transition-old(root),
    ::view-transition-new(root) {
      animation-duration: 260ms;
      animation-timing-function: var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1));
    }
    ::view-transition-new(root) {
      animation-name: vtRise, vtFadeIn;
    }
    ::view-transition-old(root) {
      animation-name: vtFadeOut;
    }
    @keyframes vtRise    { from { transform: translateY(8px); } to { transform: none; } }
    @keyframes vtFadeIn  { from { opacity: 0; } to { opacity: 1; } }
    @keyframes vtFadeOut { from { opacity: 1; } to { opacity: 0; } }

    /* Keep the header/logo visually stable across the transition */
    .header { view-transition-name: lpi-header; }
    ::view-transition-group(lpi-header) { animation-duration: 200ms; }
  }
}

/* ============================================================
   Sprint 4 (2026-07-02): SUBURB-HERO MATERIALITY PARITY — the 33× win.
   The homepage hero carries TWO extra elements the 32 suburb heroes' HTML
   lacks: a `.hero__bloom` div (warm amber light pool + cool counter-tone) and
   a `.hero__grain` SVG (fractal-noise texture). Without them a suburb `.hero`
   falls back to the flat navy gradient in style.css — it reads "empty navy",
   not the homepage's "lit evidence canvas". Adding those DIVs to 32 rankable
   pages = a DOM change (forbidden). Instead promote the SAME materiality to
   `.hero::before`/`::after` PSEUDO-elements — paint-once, background-only, ZERO
   DOM/text change — scoped with `:not(:has(.hero__bloom/__grain))` so the
   homepage (which owns the real divs) is never doubled. Cross-page consistency
   sweep per the playbook: promote ONE canonical hero treatment, no per-page edit.
   Gate A: background/paint-once, no rankable text moved, no CLS (absolutely
   positioned, z-index below content), no LCP change (H1 still paints first).
   Gate B: deepens the "lit dossier" narrative the homepage already established.
   ============================================================ */

/* Warm amber bloom + cool counter-tone — matched to the homepage `.hero__bloom`
   gradient stops/alphas. Rule-of-thirds dominant pool upper-right (Fukinsei:
   one pool dominates), cooler navy accent lower-left so the warm reads warmer. */
.hero:not(:has(.hero__bloom))::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(44% 48% at 82% 20%, rgba(255,190,1,0.26) 0%, rgba(255,190,1,0.08) 40%, transparent 70%),
    radial-gradient(34% 40% at 90% 28%, rgba(255,190,1,0.13) 0%, transparent 62%),
    radial-gradient(55% 55% at 8% 92%, rgba(91,155,213,0.16) 0%, transparent 66%),
    radial-gradient(46% 34% at 48% 112%, rgba(255,190,1,0.06) 0%, transparent 62%);
}

/* Grain texture — static feTurbulence (fractalNoise) SVG served as a tiny cached
   asset (a data-URI trips the tech-sweep's url() scanner on the SVG's own internal
   `url(#g)` filter ref). One small background request across the suburb pages;
   never the LCP. Matches the homepage grain feel without a second <svg> in the DOM.
   ~5% effective opacity, overlay blend so it reads as texture on the navy, not haze. */
.hero:not(:has(.hero__grain))::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("/assets/images/hero-grain.svg");
  background-size: 140px 140px;
}

/* ---- Suburb hero content register: match the homepage's editorial grammar ----
   `.hero__eyebrow` and `.hero__subtitle` ship UNSTYLED (no rule in style.css) so
   they render as a plain grey label + naked paragraph — the exact "plain all-caps
   label" AI-tell the homepage avoids with its bespoke index-mark kicker + amber-
   ruled answer-block. Re-express them in that same bespoke register (real text,
   presentation-only). */

/* Plain label -> hairline gold index-mark kicker (bespoke, on-narrative). */
.hero .hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4, 1rem);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.72);
  margin-bottom: var(--space-6, 1.5rem);
}
.hero .hero__eyebrow::before {
  content: "";
  width: 40px;
  height: 1px;
  flex-shrink: 0;
  background: linear-gradient(90deg, var(--color-accent, #ffbe01), rgba(255,190,1,0.1));
}

/* Naked subtitle -> the amber gradient left-rule of the homepage answer-block,
   so the suburb hero's answer reads as the same "cited fact" register. Also caps
   the measure so long suburb subtitles set in clean lines (Gate C). */
.hero .hero__subtitle {
  max-width: 52ch;
  padding-left: var(--space-5, 1.25rem);
  border-left: 2px solid transparent;
  border-image: linear-gradient(180deg, var(--color-accent, #ffbe01) 0%, rgba(255,190,1,0.15) 100%) 1;
  overflow-wrap: break-word;   /* long suburb names never push past the measure */
  /* THEME-INDEPENDENT: the hero canvas is always navy (style.css hard-codes it),
     but without an explicit color the subtitle inherits the THEMED body color —
     near-invisible dark-on-navy in light mode. Match the homepage answer-block. */
  color: rgba(255,255,255,0.9);
}
.hero .hero__subtitle strong { color: #fff; }

/* ── Mobile hero overflow fix (ALL .hero pages — homepage + 32 suburbs) ──
   PRE-EXISTING sitewide bug, exposed by the Gate C mobile eye-check: the mobile
   `.hero__content` rule in style.css sets max-width:100% + padding but does NOT
   reset the desktop asymmetric `padding-inline` (left ~0.5rem / RIGHT only 1rem).
   Because `.hero` is `overflow:hidden`, every hero's answer/subtitle, fact-rules
   and — critically — the money CTA ran UNDER the right edge and got clipped
   (homepage answer-block, suburb subtitle, the "0402…"/"Book" buttons). This is
   a conversion defect on the primary CTA at the buyer's most common device.
   Fix is pure-visual (no DOM/text): a comfortable symmetric gutter + hold every
   hero child to the content measure so nothing can exceed the column. Scoped to
   ≤600px; desktop composition (the text-left / photo-right split) is untouched.
   style.css can't be edited, so this override lands in the post-load layer. */
@media (max-width: 600px) {
  .hero .hero__content {
    /* symmetric, generous gutter replacing the clipped 1rem right pad */
    padding-inline: var(--space-5, 1.25rem);
  }
  /* no hero child may set a measure wider than the (now full-width) column */
  .hero .hero__content > * { max-width: 100%; }
  .hero .answer-block,
  .hero .hero__subtitle,
  .hero .hero__facts { max-width: 100%; }
  .hero .hero__ctas { width: 100%; }

  /* The long suburb eyebrow ("POOL SAFETY INSPECTIONS · <SUBURB>") can't shrink
     as a fixed-hairline inline-flex with wide tracking. Let it wrap under the
     hairline and ease the tracking so it sets cleanly within the viewport. */
  .hero .hero__eyebrow {
    flex-wrap: wrap;
    letter-spacing: 0.14em;
    gap: var(--space-3, 0.75rem);
    row-gap: var(--space-2, 0.5rem);
  }
}

/* ---- Global reduced-motion guard: kill all of the above motion ---- */
@media (prefers-reduced-motion: reduce) {
  .lpi-card, .lpi-service-card, .lpi-step, .lpi-cta, .lpi-feature, .pages-card,
  .theme-toggle, .btn, a.btn, .header__nav a {
    transition: none !important;
  }
  .lpi-card:hover, .lpi-service-card:hover, .lpi-feature:hover, .pages-card:hover {
    transform: none !important;
  }
  .pages-reveal, .lpi-section > .lpi-card, .lpi-steps > .lpi-step {
    animation: none !important; opacity: 1 !important; transform: none !important;
  }
  ::view-transition-group(*),
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none !important; }
}

/* ---- Hero inline links: conversion-critical contrast fix (2026-07-02 pass 1.1) ----
   The suburb hero subtitle carries an inline tel: link that inherited the default
   link blue — near-invisible on the navy hero canvas (33x pages). Set it to the
   accent register with a hairline underline; keep the hover affordance quiet.
   Applies to any anchor inside a hero subtitle/intro, both themes. */
.hero .hero__subtitle a,
.hero p a {
  color: var(--color-accent, #ffbe01);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--color-accent, #ffbe01) 55%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color 200ms ease;
}
.hero .hero__subtitle a:hover,
.hero p a:hover {
  text-decoration-color: var(--color-accent, #ffbe01);
}
/* No light-theme override: .hero's navy substrate is theme-independent
   (style.css hard-codes it), so the accent gold holds contrast in both themes. */

/* ---- Links on permanently-navy surfaces (2026-07-02 pass 1.1) ----
   .lpi-trust-strip keeps its #041d3d navy card in BOTH themes, but in light theme
   the generic `.lpi__post-body a` rule (primary blue) out-specifies
   `.lpi-trust-strip__verify` — the VBA verify link went near-invisible on navy.
   Re-assert the accent register at matching specificity; file loads last so it wins. */
.lpi__post-body .lpi-trust-strip a,
.lpi-trust-strip a.lpi-trust-strip__verify,
.lpi-trust-strip a {
  color: var(--color-accent, #ffbe01);
}

/* ---- Homepage "pool inspector near me" banner: centre-aligned (owner request 2026-07-03) ---- */
.region-statewide {
  justify-content: center;
  text-align: center;
}
.region-statewide .area-tag {
  justify-content: center;   /* keep the pin icon + heading centred as one unit */
}
.region-statewide p {
  max-width: 75ch;           /* centred long line still reads as a composed measure */
  margin-inline: auto;
}

/* ---- Facts strip carried site-wide (owner-approved 2026-07-03) ----
   In the navy heroes/bands the homepage styling applies as-is. areas.html embeds
   the strip directly in the THEMED article body (no navy band on that page), so
   re-express the white-on-navy tokens in themed colors there. Direct-child scope
   only — band-nested strips (deeper in .hero-section) must keep hero styling. */
.lpi__post-body > .hero__facts .hero__fact dt { color: var(--color-text-faint); }
.lpi__post-body > .hero__facts .hero__fact dd { color: var(--color-text-muted); }
.lpi__post-body > .hero__facts .hero__fact { border-bottom-color: var(--color-divider); }
.lpi__post-body > .hero__facts + .hero__proof span,
.lpi__post-body > .hero__proof span { color: var(--color-text-muted); }

/* Band-hero strips: cap the measure so the dl doesn't stretch the full band width */
.hero-section .hero__facts, .lpi__post-header .hero__facts { max-width: 60ch; }

/* ============================================================================
   SEAMLESSNESS PASS — homepage→inner-page continuity (2026-07-03, premium-polish)
   CSS-only. Every rule below fixes a rhythm/register break the facts-strip
   carry exposed, so the strip reads as ONE design system across all page types.
   ============================================================================ */

/* (1) SUBURB DOSSIER HEROES (33 pages) — rhythm parity with the homepage.
   The homepage separates the strip from the copy above it via the answer-block's
   `margin-bottom: var(--space-10)`. The suburb `.hero__subtitle` shipped with NO
   bottom margin, so the facts strip crowded the subtitle. Restore the same gap so
   the H1→subtitle→facts→ctas→proof rhythm matches index.html exactly. */
.hero .hero__subtitle { margin-bottom: var(--space-10); }

/* (2) BAND-HERO CONTENT PAGES (7 — services, about, faq, contact, form-23,
   re-inspections, non-conformance). The band intro `<p>` has only a top margin
   (`margin: var(--space-5) 0 0`), so it butted straight against the facts strip.
   Give the strip breathing room from the intro to match the homepage gap. */
.hero-section .hero__facts { margin-top: var(--space-8); }

/* (3) areas.html — the strip sits directly under the H1 with no separation
   (the H1 carries no bottom margin into a direct-child dl). Add a top gap so the
   H1→facts→proof→intro sequence breathes like the homepage's H1→answer→facts. */
.lpi__post-body > .hero__facts { margin-top: var(--space-6); }
.lpi__post-body > .hero__facts + .hero__proof { margin-top: var(--space-5); }

/* (4)+(5) REMOVED 2026-07-03: the strip on compliance-consultation +
   pool-inspection-for-property-sale was mis-placed in the fixed chrome .header by
   the carry script, and .lpi__post-header was missing its </header> (a conversion
   defect — the LIVE pages close it after the H1). Both pages' MARKUP is now
   repaired to match live structure (strip inside the navy post-header band, body
   back on the themed surface), so the fixed-header workaround and the
   white-on-navy body forcing became dead rules and were deleted. */

/* ---- FULL-BLEED HERO ON CONTENT PAGES (owner request 2026-07-03) ----
   The 10 content pages now open with the same section.hero.hero--dossier as the
   homepage/suburbs (was: a rounded navy card inside the article column — the
   "clunky" transition). Supporting rules: */
/* the shell's big padding-top existed to clear the fixed header on heroless
   pages; after the hero it's just section spacing — bring it down to rhythm */
.hero ~ .lpi__shell { padding-top: var(--space-10, 2.5rem); }

/* ---- ABOUT PAGE: lead figure was starved by the narrow article measure ----
   (owner: "image strangely small"). Break the about-lead grid out to a wider
   measure so the prose keeps ~55ch AND the figure gets real presence. */
.lpi-about-lead {
  width: min(1060px, calc(100vw - 3rem));
  margin-left: 50%;
  transform: translateX(-50%);
}
/* caption register: the unclassed figcaption rendered at full body size (18px
   default) — set the site's small muted caption register (matches .lpi-figure) */
.lpi-about-lead figcaption {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  margin-top: var(--space-3);
  line-height: 1.55;
}

/* ---- .skip-link (content-page template) had NO rule anywhere — it rendered as
   a raw in-flow blue link at the top of the page (exposed by the full-bleed hero
   conversion; previously masked by the old layout). Standard accessible pattern:
   hidden above the viewport, slides in on keyboard focus — matching the suburb
   pages' inline-styled skip link exactly. */
.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  padding: 1rem;
  background: var(--color-primary);
  color: #fff;
  z-index: 999;
  transform: translateY(-100%);
  transition: transform 0.2s;
}
.skip-link:focus { transform: translateY(0); }

/* ============================================================================
   CARD SECTIONS — measure breakout + homepage register (owner round 2026-07-03)
   ----------------------------------------------------------------------------
   Owner: "the card sections are squished and don't look very appealing —
   services, why us and about are all the same." Root cause: these grids live
   inside .lpi__post-body { max-width:820px }, and their auto-fit minmax(220px)
   tracks pack 4–5 cards into a ~772px column → three thin centred-text columns.
   The homepage runs the SAME components (.why-card, .service-card) in a wide
   .container with 64px gold icon chips. The fix is to bring the content pages
   UP TO that register: break the card BANDS out to a wide measure (the
   .lpi-about-lead translateX(-50%) precedent) and restore the icon chip + a
   comfortable column floor. Pure visual — no rankable-DOM/text/schema change.
   ============================================================================ */

/* -- 1. Break the card-carrying section bands out of the 820px article measure.
      Scope to sections that actually contain a card grid via :has() so prose
      sections keep their reading measure. The band (not just the grid) breaks
      out, so its background + heading stay aligned above the wider card row —
      exactly how the homepage sets these components. -- */
.lpi__post-body > .section:has(.lpi-why-grid),
.lpi__post-body > .section:has(.services-grid),
.lpi__post-body > .section:has(.process-steps),
.lpi__post-body > .section:has(> .container > .features-grid) {
  width: min(1100px, calc(100vw - 3rem));
  margin-left: 50%;
  transform: translateX(-50%);
}
/* Fallback for engines without :has() — break the grids themselves out. Same
   target width; the heading stays at article measure (still reads intentional:
   a centred lead over a wider card row). :has() is Baseline 2024, so this only
   serves legacy renderers. */
@supports not (selector(:has(*))) {
  .lpi__post-body .lpi-why-grid,
  .lpi__post-body .services-grid,
  .lpi__post-body .process-steps,
  .lpi__post-body .features-grid {
    width: min(1100px, calc(100vw - 3rem));
    margin-left: 50%;
    transform: translateX(-50%);
  }
}

/* -- 2. Column floors: with real width available, give each grid comfortable
      tracks so cards breathe instead of squishing. Match the homepage cadence
      (why = up to 3-up, services = 2-up, features/faq = 2-up). -- */
.lpi__post-body .lpi-why-grid {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-6);
  margin-top: var(--space-8);
}
.lpi__post-body .services-grid {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
.lpi__post-body .process-steps {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* -- 3. Icon chip on content why-cards — the homepage's 64px gold-gradient chip
      (style.css .why-card__icon). The bare content variant shipped without it;
      the decorative aria-hidden SVG chips are added to the HTML. Left-align the
      card content to match the icon-led editorial read (homepage centres, but
      left-anchored reads more considered at this measure and echoes the dossier
      hero). -- */
.lpi__post-body .why-card {
  text-align: left;
  padding: var(--space-7) var(--space-6);
}
.lpi__post-body .why-card__icon {
  width: 56px;
  height: 56px;
  margin: 0 0 var(--space-5);
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-hover));
  border-radius: var(--radius-lg);
  color: #fff;
  flex-shrink: 0;
}
[data-theme="dark"] .lpi__post-body .why-card__icon {
  background: linear-gradient(135deg, var(--color-accent), var(--color-accent-hover));
  color: #0d1b2a;
}
.lpi__post-body .why-card__icon svg {
  width: 26px;
  height: 26px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
}
.lpi__post-body .why-card h3 {
  margin-top: 0;
  margin-bottom: var(--space-3);
}

/* -- 4. CTA band buttons — retire the flat white pills. Owner: "the white
      buttons look horrible." Adopt the homepage hero CTA pair register: the
      FIRST action is the gold primary (accent bg, dark text), the SECOND a
      quiet outline (transparent, white border/text, hover fills navy). Where a
      page has a single CTA it reads as the gold primary. CSS-only via the
      cta-section paragraph; button text + hrefs untouched. -- */
.cta-section p .btn-white {
  border: 2px solid transparent;
}
.cta-section p .btn-white:first-child,
.cta-section p .btn-white:only-child {
  background: var(--color-accent);
  color: #0d1b2a;
}
.cta-section p .btn-white:first-child:hover,
.cta-section p .btn-white:only-child:hover {
  background: var(--color-accent-hover);
  color: #0d1b2a;
}
.cta-section p .btn-white:last-child:not(:only-child) {
  background: transparent;
  color: #fff;
  border-color: rgba(255,255,255,0.4);
}
.cta-section p .btn-white:last-child:not(:only-child):hover {
  background:
    radial-gradient(140% 180% at 82% 12%, #0a3d7a 0%, transparent 60%),
    linear-gradient(165deg, #062b58 0%, #041d3d 60%, #02152d 100%);
  border-color: rgba(255,255,255,0.65);
  color: #fff;
}

/* -- 5. Gold-on-gold invisible label fix. `[data-theme="dark"] .lpi__post-body a`
      (pages.css) tints every in-body link amber, which beats .btn-primary's own
      dark-text rule by specificity → the gold .btn-primary rendered gold text on
      a gold fill (label "Book Re-Inspection" invisible on the NCR/re-inspection
      cards in dark mode). Restore the dark ink the button was designed for, in
      BOTH themes, at a specificity that wins. Purely a color correction. -- */
.lpi__post-body a.btn-primary,
[data-theme="dark"] .lpi__post-body a.btn-primary {
  color: #0d1b2a;
}

/* ---- Why-card breathing room (owner 2026-07-03: "font and icons too close to
   the boundary of the cards"). Generous, homepage-register padding + internal
   rhythm; wins over both the pages.css space-6 and style.css space-8 variants. */
.why-card,
.lpi__post-body .why-card {
  padding: var(--space-9, 2.75rem) var(--space-8, 2.5rem);
}
.why-card .why-card__icon { margin-bottom: var(--space-5, 1.25rem); }
.why-card h3 { margin-bottom: var(--space-3, 0.75rem); }
.why-card p  { line-height: 1.65; }
@media (max-width: 600px) {
  .why-card,
  .lpi__post-body .why-card { padding: var(--space-7, 2rem) var(--space-6, 1.5rem); }
}

/* ---- Service cards (services.html): same icon-chip register + breathing room
   as the why-cards (owner 2026-07-03: "similar feel to the why us page"). ---- */
.service-card {
  padding: var(--space-9, 2.75rem) var(--space-8, 2.5rem);
}
.service-card .why-card__icon { margin-bottom: var(--space-5, 1.25rem); }
.service-card h2 {
  font-size: var(--text-lg);
  margin-bottom: var(--space-3, 0.75rem);
}
.service-card p { line-height: 1.65; }
@media (max-width: 600px) {
  .service-card { padding: var(--space-7, 2rem) var(--space-6, 1.5rem); }
}

/* ---- ABOUT PAGE centre-alignment (owner 2026-07-03) ----
   (1) "Our Service Areas" section — heading, intro, tag cloud, link line, and the
   figure+caption all centre. .areas__tags is unique to about.html, so :has() on
   the section is a safe page-scoped hook (pages.css's flex default is left there).
   (2) "Why Local Pool Inspections" section heading centres; cards stay as-is. */
.section:has(.areas__tags) .container { text-align: center; }
.section:has(.areas__tags) .areas__tags { justify-content: center; }
.section:has(.areas__tags) figure { margin-inline: auto; }
.section:has(.areas__tags) figure img { margin-inline: auto; display: block; }
#why-us > .container > h2 { text-align: center; }

/* ============================================================================
   AREAS PAGE — region text + stylised map, 2-up (owner round 2026-07-03)
   ----------------------------------------------------------------------------
   Owner: "make each image a map of the greater area." Each of the 5 region
   blocks (H2 + suburb list) pairs with a bespoke external SVG dossier-map on the
   right. The region wrapper breaks out of the 820px article measure (the
   .lpi-about-lead translateX(-50%) precedent) so the list keeps a comfortable
   measure AND the map gets real presence. Maps are external <img> (their SVG
   <text> never enters the page's visible-text hash). Wrapper markup only — zero
   wording change. Mobile stacks the map below the list.
   ============================================================================ */
.lpi-region {
  width: min(1080px, calc(100vw - 3rem));
  margin-left: 50%;
  transform: translateX(-50%);
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: var(--space-8) var(--space-10);
  align-items: start;
  margin-top: var(--space-4);
  margin-bottom: var(--space-6);
}
/* the H2 inside the wrapper keeps its rhythm but shouldn't carry the big top
   margin now that the wrapper spaces the sections */
.lpi-region__text > h2:first-child { margin-top: var(--space-6); }
.lpi-region__text ul { margin-bottom: 0; }

/* map figure — a card in the site's own language: rounded, hairline-framed,
   sits beside the list. aspect-ratio holds the box so lazy-load = zero CLS. */
.lpi-region__map {
  margin: var(--space-10) 0 0;
  position: sticky;
  top: var(--space-16, 4rem);
}
.lpi-region__map img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 460 / 380;
  border-radius: var(--radius-xl);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
}

/* Stack on narrow viewports — map drops BELOW its region's list. Full-width map
   in the stacked flow (still inside the broken-out wrapper measure). */
@media (max-width: 700px) {
  .lpi-region {
    grid-template-columns: 1fr;
    gap: var(--space-5);
  }
  .lpi-region__map {
    position: static;
    margin-top: var(--space-2);
    max-width: 460px;
  }
}

/* ---- Areas page: suburb links keep the body text colour (owner 2026-07-03:
   "they can stay underlined... i just dont want them yellow"). Wins over the
   dark-theme .lpi__post-body a accent rule via higher specificity + later load.
   Hover affordance = thicker underline, no colour shift. ---- */
.lpi__post-body.lpi__post-body--areas ul a,
[data-theme="dark"] .lpi__post-body.lpi__post-body--areas ul a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.lpi__post-body.lpi__post-body--areas ul a:hover {
  text-decoration-thickness: 2px;
}

/* ---- Gold headline accents on menu pages (owner 2026-07-03: match the
   homepage "Geelong & Victoria" treatment). H1 spans reuse the homepage
   .hero h1 .hero__accent rule (display:block gold + glow). The why-us H2
   variant stays inline mid-sentence. ---- */
.hero__accent--inline,
h2 .hero__accent--inline {
  display: inline;
  color: var(--color-accent, #ffbe01);
  font-weight: 800;
  text-shadow: 0 0 40px rgba(255,190,1,0.30);
}
