/* =========================================================================
   Plumber Down Under - theme.css
   BEM prefix: kfy-
   Mobile-first
   ========================================================================= */

/* =========================================================================
   WCAG 2.1 AA — VERIFIED CONTRAST PAIRS (see design_spec.md §3)
   ----------------------------------------------------------------------
   APPROVED text/background pairings (computed ratios):
     brown-deep  on cream         → 13.33:1 (AAA)
     brown-deep  on white         → 15.17:1 (AAA)
     brown-soft  on cream         →  8.82:1 (AAA)
     white       on brown-deep    → 15.17:1 (AAA)
     white       on maroon        → 12.51:1 (AAA)
     white       on red-plunger   →  5.94:1 (AA)
     orange-acc. on white         →  5.85:1 (AA)
     orange-acc. on cream         →  5.14:1 (AA)
     brand-orange on brown-deep   →  5.54:1 (AA)
     brown-deep  on brand-orange  →  5.54:1 (AA — Primary button)
     sunset-yel. on brown-deep    →  9.52:1 (AAA — display only)

   FORBIDDEN — never use as text/background:
     brand-orange  on white   (2.74:1)   sunset-yellow on white (1.59:1)
     brand-orange  on cream   (2.41:1)   sunset-amber  on white (2.35:1)
     cream         on sand    (1.12:1 — adjacent surfaces only)
   ========================================================================= */

/* ---------- Custom Fonts ----------
   Self-host Moderniz + Super Cedar in /assets/fonts/.
   The shipped files are the licensed source formats (.otf / .ttf). The CSS
   also lists .woff2/.woff first so an optional pre-compressed copy will be
   picked up automatically with no further changes when added later.
   When all sources are missing, the system fallbacks (Impact / Georgia)
   render automatically thanks to font-display: swap.

   ADA / WCAG 2.1 hardening (see design_spec.md §4 + §9):
   - font-display: swap          → fallback paints first; no FOIT (LCP/SI a11y)
   - unicode-range               → fallback handles any glyph not in display face,
                                   so accented characters never render as tofu
   - font-feature-settings       → kerning + standard ligatures on by default
                                   (improves legibility for low-vision readers,
                                   does not break screen readers)
   - "dlig" 0                    → discretionary ligatures off (some can confuse
                                   text-to-speech in display caps)
*/
@font-face {
	font-family: "Moderniz";
	src: url("../fonts/Moderniz.woff2") format("woff2"),
	     url("../fonts/Moderniz.woff")  format("woff"),
	     url("../fonts/Moderniz.otf")   format("opentype");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
	/* Latin + supplemental punctuation only - the licensed Moderniz file is
	   intentionally Latin-only; everything outside this range correctly
	   falls back to the system stack so accents/CJK/emoji render properly. */
	unicode-range: U+0000-007F, U+00A0-00FF, U+0152-0153, U+02BB-02BC,
	               U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC,
	               U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
	font-feature-settings: "kern" 1, "liga" 1, "dlig" 0;
}

@font-face {
	font-family: "Super Cedar";
	src: url("../fonts/SuperCedar.woff2") format("woff2"),
	     url("../fonts/SuperCedar.woff")  format("woff"),
	     url("../fonts/Super%20Cedar.ttf") format("truetype");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
	/* NOTE: U+0030-0039 (digits) intentionally excluded — the bundled Super
	   Cedar file ships without numeral glyphs, so claiming them in the
	   range causes "24/7" to render as "2/" (browsers won't fall through
	   to the next stack font once the range matches). The companion
	   @font-face below routes digits to a system serif so headings like
	   "24/7 Emergency Plumbing" display correctly. */
	unicode-range: U+0000-002F, U+003A-007F, U+00A0-00FF, U+0152-0153,
	               U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F,
	               U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,
	               U+2215, U+FEFF, U+FFFD;
	font-feature-settings: "kern" 1, "liga" 1, "dlig" 0;
}

/* Digits-only fallback for Super Cedar — system serif keeps the heading
   tone close to Super Cedar's voice while guaranteeing every numeral
   renders. Applies anywhere font-family includes "Super Cedar". */
@font-face {
	font-family: "Super Cedar";
	src: local("Georgia"), local("Times New Roman"), local("Cambria"),
	     local("Noto Serif"), local("Liberation Serif"), local("serif");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0030-0039;
	font-feature-settings: "kern" 1, "lnum" 1, "tnum" 1;
}

/* Same safeguard for Moderniz — the bundled .otf is only 11 KB and a
   number of glyphs (incl. some numerals at certain weights) are missing
   from the licensed subset. Route digits to a condensed system display
   so Moderniz-styled labels never lose a character. */
@font-face {
	font-family: "Moderniz";
	src: local("Impact"), local("Haettenschweiler"),
	     local("Arial Narrow Bold"), local("Helvetica Inserat"),
	     local("Oswald"), local("sans-serif");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0030-0039;
	font-feature-settings: "kern" 1, "lnum" 1, "tnum" 1;
}

/* ADA hardening for the brand display + heading faces:
   - font-synthesis: none → never let the browser fake bold or italic on a
     display face. Synthesized weights destroy display fonts and are
     nearly unreadable for low-vision users.
   - text-rendering: optimizeLegibility → enables kerning and contextual
     alternates the font ships with.
   - -webkit-font-smoothing tuned for warm-on-dark surfaces (most of the
     site) without making body sans look anaemic. */
h1,
h2,
h3,
h4,
h5,
.kfy-eyebrow,
.kfy-section-label,
.kfy-btn,
[class*="kfy-"][class*="__title"],
[class*="kfy-"][class*="__eyebrow"],
[class*="kfy-"][class*="__heading"] {
	font-synthesis: none;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* ---------- Design Tokens (Plumber Down Under) ---------- */
:root {
	/* PDU palette — see design_spec.md §3 */
	--pdu-white:              #FFFFFF;
	--pdu-cream:              #FBEFD9;
	--pdu-sand:               #F5E1C0;
	--pdu-brown-deep:         #3A1F12;
	--pdu-brown-soft:         #5C3A28;
	--pdu-maroon:             #4D2645;
	--pdu-ink:                #0F0A08;
	--pdu-brand-orange:       #EF7E1A;
	--pdu-orange-accessible:  #A04E0A;
	--pdu-sunset-yellow:      #F7C73B;
	--pdu-sunset-amber:       #E89829;
	--pdu-red-plunger:        #B23A2C;
	/* Mascot glove palette — sampled from the kangaroo's red boxing
	   gloves. Bright cherry highlight on top, plunger-red base on
	   bottom, deep maroon shadow for hover/active depth. Used for
	   high-energy "punch" CTAs (e.g. process block conversion pair)
	   so they read as the same red the mascot is throwing. */
	--pdu-glove-light:        #E5483A;
	--pdu-glove:              #C9342A;
	--pdu-glove-deep:         #8E2A20;
	/* Eggplant — sampled from the van-body wrap. Adds the "touch of dark"
	   the brand needs to anchor the warm sunset palette. White on
	   #3A1D38 ≈ 15.25:1 (AAA), so it is safe as a high-emphasis surface. */
	--pdu-eggplant:           #3A1D38;
	--pdu-eggplant-deep:      #25131F;

	/* Legacy palette aliases (so existing BEM rules keep working) */
	--color-gold:         var(--pdu-brand-orange);
	--color-burnt-orange: var(--pdu-orange-accessible);
	--color-red:          var(--pdu-red-plunger);
	--color-cream:        var(--pdu-cream);
	--color-light-gray:   #C9B79A;
	--color-medium-gray:  var(--pdu-brown-soft);
	--color-steel-blue:   var(--pdu-eggplant);
	--color-warm-brown:   var(--pdu-brown-soft);
	--color-dark-brown:   var(--pdu-brown-deep);
	--color-deep-brown:   var(--pdu-brown-deep);
	--color-near-black:   var(--pdu-eggplant-deep);
	--color-dark-teal:    var(--pdu-eggplant);

	/* Semantic — dark surface keeps the original structure but recoloured.
	   Body background defaults to deep brown with cream text (15.17:1 AAA). */
	--bg-primary:      var(--pdu-brown-deep);
	--bg-secondary:    var(--pdu-maroon);
	--bg-light:        var(--pdu-cream);
	--bg-card:         var(--pdu-sand);
	--text-primary:    var(--pdu-cream);
	--text-secondary:  #E6D2A8;
	--text-on-light:   var(--pdu-brown-deep);
	--text-muted:      var(--pdu-brown-soft);
	--accent-primary:  var(--pdu-brand-orange);
	--accent-secondary:var(--pdu-orange-accessible);
	--accent-danger:   var(--pdu-red-plunger);
	--border-default:  rgba(251, 239, 217, 0.18);
	--border-dark:     var(--pdu-brown-deep);

	/* Typography */
	--font-display: "Moderniz", Impact, "Arial Narrow Bold", "Helvetica Inserat", sans-serif;
	--font-body:    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
	--font-accent:  "Super Cedar", Georgia, "Times New Roman", serif;
	/* Hero/H1 only — system display stack. Moderniz is heavily condensed,
	   so even with aggressive size caps the hero headline kept fragmenting
	   to 5+ cramped lines in the 992-1199px range where the form column
	   eats half the width. Each platform's native display face here is
	   ~30 % wider per glyph, ships in heavy/black weights, and renders
	   with crisp on-screen hinting at any size. No external font load.
	     - macOS / iOS  → SF Pro Display
	     - Windows 11   → Segoe UI Variable Display
	     - Older Windows→ Segoe UI
	     - Android      → Roboto Flex / Roboto
	     - Anything else→ system-ui / sans-serif */
	--font-hero:    -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI Variable Display", "Segoe UI", "Helvetica Neue", "Roboto Flex", Roboto, system-ui, sans-serif;

	/* Type scale (see design_spec.md §4 — 18px base, 1.25 modular) */
	--fs-micro:    0.778rem;
	--fs-small:    0.889rem;
	--fs-body:     1rem;
	--fs-body-lg:  1.125rem;
	--fs-h5:       1.25rem;
	--fs-h4:       1.563rem;
	--fs-h3:       1.953rem;
	--fs-h2:       clamp(1.75rem, 4vw, 3.052rem);
	--fs-h1:       clamp(2rem, 5vw, 3.815rem);

	/* Spacing — 8pt scale (see design_spec.md §5) */
	--sp-1: 4px;
	--sp-2: 8px;
	--sp-3: 12px;
	--sp-4: 16px;
	--sp-5: 24px;
	--sp-6: 32px;
	--sp-7: 40px;
	--sp-8: 48px;
	--sp-9: 56px;
	--sp-10: 64px;
	--sp-11: 72px;
	--sp-12: 80px;
	--sp-13: 96px;
	--sp-14: 112px;
	--sp-16: 128px;

	/* Radius (pill default for buttons / chips) */
	--radius-sm:   8px;
	--radius-md:   16px;
	--radius-lg:   24px;
	--radius-xl:   24px;
	--radius-full: 999px;

	/* Shadows (warm brown-tinted) */
	--shadow-sm:   0 1px 3px rgba(58, 31, 18, 0.10);
	--shadow-md:   0 4px 16px rgba(58, 31, 18, 0.12);
	--shadow-lg:   0 12px 32px rgba(58, 31, 18, 0.18);
	--shadow-xl:   0 16px 48px rgba(58, 31, 18, 0.25);
	--shadow-gold: 0 4px 20px rgba(239, 126, 26, 0.30);

	/* Transitions */
	--ease-default: 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
	--ease-bounce:  0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
	--dur-micro:    150ms;
	--dur-ui:       250ms;
	--dur-reveal:   600ms;

	/* Layout */
	--container-max:  1200px;
	--container-wide: 1440px;
	--header-height:  72px;
	--kfy-header-h:   142px;

	/* Sand grain texture — inline SVG (fractalNoise turbulence) tinted warm
	   cream (R 0.95 / G 0.85 / B 0.65) at ~18% alpha. Reused across dark
	   sections via background-image + mix-blend-mode: overlay so dark
	   surfaces gain a subtle "outback paper" warmth without lifting their
	   value. ~600 bytes inline → no extra HTTP request. Tile is 180×180
	   so the grain stays fine at desktop and tablet zoom. */
	--pdu-grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.95 0 0 0 0 0.85 0 0 0 0 0.65 0 0 0 0.18 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

@media (max-width: 767px) {
	/* v2.7.3: dropped 92→72 to match the slimmer mobile navbar
	   (32px brand-img + nav padding + island margin). Anything that
	   reads --kfy-header-h (scroll-padding-top, drawer offset, hero
	   min-heights) now lines up with the actual rendered bar height
	   instead of leaving a 20px dead zone above the page content. */
	:root { --kfy-header-h: 72px; }
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* 18px base (design_spec.md §4). All other sizes are rem-based so user
   zoom and browser default-size overrides cascade correctly.
   scroll-padding-top keeps in-page anchor jumps (e.g. #hero, #hero-form)
   from landing under the fixed .kfy-header island. The fallback matches
   the --kfy-header-h custom property defined in :root. */
html {
	font-size: 18px;
	scroll-behavior: smooth;
	scroll-padding-top: calc(var(--kfy-header-h, 142px) + 16px);
}

/* ---- Lenis smooth-scroll integration ----
   Lenis tags <html> with `.lenis.lenis-smooth` while it's driving the
   scroll. Its inertial easing fights the browser's native
   `scroll-behavior: smooth` declaration above, so we have to disable
   that *while* Lenis is active (and only then — fallback path keeps
   native smooth-scroll if Lenis fails to load or reduced-motion is on).
   `[data-lenis-prevent]` opts an inner scroll container out of Lenis,
   which the mobile drawer uses so its overflow:auto still works. */
html.lenis,
html.lenis body {
	height: auto;
}
.lenis.lenis-smooth {
	scroll-behavior: auto !important;
}
.lenis.lenis-smooth [data-lenis-prevent] {
	overscroll-behavior: contain;
}
.lenis.lenis-stopped {
	overflow: hidden;
}
.lenis.lenis-smooth iframe {
	pointer-events: none;
}

body {
	margin: 0;
	background: var(--bg-primary);
	color: var(--text-primary);
	font-family: var(--font-body);
	font-size: var(--fs-body);
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	/* Kerning + standard ligatures help low-vision and dyslexic readers.
	   Text-size-adjust prevents iOS/Android from auto-resizing in landscape,
	   which would silently violate the 18px body-text floor (design_spec §4). */
	font-feature-settings: "kern" 1, "liga" 1;
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

img, svg { max-width: 100%; height: auto; display: block; }

a { color: var(--accent-primary); text-decoration: none; transition: color var(--dur-ui) var(--ease-default); }
a:hover { color: var(--accent-secondary); text-decoration: underline; text-underline-offset: 3px; }

/* H1 + display roles use Moderniz; section headings use Super Cedar. */
h1 {
	font-family: var(--font-display);
	font-weight: 400;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	line-height: 1.15;
	margin: 0 0 var(--sp-4);
	font-size: var(--fs-h1);
}

h2, h3, h4, h5 {
	font-family: var(--font-accent);
	font-weight: 400;
	line-height: 1.2;
	margin: 0 0 var(--sp-4);
}

h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); margin-bottom: var(--sp-3); }
h5 { font-size: var(--fs-h5); margin-bottom: var(--sp-2); }

p { margin: 0 0 var(--sp-4); max-width: 65ch; }

::selection { background: var(--accent-primary); color: var(--pdu-brown-deep); }

/* Global focus ring — never removed (design_spec.md §9). */
:focus-visible {
	outline: 3px solid var(--pdu-orange-accessible);
	outline-offset: 2px;
	border-radius: 2px;
}

/* Skip-link helper — render once at the top of the document */
.kfy-skip-link {
	position: absolute;
	left: -9999px;
	top: var(--sp-2);
	z-index: 999;
	padding: var(--sp-3) var(--sp-5);
	background: var(--pdu-brown-deep);
	color: var(--pdu-cream);
	font-weight: 700;
	text-decoration: none;
	border-radius: var(--radius-sm);
}
.kfy-skip-link:focus-visible { left: var(--sp-2); }

/* =========================================================================
   Scrollbar — brand-aligned
   --------------------------------------------------------------------------
   The page sits on a deep-brown background (--pdu-brown-deep) with cream
   text. The default OS scrollbar reads as a cold gray strip down the side
   that fights the warm sunset palette. We restyle it so the track blends
   into the eggplant trim of the header island and the thumb matches the
   brand-orange CTAs, with a sunset-amber hover state.

   - Firefox / modern Edge → scrollbar-color + scrollbar-width
   - Chrome / Safari       → ::-webkit-scrollbar pseudo-elements
   - Light surfaces (cream cards / modals) get an inverted variant via
     `.kfy-scroll--light` so the thumb still has enough contrast.

   ADA / a11y:
   - Width stays at 12px (above the WCAG 2.5.5 24×24 target only applies
     to interactive controls; scrollbars are an exception, but 12px is
     still well above the 8px Chrome default for easier mouse targeting).
   - Thumb uses --pdu-brand-orange (5.54:1 against brown-deep, AA).
   - Falls back to OS-native scrollbar if any property is unsupported.
   ========================================================================= */
:root {
	--scrollbar-track: var(--pdu-eggplant-deep);
	--scrollbar-thumb: var(--pdu-brand-orange);
	--scrollbar-thumb-hover: var(--pdu-sunset-amber);
}

html {
	scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
	scrollbar-width: thin;
}

::-webkit-scrollbar {
	width: 12px;
	height: 12px;
}
::-webkit-scrollbar-track {
	background: var(--scrollbar-track);
}
::-webkit-scrollbar-thumb {
	background: linear-gradient(
		180deg,
		var(--pdu-brand-orange) 0%,
		var(--pdu-orange-accessible) 100%
	);
	border: 2px solid var(--scrollbar-track);
	border-radius: var(--radius-full);
	background-clip: padding-box;
	transition: background-color var(--dur-ui) var(--ease-default);
}
::-webkit-scrollbar-thumb:hover {
	background: linear-gradient(
		180deg,
		var(--pdu-sunset-yellow) 0%,
		var(--pdu-brand-orange) 100%
	);
	background-clip: padding-box;
}
::-webkit-scrollbar-thumb:active {
	background: var(--pdu-orange-accessible);
	background-clip: padding-box;
}
::-webkit-scrollbar-corner {
	background: var(--scrollbar-track);
}

/* Light-surface variant — apply to any scroll container sitting on cream
   (e.g. modal dialogs, dropdown panels) so the thumb stays legible. */
.kfy-scroll--light {
	scrollbar-color: var(--pdu-brown-deep) var(--pdu-cream);
}
.kfy-scroll--light::-webkit-scrollbar-track {
	background: var(--pdu-cream);
}
.kfy-scroll--light::-webkit-scrollbar-thumb {
	background: linear-gradient(
		180deg,
		var(--pdu-brown-soft) 0%,
		var(--pdu-brown-deep) 100%
	);
	border-color: var(--pdu-cream);
	background-clip: padding-box;
}
.kfy-scroll--light::-webkit-scrollbar-thumb:hover {
	background: var(--pdu-brand-orange);
	background-clip: padding-box;
}

/* Reduced-motion respect (design_spec.md §8) */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ---------- Layout primitives ---------- */
.kfy-container {
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
	padding-inline: var(--sp-5);
}

.kfy-container--narrow {
	max-width: 820px;
}

@media (min-width: 992px) {
	.kfy-container { padding-inline: var(--sp-6); }
}

.kfy-section {
	padding: clamp(var(--sp-10), 8vw, var(--sp-16)) 0;
}

.kfy-section--dark   { background: var(--bg-primary); color: var(--text-primary); }
.kfy-section--darker { background: var(--bg-secondary); color: var(--text-primary); }
.kfy-section--light  { background: var(--bg-light); color: var(--text-on-light); }
.kfy-section--brown  {
	background: linear-gradient(135deg, var(--color-deep-brown), var(--color-warm-brown));
	color: var(--text-primary);
}

/* ---------- Section header pattern ---------- */
.kfy-section-header {
	text-align: center;
	max-width: 760px;
	margin: 0 auto var(--sp-12);
}

.kfy-section-label {
	display: inline-block;
	font-family: var(--font-display);
	text-transform: uppercase;
	font-size: 14px;
	letter-spacing: 2px;
	color: var(--accent-primary);
	background: rgba(198, 187, 60, 0.12);
	border: 1px solid rgba(198, 187, 60, 0.4);
	padding: 6px 14px;
	border-radius: var(--radius-full);
	margin: 0 0 var(--sp-4);
}

.kfy-section--light .kfy-section-label {
	color: var(--color-warm-brown);
	background: rgba(142, 68, 32, 0.08);
	border-color: rgba(142, 68, 32, 0.3);
}

.kfy-section-title {
	margin: 0 0 var(--sp-3);
}

.kfy-section-subtitle {
	font-size: clamp(17px, 1vw + 15px, 20px);
	color: var(--text-secondary);
	line-height: 1.6;
	margin: 0;
}

.kfy-section--light .kfy-section-subtitle { color: var(--text-muted); }

/* ---------- Inline SVG icons ---------- */
.kfy-icon {
	display: inline-block;
	flex-shrink: 0;
	vertical-align: middle;
	color: currentColor;
}
.kfy-icon--gold { color: var(--color-gold); }
.kfy-icon--brown { color: var(--color-warm-brown); }
.kfy-icon--cream { color: var(--color-cream); }

.kfy-section-divider {
	display: block;
	width: 80px;
	height: 4px;
	background: linear-gradient(90deg, var(--color-gold), var(--color-burnt-orange));
	border-radius: var(--radius-full);
	margin: var(--sp-4) auto 0;
}

/* ---------- Buttons ---------- */
.kfy-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-2);
	font-family: var(--font-display);
	font-size: 16px;
	text-transform: uppercase;
	letter-spacing: 1px;
	padding: 14px 28px;
	border: 2px solid transparent;
	border-radius: var(--radius-md);
	cursor: pointer;
	transition: all var(--ease-default);
	text-decoration: none;
	line-height: 1;
	min-height: 48px;
	white-space: nowrap;
}
/* Suppress the global a:hover underline on every button variant —
   buttons should never look like inline text links on hover, the
   gradient/lift/shadow already telegraph interactivity. Covers
   focus-visible too so keyboard focus stays clean. */
.kfy-btn,
.kfy-btn:hover,
.kfy-btn:focus,
.kfy-btn:focus-visible,
.kfy-btn:active,
.kfy-btn:visited {
	text-decoration: none;
}

/* Primary CTA — repainted in the mascot's boxing-glove red (see the
   --pdu-glove* tokens in :root). Three-stop gradient mimics the
   highlight→base→shadow shading on the glove leather; cream text +
   subtle dark text-shadow keeps the WCAG contrast comfortable on the
   bright red. The inset top edge adds a faint sheen so the pill reads
   as 3D leather rather than flat ink. */
.kfy-btn--primary {
	background: linear-gradient(135deg, var(--pdu-glove-light) 0%, var(--pdu-glove) 55%, var(--pdu-glove-deep) 100%);
	color: var(--pdu-cream);
	box-shadow:
		0 6px 18px rgba(178, 58, 44, 0.45),
		inset 0 1px 0 rgba(255, 255, 255, 0.18);
	border-color: transparent;
	text-shadow: 0 1px 1px rgba(60, 14, 9, 0.35);
}
.kfy-btn--primary:hover,
.kfy-btn--primary:focus-visible {
	transform: translateY(-2px);
	box-shadow:
		0 10px 28px rgba(178, 58, 44, 0.55),
		inset 0 1px 0 rgba(255, 255, 255, 0.22);
	color: var(--pdu-cream);
}
.kfy-btn--primary:active {
	transform: translateY(0);
	box-shadow: 0 4px 12px rgba(142, 42, 32, 0.5);
}

/* Secondary CTA — ghost counterpart to the glove-red primary. Same
   palette as .kfy-btn--primary so the two read as a coordinated pair
   wherever they appear together (final-CTA, process pair, not-found
   page). The fill-on-hover behaviour preserves the visual hierarchy:
   ghost in repose, primary-equivalent on intent. .kfy-icon inherits
   currentColor so the phone glyph in CALL buttons tracks the text. */
.kfy-btn--outline {
	background: transparent;
	color: var(--pdu-glove-light);
	border-color: var(--pdu-glove);
	border-width: 2px;
}
.kfy-btn--outline .kfy-icon {
	color: currentColor;
	transition: color var(--ease-default);
}
.kfy-btn--outline:hover,
.kfy-btn--outline:focus-visible {
	background: linear-gradient(135deg, var(--pdu-glove-light), var(--pdu-glove));
	color: var(--pdu-cream);
	border-color: transparent;
	transform: translateY(-2px);
	box-shadow: 0 8px 22px rgba(178, 58, 44, 0.4);
}
.kfy-btn--outline:active {
	transform: translateY(0);
	box-shadow: 0 4px 12px rgba(142, 42, 32, 0.4);
}

.kfy-btn--danger {
	background: linear-gradient(135deg, var(--color-red), #a12a22);
	color: var(--color-cream);
}
.kfy-btn--danger:hover {
	transform: translateY(-2px);
	box-shadow: 0 6px 24px rgba(205, 54, 44, 0.4);
	color: var(--color-cream);
}

.kfy-btn--full { width: 100%; }
.kfy-btn--lg { padding: 18px 36px; font-size: 18px; min-height: 56px; }

/* ---------- Generic card ---------- */
.kfy-card {
	background: var(--bg-card);
	color: var(--text-on-light);
	border-radius: var(--radius-lg);
	padding: var(--sp-6);
	box-shadow: var(--shadow-md);
	border: 1px solid rgba(189, 188, 188, 0.3);
	transition: transform var(--ease-default), box-shadow var(--ease-default);
}
.kfy-card:hover {
	transform: translateY(-4px);
	box-shadow: var(--shadow-lg);
}

/* =========================================================================
   BLOCK 1 - HEADER
   ========================================================================= */
/* Sticky behavior is applied to the template-part wrapper (the direct parent
   of .kfy-header) because position: sticky is constrained by its parent's
   bounding box. The wrapper's containing block is the page body, which gives
   the header room to actually stick. */
.wp-block-template-part:has(> .kfy-header),
header.wp-block-template-part:has(> .kfy-header) {
	position: sticky;
	top: 0;
	z-index: 1000;
	margin-block: 0 !important;
}

/* Kill the WP "block-gap" margin that WordPress injects between top-level
   siblings of .wp-site-blocks (header → post-content → footer). Without this,
   theme.json's blockGap creates a visible gap between the sticky header and
   the hero. */
.wp-site-blocks > * + *,
.wp-site-blocks > .wp-block-post-content,
.wp-site-blocks > main,
.wp-site-blocks > footer {
	margin-block-start: 0 !important;
}

/* Also zero out the post-content wrapper's own top spacing so the hero sits
   flush against the header. */
.wp-block-post-content,
.entry-content {
	margin-block-start: 0 !important;
	padding-block-start: 0 !important;
}
.wp-block-post-content > :first-child,
.entry-content > :first-child {
	margin-block-start: 0 !important;
}

/* Kill the block-gap between every sibling inside post-content too - every
   kfy/* section already supplies its own vertical rhythm via .kfy-section
   padding, so WP's flow-layout 2rem gap just creates ugly bands of body
   color between sections. */
.wp-block-post-content.is-layout-flow > * + *,
.entry-content.is-layout-flow > * + *,
.wp-block-post-content > * + *,
.entry-content > * + * {
	margin-block-start: 0 !important;
}

/* =========================================================================
   Header shell — transparent floating frame, pinned over the hero
   --------------------------------------------------------------------------
   The outer .kfy-header is intentionally TRANSPARENT and pulled out of
   document flow with position: fixed. This lets the centered "island"
   nav (.kfy-header__nav) sit directly on top of the hero / page-hero
   artwork — no body-bg strip between header and hero, matching the
   Volt Vikings overlap pattern.
   Z-index is high enough to clear any block decorations but stays
   below modal scrim levels (defined in §10 of design_spec).
   The colored band, blur, border, and shadow have all moved to the
   inner __nav element below, which is the actual visible chrome.
   ========================================================================= */
.kfy-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 100;
	background: transparent;
	transition: background var(--ease-default);
}

/* Topbar is hidden in the floating-island layout — its info (location,
   reviews, phone) lives in the nav island, hero, and footer. We keep
   the markup so legacy block patterns still parse, and so the data
   remains crawlable for SEO. */
.kfy-header__topbar {
	display: none;

	background: var(--color-near-black);
	color: var(--color-cream);
	font-size: 14px;
	padding: 8px 0;
	border-bottom: 1px solid rgba(142, 68, 32, 0.4);
	overflow: hidden;
	max-height: 80px;
	transition:
		max-height var(--ease-default),
		padding var(--ease-default),
		opacity var(--ease-default),
		border-color var(--ease-default);
}
/* Collapse the topbar once the user has clearly started scrolling. The
   `is-scrolled` class is added by JS after a generous threshold so it stays
   visible for a moment first. */
.kfy-header.is-scrolled .kfy-header__topbar {
	max-height: 0;
	padding-top: 0;
	padding-bottom: 0;
	opacity: 0;
	border-color: transparent;
}
.kfy-header__topbar-inner {
	max-width: var(--container-max);
	margin-inline: auto;
	padding-inline: var(--sp-5);
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: var(--sp-4);
}
.kfy-header__topbar-phone {
	color: var(--color-gold);
	font-family: var(--font-display);
	letter-spacing: 0.5px;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	line-height: 1;
}
.kfy-header__topbar-phone > span,
.kfy-header__topbar-phone > strong { line-height: 1; }
.kfy-header__topbar-phone .kfy-icon {
	display: block;
	flex-shrink: 0;
	position: relative;
	top: 0.5px; /* nudge to optical center for the display font */
}

/* Location line - left side of the topbar */
.kfy-header__topbar-loc {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--color-cream);
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1.5px; /* 0.107em - meets caps tracking floor */
	text-transform: uppercase;
	text-decoration: none;
	transition: color var(--ease-default);
	line-height: 1;
}
.kfy-header__topbar-loc .kfy-icon {
	color: var(--color-gold);
	flex-shrink: 0;
	display: block;
	position: relative;
	top: 0.5px;
}
.kfy-header__topbar-loc:hover { color: var(--color-gold); }

/* Right group - rating chip + divider + phone */
.kfy-header__topbar-right {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-3);
}

.kfy-header__topbar-divider {
	display: inline-block;
	width: 1px;
	height: 14px;
	background: rgba(198, 187, 60, 0.35);
}

/* Topbar review badges - sit inside the topbar without inheriting the
   social-proof section's vertical stacking. */
.kfy-header__topbar-reviews {
	margin: 0;
	max-width: none;
	gap: 8px;
	flex-wrap: nowrap;
	justify-content: flex-end;
}
/* (Legacy mobile-phone styles removed - see new drawer below.) */

/* Narrow tablets - drop the long location line so the rating + phone keep
   breathing room. The whole topbar still hides at <576px below. */
@media (max-width: 767px) {
	.kfy-header__topbar-loc { display: none; }
	/* Drop the Facebook badge first to keep one social-proof signal visible. */
	.kfy-header__topbar-reviews .kfy-review-badge--facebook { display: none; }
}

@media (max-width: 575px) {
	.kfy-header__topbar { display: none; }
	:root { --kfy-topbar-h: 0px; }
}

/* =========================================================================
   Header navigation — 5-column grid with mascot badge centerpiece
   --------------------------------------------------------------------------
   Desktop layout (≥1024px):
     [wordmark] [left-nav] [MASCOT badge] [right-nav] [cta]
        auto       1fr         auto         1fr        auto

   The mascot is a circular badge that sits in the middle column and
   intentionally OVERFLOWS the header bar downward (like a sheriff's
   star pinned to a bar). The header itself keeps its own height; the
   badge oversize is pure visual flourish via .kfy-header__mascot-img
   negative margins.

   Mobile (<1024px):
     [wordmark] [MASCOT badge] [hamburger]
     The two nav <ul>s collapse into the existing slide-down drawer.
   ========================================================================= */
.kfy-header__nav {
	/* v2.8/v2.10: mascot geometry exposed as custom properties so the
	   grid (which reserves a clearance lane via minmax in the middle
	   column) and the absolutely-positioned .kfy-header__mascot stay
	   in lockstep. Update one number here and both the badge and the
	   nav reservation move together. Each desktop breakpoint
	   overrides --kfy-mascot-w (and optionally the buffer) below. */
	--kfy-mascot-w: 76px;
	--kfy-mascot-buffer: 24px;
	--kfy-mascot-clearance: calc(var(--kfy-mascot-w) + var(--kfy-mascot-buffer) * 2);

	/* Floating island — centered, max-width, breathing room from edges.
	   Capped tighter than the page container so the bar reads as a
	   compact lockup rather than a full-bleed band. */
	max-width: 1180px;
	margin-inline: auto;
	margin-block: var(--sp-3);
	padding: var(--sp-2) var(--sp-4);

	/* Visual chrome — was previously on the outer .kfy-header. Lives
	   on the island itself now so the band stops at the rounded edges
	   instead of spanning the viewport. */
	background: rgba(58, 29, 56, 0.95); /* eggplant @ 95% — wrap van-body anchor */
	backdrop-filter: blur(12px);
	-webkit-backdrop-filter: blur(12px);
	border: 2px solid var(--color-warm-brown);
	border-radius: 999px; /* full pill — sheriff-star mascot pokes through cleanly */
	box-shadow:
		0 8px 24px rgba(15, 8, 6, 0.35),
		0 2px 6px rgba(15, 8, 6, 0.25);

	display: grid;
	/* v2.7: mascot is now absolutely positioned (see .kfy-header__mascot
	   below), so the grid no longer needs a centre column to reserve
	   space for it. The wordmark and actions are pushed to the edges
	   while the empty 1fr spacer between them gives the mascot a clear
	   visual lane through the middle of the bar. */
	grid-template-columns: auto 1fr auto;
	grid-template-areas: "wordmark . actions";
	align-items: center;
	gap: var(--sp-3);
	position: relative;
	transition:
		background var(--ease-default),
		box-shadow var(--ease-default),
		margin-block var(--ease-default),
		border-radius var(--ease-default);
}

/* Tablet+ — give the island a touch more side air and an inner gutter
   so the wordmark/CTA don't kiss the rounded edge. */
@media (min-width: 768px) {
	.kfy-header__nav {
		margin-inline: var(--sp-5);
		padding: var(--sp-2) var(--sp-5);
	}
}
@media (min-width: 1240px) {
	.kfy-header__nav {
		/* Once the viewport exceeds the island cap + breathing room,
		   recenter via auto margins instead of fixed side margins. */
		margin-inline: auto;
	}
}

/* Scrolled state — shrink the floating gap and tighten the radius so
   the bar feels anchored to the top while still reading as an island. */
.kfy-header.is-scrolled .kfy-header__nav {
	margin-block: var(--sp-2);
	border-radius: var(--radius-lg);
	background: rgba(58, 29, 56, 0.98);
	box-shadow:
		0 6px 20px rgba(15, 8, 6, 0.45),
		0 1px 3px rgba(15, 8, 6, 0.3);
}
/* Mobile (<992px): hide the mascot entirely. The mobile build now
   ships the full horizontal "Maple Paw Plumbing" lockup (see the
   <picture> source swap in the header render template), so the
   wordmark itself carries the branding and the mascot badge would
   only crowd the bar / overlap the hamburger. The mascot returns at
   the desktop breakpoint where the layout has room for it. */
@media (max-width: 991px) {
	.kfy-header__mascot { display: none !important; }
}

.kfy-header__brand {
	grid-area: wordmark;
	display: inline-flex;
	align-items: center;
	line-height: 0;
	flex-shrink: 0;
	transition: transform var(--ease-default);
}
.kfy-header__brand:hover {
	transform: scale(1.03);
}
.kfy-header__brand-img {
	/* v2.7.3: HEIGHT-driven sizing on mobile so the navbar stays
	   under ~64px tall and stops covering the page content below.
	   The wide FullLogo lockup (mascot + sunset banner + wordmark)
	   scales down to a compact icon-tag at 32px tall (~57px wide
	   at the 16:9 aspect) — small enough to live as a sticky bar
	   ornament, big enough that the wordmark + mascot still read
	   as the brand mark. Width is capped so the auto sizing has
	   a hard ceiling on tablets. */
	height: 32px;
	width: auto;
	max-width: 200px;
	display: block;
	filter: drop-shadow(0 2px 6px rgba(41, 22, 16, 0.4));
}
@media (min-width: 480px) {
	.kfy-header__brand-img { height: 36px; max-width: 220px; }
}
@media (min-width: 768px) {
	/* Tablet still on the mobile lockup (the <picture> source query
	   uses ≤991px) — give it a touch more room. */
	.kfy-header__brand-img { height: 44px; max-width: 260px; }
}
@media (min-width: 992px) {
	/* Desktop swaps to the compact crest (LogoOnly.png) — square
	   aspect, so height drives sizing again here. */
	.kfy-header__brand-img { width: auto; height: 64px; max-width: 240px; }
}
@media (min-width: 1200px) {
	.kfy-header__brand-img { width: auto; height: 72px; max-width: 280px; }
}
.kfy-header.is-scrolled .kfy-header__brand-img {
	/* Mobile/tablet: scrolled state shrinks the height a touch so the
	   sticky bar feels even more compact while preserving aspect. */
	height: 28px;
	transition: height var(--ease-default);
}
@media (min-width: 768px) {
	.kfy-header.is-scrolled .kfy-header__brand-img { height: 36px; }
}
@media (min-width: 992px) {
	/* Desktop swaps back to LogoOnly.png (a square crest) — height
	   sizing returns since the aspect is roughly 1:1. */
	.kfy-header.is-scrolled .kfy-header__brand-img {
		width: auto;
		max-width: 240px;
		height: 52px;
		transition: height var(--ease-default);
	}
}

/* Picture wrapper has no intrinsic dimensions — collapse it to the
   inner <img> so flex/grid alignment stays consistent. */
.kfy-header__brand picture {
	display: inline-flex;
	line-height: 0;
}

/* Center mascot badge — circular sheriff-star treatment */
/* Center mascot — bare PNG floating in the nav island. No cream disc,
   no eggplant ring, no gold halo. The mascot art has its own
   transparent background so it blends straight into the eggplant pill
   and pokes below it like a sheriff-star pin. A soft drop-shadow on
   the image itself preserves separation from the nav bar without
   adding a visible badge frame.

   v2.7: Switched from a grid-area cell to absolute positioning anchored
   to the nav's true horizontal centre. Reason: the left side of the
   nav (wordmark + 2 links) is narrower than the right (3 links + CTA),
   so the equal 1fr spacer cells were pushing the mascot ~90px left of
   the visual centre. Pinning it to left:50% of the nav island fixes
   that no matter what the wordmark or CTA widths end up being.

   The `translate` property handles the centering so the existing
   `transform`-based hover scale/rotate keeps working without conflict. */
.kfy-header__mascot {
	position: absolute;
	left: 50%;
	top: 50%;
	translate: -50% -50%;
	display: flex;
	align-items: center;
	justify-content: center;
	line-height: 0;
	flex-shrink: 0;
	/* v2.8: Width/height pulled from the same --kfy-mascot-w token the
	   nav grid uses to compute its central clearance lane, so changing
	   one number resizes the badge AND widens the nav reservation in
	   the same step. */
	width: var(--kfy-mascot-w);
	height: var(--kfy-mascot-w);
	background: transparent;
	transition: transform var(--ease-default), translate var(--ease-default),
	            width var(--ease-default), height var(--ease-default);
	z-index: 3;
	pointer-events: auto;
}
.kfy-header__mascot:hover {
	transform: scale(1.05) rotate(-3deg);
}
.kfy-header__mascot-img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	display: block;
	filter: drop-shadow(0 4px 10px rgba(15, 8, 6, 0.45));
}

/* Mascot growth ramp — the clearance lane in the desktop grid follows
   --kfy-mascot-w automatically because it's defined in terms of it. */
@media (min-width: 768px) {
	.kfy-header__nav { --kfy-mascot-w: 96px; }
}
@media (min-width: 1024px) {
	.kfy-header__nav { --kfy-mascot-w: 116px; --kfy-mascot-buffer: 28px; }
	.kfy-header__mascot {
		/* Sheriff-star overflow: the badge hangs below the bar
		   centreline so it reads as a pinned emblem, not just another
		   nav cell. We bias the translate Y instead of using
		   margin-bottom (which has no effect on absolutely-positioned
		   elements) so the offset still composes cleanly with the
		   centring translate.

		   v2.11: pulled the badge upward by 20% of its own height
		   (the `- 0.2 * var(--kfy-mascot-w)` term) so the head reads
		   higher in the bar — feels more pinned-from-above instead of
		   hanging off the bottom edge. */
		translate: -50% calc(-50% + 28px - 0.2 * var(--kfy-mascot-w));
	}
}
@media (min-width: 1200px) {
	.kfy-header__nav { --kfy-mascot-w: 130px; --kfy-mascot-buffer: 32px; }
	.kfy-header__mascot {
		translate: -50% calc(-50% + 38px - 0.2 * var(--kfy-mascot-w));
	}
}

/* Scrolled state — mascot shrinks alongside the bar but KEEPS its
   sheriff-star hang so it stays pinned through the centre of the
   pill instead of snapping flush inside it. The clearance lane
   shrinks with it because --kfy-mascot-w is overridden on the nav.
   The same 20% upward bias from v2.11 is applied so the badge
   tracks higher in every state. */
.kfy-header.is-scrolled .kfy-header__nav { --kfy-mascot-w: 68px; }
.kfy-header.is-scrolled .kfy-header__mascot {
	translate: -50% calc(-50% + 16px - 0.2 * var(--kfy-mascot-w));
}
@media (min-width: 1024px) {
	.kfy-header.is-scrolled .kfy-header__nav { --kfy-mascot-w: 82px; }
	.kfy-header.is-scrolled .kfy-header__mascot {
		translate: -50% calc(-50% + 20px - 0.2 * var(--kfy-mascot-w));
	}
}
@media (min-width: 1200px) {
	.kfy-header.is-scrolled .kfy-header__nav { --kfy-mascot-w: 92px; }
	.kfy-header.is-scrolled .kfy-header__mascot {
		translate: -50% calc(-50% + 24px - 0.2 * var(--kfy-mascot-w));
	}
}

.kfy-header__menu {
	display: none;
	gap: var(--sp-4);
	list-style: none;
	margin: 0;
	padding: 0;
}
/* v2.9: Both menus push toward the OUTER edge of their cell (logo on
   the left, CTA on the right) instead of inward toward the centred
   mascot. Match-style to the Elementor reference: the menu items act
   as a continuation of the brand lockup at each end of the bar, and
   the mascot floats clearly in the middle empty band.

   Combined with the explicit central clearance lane in the desktop
   grid template, this guarantees:
   - Left menu starts immediately after the logo, never under the mascot.
   - Right menu ends immediately before the CTA, never under the mascot.
   - The empty mascot band stays exactly --kfy-mascot-clearance wide.

   We also nudge each menu away from the wordmark / CTA pill by
   --sp-3 of inline gap so the link rhythm doesn't kiss the brand
   marks. */
.kfy-header__menu--left  {
	grid-area: left-nav;
	justify-self: start;
	margin-inline-start: var(--sp-3);
}
.kfy-header__menu--right {
	grid-area: right-nav;
	justify-self: end;
	margin-inline-end: var(--sp-3);
}
/* ---- Primary nav links ----
   Hover effect (on-brand): a sunset-gradient underline grows from the
   centre, the link lifts 1px, the cream text warms to brand-orange,
   and a soft orange glow appears underneath. The whole thing reverses
   on mouse-out via the same eased timing. Focus-visible mirrors the
   hover state (with the global focus ring) so keyboard users get the
   same affordance. Honours prefers-reduced-motion via the global
   override at the top of the file. */
.kfy-header__menu a {
	color: var(--color-cream);
	font-family: var(--font-body);
	font-weight: 600;
	font-size: 16px;
	padding: 8px 6px;
	position: relative;
	white-space: nowrap;
	text-decoration: none;
	transition:
		color var(--dur-ui) var(--ease-default),
		transform var(--dur-ui) var(--ease-default),
		text-shadow var(--dur-ui) var(--ease-default);
}
.kfy-header__menu a::after {
	content: "";
	position: absolute;
	left: 6px; right: 6px; bottom: 2px;
	height: 2px;
	border-radius: 2px;
	background: linear-gradient(
		90deg,
		var(--pdu-sunset-yellow) 0%,
		var(--pdu-brand-orange) 50%,
		var(--pdu-red-plunger) 100%
	);
	box-shadow: 0 4px 14px rgba(239, 126, 26, 0.55);
	transform: scaleX(0);
	transform-origin: center;
	transition: transform var(--ease-bounce);
}
.kfy-header__menu a:hover,
.kfy-header__menu a:focus-visible {
	color: var(--pdu-sunset-yellow);
	transform: translateY(-1px);
	text-shadow: 0 0 18px rgba(247, 199, 59, 0.45);
}
.kfy-header__menu a:hover::after,
.kfy-header__menu a:focus-visible::after {
	transform: scaleX(1);
}
.kfy-header__menu a:active {
	transform: translateY(0);
}

/* Current-page indicator — same look as hover but always-on, with
   slightly muted glow so the active item still reads as a state, not
   a button. WP injects .current-menu-item / aria-current="page" on
   the active link in custom-rendered menus; we cover both. */
.kfy-header__menu a[aria-current="page"],
.kfy-header__menu .current-menu-item > a {
	color: var(--pdu-brand-orange);
}
.kfy-header__menu a[aria-current="page"]::after,
.kfy-header__menu .current-menu-item > a::after {
	transform: scaleX(1);
	box-shadow: 0 3px 10px rgba(239, 126, 26, 0.35);
}

.kfy-header__cta {
	display: none;
	grid-area: cta;
}

.kfy-header__hamburger {
	grid-area: actions;
	justify-self: end;
	display: inline-flex;
	flex-direction: column;
	justify-content: center;
	gap: 5px;
	width: 44px;
	height: 44px;
	border: 1.5px solid rgba(248, 243, 224, 0.35);
	background: rgba(15, 8, 6, 0.25);
	border-radius: var(--radius-md);
	cursor: pointer;
	padding: 10px;
	flex-shrink: 0;
	transition: background var(--ease-default), border-color var(--ease-default);
}
.kfy-header__hamburger:hover,
.kfy-header__hamburger:focus-visible {
	background: rgba(248, 243, 224, 0.10);
	border-color: rgba(248, 243, 224, 0.55);
}
.kfy-header__hamburger span {
	display: block;
	width: 100%;
	height: 2px;
	background: var(--color-cream);
	border-radius: 2px;
	transition: transform var(--ease-default), opacity var(--ease-default);
}
.kfy-header.is-open .kfy-header__hamburger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.kfy-header.is-open .kfy-header__hamburger span:nth-child(2) { opacity: 0; }
.kfy-header.is-open .kfy-header__hamburger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* =========================================================================
   Mobile drawer — floating island that matches the nav pill above it
   --------------------------------------------------------------------------
   v2.12: rebuilt to fix the "broken" feel on mobile. Old version was a
   full-bleed band glued to top:100% of the fixed header; on the new
   floating-island nav the drawer floated below the pill with a visible
   gap and no visual relationship to the bar.

   New build:
   - The drawer is itself a rounded island, inset from the viewport
     edges so it visually echoes the nav pill above it.
   - A blurred backdrop (::before on the open header) dims the page
     and is click-dismissable from JS.
   - Internal scrolling is enabled so long menus stay reachable on
     short phones, with momentum scrolling on iOS.
   - Aligned to the actual rendered header height via the
     --kfy-header-h custom prop already maintained by the JS.
   ========================================================================= */

/* Backdrop — a dim/blur layer painted on the fixed header itself so it
   sits below the drawer (z-index stack inside the header) but above
   page content. Pointer-events flip on with the drawer. */
.kfy-header::before {
	content: "";
	position: fixed;
	inset: 0;
	background: rgba(15, 8, 6, 0.55);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 240ms ease, visibility 0s linear 240ms;
	z-index: 0;
}
.kfy-header.is-open::before {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transition: opacity 240ms ease, visibility 0s linear 0s;
}
@media (min-width: 992px) {
	.kfy-header::before { display: none; }
}

.kfy-header__mobile {
	display: block;
	position: absolute;
	left: 0;
	right: 0;
	top: calc(var(--kfy-header-h, 88px) - var(--sp-2));
	margin-inline: var(--sp-3);
	max-width: calc(100vw - var(--sp-3) * 2);
	max-height: calc(100dvh - var(--kfy-header-h, 88px) - var(--sp-5));
	overflow-x: hidden;
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
	overscroll-behavior: contain;

	background:
		radial-gradient(620px 280px at 50% -10%, rgba(198, 187, 60, 0.12), transparent 65%),
		linear-gradient(180deg, var(--color-dark-teal) 0%, var(--color-near-black) 100%);
	border: 2px solid var(--color-warm-brown);
	border-radius: var(--radius-lg);
	box-shadow:
		0 18px 40px rgba(15, 8, 6, 0.55),
		0 4px 12px rgba(15, 8, 6, 0.35);

	opacity: 0;
	visibility: hidden;
	transform: translateY(-12px) scale(0.98);
	transform-origin: top center;
	transition:
		opacity 220ms ease,
		transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1),
		visibility 0s linear 220ms;
	pointer-events: none;
	z-index: 2;
}
.kfy-header.is-open .kfy-header__mobile {
	opacity: 1;
	visibility: visible;
	transform: translateY(0) scale(1);
	pointer-events: auto;
	transition:
		opacity 220ms ease,
		transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1),
		visibility 0s linear 0s;
}
@media (min-width: 480px) {
	.kfy-header__mobile { margin-inline: var(--sp-5); }
}

/* Body scroll lock when the drawer is open (set by JS). */
body.kfy-menu-open {
	overflow: hidden;
}

.kfy-header__mobile-inner {
	position: relative;
	padding: var(--sp-4) var(--sp-5) calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
	max-width: 520px;
	margin: 0 auto;
}

/* Brand watermark - subtle paw bottom-right */
.kfy-header__mobile-paw {
	position: absolute;
	right: -28px;
	bottom: -38px;
	color: var(--color-gold);
	opacity: 0.06;
	pointer-events: none;
	line-height: 0;
	transform: rotate(-12deg);
}
.kfy-header__mobile-paw .kfy-icon { width: 160px; height: 160px; }

/* Nav list - clean text rows divided by hairlines */
.kfy-header__mobile-list {
	list-style: none;
	margin: 0;
	padding: 0;
	border-top: 1px solid rgba(248, 243, 224, 0.06);
}
.kfy-header__mobile-list li {
	border-bottom: 1px solid rgba(248, 243, 224, 0.06);
	opacity: 0;
	transform: translateX(-6px);
	transition: opacity 220ms ease, transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
	transition-delay: calc(40ms + var(--row-index, 0) * 28ms);
}
.kfy-header.is-open .kfy-header__mobile-list li {
	opacity: 1;
	transform: translateX(0);
}

.kfy-header__mobile-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 14px 4px;
	color: var(--color-cream);
	font-family: var(--font-body);
	font-weight: 600;
	font-size: 16px;
	letter-spacing: 0.2px;
	text-decoration: none;
	transition: color 160ms ease, padding-left 160ms ease;
}
.kfy-header__mobile-row:hover,
.kfy-header__mobile-row:focus-visible {
	color: var(--color-gold);
	padding-left: 8px;
	outline: none;
}
.kfy-header__mobile-row-chev {
	color: rgba(248, 243, 224, 0.35);
	transition: transform 160ms ease, color 160ms ease;
	display: inline-flex;
}
.kfy-header__mobile-row:hover .kfy-header__mobile-row-chev {
	color: var(--color-gold);
	transform: translateX(3px);
}

/* Action row - compact: one prominent gold pill + ghost call link */
.kfy-header__mobile-actions {
	margin-top: 14px;
	display: grid;
	grid-template-columns: 1fr;
	gap: 8px;
	position: relative;
	z-index: 1;
}
/* Call - primary, dominant glove-red pill. Mirrors .kfy-btn--primary so
   the drawer's headline action matches the site-wide "Get A Fast Quote"
   pill (same gradient stops, cream text + dark text-shadow, glove-red
   shadow halo). Keeps the header CTA, the in-menu call, and the form
   submit reading as one coordinated red button family. */
.kfy-header__mobile-call {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 12px;
	padding: 14px 20px;
	border-radius: var(--radius-full);
	background: linear-gradient(135deg, var(--pdu-glove-light) 0%, var(--pdu-glove) 55%, var(--pdu-glove-deep) 100%);
	color: var(--pdu-cream);
	text-decoration: none;
	box-shadow:
		0 6px 18px rgba(178, 58, 44, 0.45),
		inset 0 1px 0 rgba(255, 255, 255, 0.18);
	text-shadow: 0 1px 1px rgba(60, 14, 9, 0.35);
	transition: transform var(--ease-default), box-shadow var(--ease-default);
	min-width: 0;
}
.kfy-header__mobile-call:hover {
	transform: translateY(-2px);
	box-shadow:
		0 10px 28px rgba(178, 58, 44, 0.55),
		inset 0 1px 0 rgba(255, 255, 255, 0.22);
	color: var(--pdu-cream);
}
.kfy-header__mobile-call .kfy-icon { color: var(--pdu-cream); flex-shrink: 0; }
.kfy-header__mobile-call-text {
	display: inline-flex;
	align-items: baseline;
	gap: 8px;
	white-space: nowrap;
	line-height: 1;
	min-width: 0;
}
.kfy-header__mobile-call-eyebrow {
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1.4px;
	text-transform: uppercase;
	opacity: 0.85;
}
.kfy-header__mobile-call-num {
	font-family: var(--font-display);
	font-size: 18px;
	letter-spacing: 0.5px;
}

/* Narrow phones (≤380px): the drawer's 24px inner padding + the pill's
   20px padding + 18px icon leave only ~210px for the "CALL (512) 555-0142"
   string, which overflows the gold pill at 360px-wide viewports. Tighten
   the inner padding, shrink the gap/typography, and allow the label to
   reflow if the phone format ever gets longer. */
@media (max-width: 380px) {
	.kfy-header__mobile-inner {
		padding-left: var(--sp-4);
		padding-right: var(--sp-4);
	}
	.kfy-header__mobile-call {
		gap: 10px;
		padding: 13px 14px;
	}
	.kfy-header__mobile-call-text {
		gap: 6px;
		white-space: normal;
		flex-wrap: wrap;
		justify-content: center;
		row-gap: 2px;
	}
	.kfy-header__mobile-call-eyebrow { font-size: 12px; letter-spacing: 1.2px; }
	.kfy-header__mobile-call-num { font-size: 16px; }
}

/* Contact Us - secondary outline (matches design-spec .btn-secondary) */
.kfy-header__mobile-quote {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 12px 18px;
	border-radius: var(--radius-full);
	background: transparent;
	color: var(--color-gold);
	border: 1.5px solid rgba(198, 187, 60, 0.55);
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1.4px;
	text-transform: uppercase;
	text-decoration: none;
	transition: background var(--ease-default), border-color var(--ease-default), color var(--ease-default);
}
.kfy-header__mobile-quote:hover {
	background: rgba(198, 187, 60, 0.12);
	border-color: var(--color-gold);
	color: var(--color-gold);
}
.kfy-header__mobile-quote .kfy-icon { color: inherit; transition: transform var(--ease-default); }
.kfy-header__mobile-quote:hover .kfy-icon { transform: translateX(3px); }

@media (min-width: 992px) {
	/* Desktop ≥1024px: lockup reads
	      [logo] [Home Services Areas] ... 🦘 ... [About Contact] [CTA]

	   v2.10: Switched away from the fixed-min outer cells (which were
	   leaving 100+ px of dead space between the narrow logo art and
	   the left menu). Now every visible item is auto-sized and a
	   single elastic spacer in the middle absorbs the slack, so the
	   menus naturally hug the wordmark on the left and the CTA pill
	   on the right just like the Elementor reference.

	   The spacer's `minmax(var(--kfy-mascot-clearance), 1fr)` keeps
	   our hard guarantee from v2.8 intact — the menus literally
	   cannot enter the mascot's clearance band even if link labels
	   grow — while letting the spacer expand to fill any extra
	   horizontal room when the nav is wider than the menus need. */
	.kfy-header__nav {
		grid-template-columns:
			auto                                            /* wordmark */
			auto                                            /* left menu */
			minmax(var(--kfy-mascot-clearance), 1fr)        /* mascot lane */
			auto                                            /* right menu */
			auto;                                           /* cta */
		grid-template-areas: "wordmark left-nav . right-nav cta";
		gap: var(--sp-3);
	}
	.kfy-header__menu { display: flex; }
	.kfy-header__cta { display: inline-flex; justify-self: end; }
	.kfy-header__brand { justify-self: start; }
	.kfy-header__hamburger { display: none; }
	.kfy-header__mobile { display: none !important; }
}

/* =========================================================================
   BLOCK 2 - HERO
   ========================================================================= */
.kfy-hero {
	position: relative;
	overflow: hidden;
	background-color: var(--pdu-eggplant-deep);
	/* Wrap-true sunset → dusk fallback gradient: only seen when no photo
	   background is set. The .kfy-hero--has-photo modifier hides this
	   layer behind the photo and the calibrated overlay below. */
	background-image:
		radial-gradient(ellipse at 80% 0%,  rgba(247, 199, 59, 0.28), transparent 60%),
		radial-gradient(ellipse at 0% 100%, rgba(178, 58, 44, 0.32),  transparent 60%),
		linear-gradient(180deg,
			#5C3A28 0%,
			var(--pdu-maroon) 45%,
			var(--pdu-eggplant) 78%,
			var(--pdu-eggplant-deep) 100%
		);
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
	color: var(--color-cream);
	/* Top padding bumped so the eyebrow chip + headline never tuck under
	   the floating header island (.kfy-header is position:fixed and
	   covers ~144px from the viewport top). Bottom padding keeps the
	   original generous rhythm. */
	padding: clamp(160px, 14vw, 200px) 0 clamp(var(--sp-10), 8vw, var(--sp-14));
	/* Hero is now the first thing in the viewport (header overlays it),
	   so the full svh is ours — no need to subtract a header height.
	   We add a bit beyond the viewport so the kangaroo mascot's tail
	   and feet fit fully inside the hero (which is overflow:hidden). */
	min-height: calc(100svh + 80px);
	display: flex;
	align-items: center;
}

/* =========================================================================
   .kfy-hero--has-photo  → hero with vector-scene/photo background
   --------------------------------------------------------------------------
   ADA / WCAG 2.1 AA contrast plan (see design_spec.md §3, §9):

   The vector-scene image has a very bright sun area (relative luminance
   ≈ 0.96). Cream text (#FBEFD9, L ≈ 0.890) on that area would be
   ~1.05 : 1 — a hard fail. The overlay below is calibrated so even the
   brightest pixel under the headline / subtitle drops to L ≤ 0.16, which
   gives cream text a worst-case ratio of 4.5 : 1 (AA body) and a typical
   ratio above 7 : 1 (AAA body) in the content column.

   Layer stack (bottom → top):
     1. .kfy-hero background-color = eggplant-deep      (final fallback)
     2. .kfy-hero__bg              = vector scene photo (z 0)
     3. .kfy-hero::before          = directional dark overlay (z 1)
     4. .kfy-hero__inner content   = headline / subtitle / form (z 2+)
   ========================================================================= */
.kfy-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	background:
		radial-gradient(ellipse at 80% 0%, rgba(247, 199, 59, 0.10), transparent 60%),
		radial-gradient(ellipse at 0% 100%, rgba(142, 68, 32, 0.20), transparent 60%),
		linear-gradient(180deg, rgba(41, 22, 16, 0.20) 0%, rgba(41, 22, 16, 0.35) 60%, rgba(41, 22, 16, 0.55) 100%);
	pointer-events: none;
	z-index: 1;
}
.kfy-hero__bg {
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center;
	z-index: 0;
}

/* =========================================================================
   .kfy-hero--parallax  → two-layer scroll parallax
   --------------------------------------------------------------------------
   Layout (inside .kfy-hero, z-stacking bottom → top):
     0. .kfy-hero background-color (eggplant-deep) — final fallback
     1. .kfy-hero__scene-base    — the sky/sunset image (lags scroll)
     2. .kfy-hero__scene-ground  — the foreground silhouette (drifts UP)
     3. .kfy-hero::before        — calibrated dark scrim for AA contrast
     4. .kfy-hero__inner         — text + form

   Motion model:
     The JS handler writes a single CSS custom property --kfy-hero-py,
     measured in PIXELS, equal to:
         (scrollY - heroTop)   while the hero is in view
     Each layer multiplies it by its own factor and translates by that
     amount. Positive Y = element moves DOWN inside the hero, which
     LAGS the page (page moves up faster) → far/parallax depth.
     Negative Y = element moves UP inside the hero, which OUTPACES
     the page → near/foreground push.

   Defaults:
     base   → +0.30 (sky drifts down at 30% of scroll → far)
     ground → −0.18 (ground lifts up at 18% of scroll → near, dramatic)

   ADA / WCAG 2.3.3 (Animation from Interactions):
     The transforms are wrapped in @media (prefers-reduced-motion:
     no-preference). Users with reduced-motion preference see a static
     two-layer composition with NO scroll-driven movement.
   ========================================================================= */
.kfy-hero.kfy-hero--parallax .kfy-hero__scene {
	position: absolute;
	inset: 0;
	overflow: hidden;
	z-index: 0;
	pointer-events: none;
	/* The custom property the JS handler updates — falls back to 0 so the
	   composition is correct on first paint before any scroll fires. */
	--kfy-hero-py: 0px;
}
.kfy-hero.kfy-hero--parallax .kfy-hero__scene-base,
.kfy-hero.kfy-hero--parallax .kfy-hero__scene-ground {
	position: absolute;
	left: 0;
	width: 100%;
	background-repeat: no-repeat;
	will-change: transform;
	/* Pre-promote to GPU layer for jank-free scrolling without forcing
	   a permanent compositing layer (will-change is enough on modern
	   browsers; backface-visibility belt-and-braces). */
	backface-visibility: hidden;
	transform: translate3d(0, 0, 0);
}
.kfy-hero.kfy-hero--parallax .kfy-hero__scene-base {
	top: 0;
	height: 110%; /* slight oversize so vertical drift never reveals the
	                  eggplant fallback at the top edge */
	background-size: cover;
	background-position: center 25%;
}
.kfy-hero.kfy-hero--parallax .kfy-hero__scene-ground {
	bottom: 0;
	/* Ground silhouette is a horizontal strip — sized to ~45% of hero
	   height so the trees/grass anchor the lower third without crowding
	   the form card on the right. */
	height: 48%;
	background-size: cover;
	background-position: center bottom;
}

/* Apply the actual parallax transforms ONLY when the user has not asked
   for reduced motion. With reduce-motion, both layers stay at their
   layout positions for a static composed scene. */
@media (prefers-reduced-motion: no-preference) {
	.kfy-hero.kfy-hero--parallax .kfy-hero__scene-base {
		transform: translate3d(0, calc(var(--kfy-hero-py, 0px) *  0.30), 0);
	}
	.kfy-hero.kfy-hero--parallax .kfy-hero__scene-ground {
		transform: translate3d(0, calc(var(--kfy-hero-py, 0px) * -0.18), 0);
	}
}

/* --has-photo modifier overrides — declared after base rules so they win
   on equal specificity (compound selector .kfy-hero.kfy-hero--has-photo
   bumps specificity to (0,2,0)+pseudo so it always overrides the base
   .kfy-hero::before layer regardless of source-order edits later). */
.kfy-hero.kfy-hero--has-photo {
	/* Solid color fallback only — the photo + overlay cover everything else. */
	background-image: none;
}
.kfy-hero.kfy-hero--has-photo .kfy-hero__bg {
	background-position: center 35%; /* lift horizon: trees anchor under content */
}
.kfy-hero.kfy-hero--has-photo::before {
	/* Lighter atmospheric tint - the vector scene shines through clearly.
	   Trade-off acknowledged (see design_spec §3 / §9):
	     A scrim heavy enough to guarantee per-pixel WCAG AA over the
	     brightest sun area would crush the artwork (~80%+ overlay). The
	     stylistic decision is to keep the scrim moderate and rely on:
	       1. The text-shadow safety net on .kfy-hero cream text below.
	       2. The opaque cream form card that covers the bright sun zone.
	       3. The dark tree silhouette + grasslands that naturally sit
	          under the headline column once the bg is positioned at 5% x.
	     This keeps the warm sunset reading as designed while still
	     giving cream text 4.5+:1 over the pixels it actually overlays. */
	background:
		linear-gradient(105deg,
			rgba(37, 19, 31, 0.55) 0%,
			rgba(37, 19, 31, 0.42) 35%,
			rgba(58, 29, 56, 0.22) 65%,
			rgba(58, 29, 56, 0.10) 100%
		),
		/* Bottom-up warm vignette: ember glow under the CTA row. */
		linear-gradient(180deg,
			transparent 55%,
			rgba(178, 58, 44, 0.14) 100%
		);
}
/* Position the bg so the dark left-tree silhouette lands behind the
   headline column and the bright sun stays under the opaque form card. */
.kfy-hero.kfy-hero--has-photo .kfy-hero__bg {
	background-position: 8% 35%;
}
/* Cream-text legibility safety net: the lighter scrim above means
   individual bright pixels can sit under text, so we add a generous
   warm-dark text-shadow. Per WCAG 2.x this does NOT formally count
   toward the contrast ratio, but it provides perceptual contrast and
   is the standard treatment for hero text over photographic bgs. */
.kfy-hero.kfy-hero--has-photo .kfy-hero__title,
.kfy-hero.kfy-hero--has-photo .kfy-hero__subtitle,
.kfy-hero.kfy-hero--has-photo .kfy-hero__owner-pill {
	text-shadow:
		0 1px 2px  rgba(15, 8, 6, 0.85),
		0 2px 12px rgba(15, 8, 6, 0.55);
}
/* Mobile: layout collapses to a single column → soft top-down dim
   keeps both content and form-card areas legible without darkening the
   sky to mud. */
@media (max-width: 991px) {
	.kfy-hero.kfy-hero--has-photo::before {
		background:
			linear-gradient(180deg,
				rgba(37, 19, 31, 0.55) 0%,
				rgba(37, 19, 31, 0.42) 45%,
				rgba(58, 29, 56, 0.30) 75%,
				rgba(58, 29, 56, 0.18) 100%
			);
	}
	.kfy-hero.kfy-hero--has-photo .kfy-hero__bg {
		background-position: center 30%;
	}
}

/* =========================================================================
   Drifting cloud animation
   --------------------------------------------------------------------------
   Three SVG-as-data-URI cloud silhouettes in the upper sky, each on its
   own animation track at a different speed + delay so the rhythm never
   syncs up. Slower clouds also render smaller + more transparent, which
   reinforces atmospheric perspective (depth = distance).

   ADA / WCAG 2.2.2 + 2.3.3 (Pause, Stop, Hide / Animation from Interactions):
     - Animation duration is long (60-110s) and motion is subtle (slow
       horizontal drift only, no flashing or scale changes), well under
       the 5/sec flash threshold.
     - The whole animation is gated behind @media (prefers-reduced-motion:
       no-preference) → users with reduced-motion preference see a static,
       still sky.
   ========================================================================= */
.kfy-hero__clouds {
	position: absolute;
	inset: 0;
	z-index: 1; /* above .kfy-hero__bg (z 0), below .kfy-hero::before scrim
	               (z 1 too) — same z so painting order wins; clouds are
	               rendered AFTER the bg in markup so they paint on top. */
	overflow: hidden;
	pointer-events: none;
}
.kfy-hero__cloud {
	position: absolute;
	top: 0;
	display: block;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	/* Inline SVG cloud silhouette (three overlapping ellipses). Pure
	   white at 0.85 opacity reads as a soft cumulus against the warm
	   sunset. Encoded with %23 for # and %20 for spaces so the data
	   URI works without external escaping. */
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80'><g fill='%23ffffff' opacity='0.85'><ellipse cx='50' cy='52' rx='40' ry='22'/><ellipse cx='100' cy='38' rx='52' ry='30'/><ellipse cx='150' cy='52' rx='40' ry='22'/></g></svg>");
	will-change: transform;
}
.kfy-hero__cloud--1 {
	top: 8%;
	width: 220px;
	height: 88px;
	opacity: 0.55;
}
.kfy-hero__cloud--2 {
	top: 14%;
	width: 160px;
	height: 64px;
	opacity: 0.40;
}
.kfy-hero__cloud--3 {
	top: 4%;
	width: 280px;
	height: 112px;
	opacity: 0.65;
}
@keyframes kfy-cloud-drift {
	from { transform: translate3d(-30vw, 0, 0); }
	to   { transform: translate3d(130vw, 0, 0); }
}
@media (prefers-reduced-motion: no-preference) {
	.kfy-hero__cloud--1 {
		animation: kfy-cloud-drift 75s linear infinite;
		animation-delay: -10s;
	}
	.kfy-hero__cloud--2 {
		animation: kfy-cloud-drift 110s linear infinite;
		animation-delay: -55s; /* starts mid-flight so all 3 are visible at load */
	}
	.kfy-hero__cloud--3 {
		animation: kfy-cloud-drift 90s linear infinite;
		animation-delay: -30s;
	}
}
/* Reduced-motion: park clouds at sensible static positions instead of
   stacked at -30vw (off-screen left). */
@media (prefers-reduced-motion: reduce) {
	.kfy-hero__cloud--1 { transform: translate3d(15vw, 0, 0); }
	.kfy-hero__cloud--2 { transform: translate3d(55vw, 0, 0); }
	.kfy-hero__cloud--3 { transform: translate3d(78vw, 0, 0); }
}
.kfy-hero__inner {
	position: relative;
	z-index: 2;
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
	padding-inline: var(--sp-5);
	display: grid;
	gap: var(--sp-8);
	grid-template-columns: 1fr;
	align-items: center;
}

/* The CALL button gets a positioned wrapper so the back-of-van decoration
   can be anchored directly to the button. This means the van follows the
   button at every breakpoint and through any layout reflow.
   The wrapper stretches to fill its grid cell so the primary CTA is at
   least as wide as the secondary "Get Free Quote" button next to it
   (otherwise inline-flex would shrink it to its content). */
.kfy-hero__cta-call-wrap {
	position: relative;
	display: flex;
	width: 100%;
	isolation: isolate;
}
.kfy-hero__cta-call-wrap > .kfy-hero__cta-call {
	position: relative;
	z-index: 2;
	width: 100%;
}

/* Make sure surrounding hero content (badges, area pills, certs, etc.)
   sits ABOVE the gradient overlay. They share the same stacking context,
   so giving the call wrapper a positive z-index lifts the whole CTA row
   above the ::before pseudo. */
.kfy-hero__content > * {
	position: relative;
	z-index: 2;
}
.kfy-hero__cta-call-wrap > .kfy-hero__cta-call {
	z-index: 3;
}

.kfy-hero__ratings {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2);
	margin-bottom: var(--sp-4);
}
.kfy-hero__rating-badge {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	background: rgba(248, 243, 224, 0.08);
	border: 1px solid rgba(198, 187, 60, 0.3);
	color: var(--color-cream);
	padding: 6px 12px;
	border-radius: var(--radius-full);
	font-size: 14px;
}
.kfy-hero__rating-badge strong { color: var(--color-gold); }

/* Hero headline — uses the system display stack (--font-hero) instead
   of Moderniz so the WHO/WHERE statement and the SAME-DAY/HONEST PRICING
   promise fit in 2 lines each at the squeezed 2-column desktop hero.
   System display fonts at weight 900 keep the visual punch while
   delivering ~30 % more characters per line than Moderniz, so the
   headline stops fragmenting into 5+ short orphan lines.

   Sizing tiers (default → narrower at 992-1199px → larger at ≥1200px):
     - default base  : clamp(28px, 3.4vw + 0.5rem, 44px)
     - 992-1199px    : clamp(26px, 3vw  + 0.25rem, 36px)  ← squeezed grid
     - ≥1200px       : clamp(40px, 3.2vw + 0.25rem, 56px) ← roomy grid

   ADA / WCAG 2.1 notes:
     - line-height 1.08 - floor for display caps; body still uses 1.6.
     - text-wrap: balance distributes line breaks evenly so no line is
       a single short word (cognitive-load win for low-vision readers).
     - hyphens: manual + overflow-wrap: break-word prevents the browser
       from auto-hyphenating brand names while still preventing a
       super-long single word from blowing past the column width.
     - letter-spacing -0.005em offsets the slight tracking that platform
       display fonts ship with at heavy weights (purely aesthetic). */
.kfy-hero__title {
	margin: 0 0 var(--sp-4);
	font-family: var(--font-hero);
	font-weight: 900;
	font-size: clamp(28px, 3.4vw + 0.5rem, 44px);
	line-height: 1.08;
	letter-spacing: -0.005em;
	text-wrap: balance;
	hyphens: manual;
	overflow-wrap: break-word;
	word-spacing: -0.01em;
}
.kfy-hero__title span {
	color: var(--color-gold);
	display: block;
	font-family: var(--font-hero);
	font-weight: 800;          /* one notch lighter than the main statement */
	font-size: 0.78em;         /* clear secondary-promise hierarchy */
	margin-top: 0.28em;        /* breathing room between statement + promise */
	line-height: 1.1;
	letter-spacing: 0;
}

/* Squeezed 2-column tier (form column eats ~half the width): use the
   smallest scale so 'LICENSED PLUMBER IN' fits on one line and
   'SAME-DAY SERVICE,' fits on one line. */
@media (min-width: 992px) and (max-width: 1199px) {
	.kfy-hero__title {
		font-size: clamp(26px, 3vw + 0.25rem, 36px);
	}
}

/* Roomy desktop tier (≥1200px): the content column is wide enough for
   a punchier hero, so we open the upper bound back up. */
@media (min-width: 1200px) {
	.kfy-hero__title {
		font-size: clamp(40px, 3.2vw + 0.25rem, 56px);
	}
}

.kfy-hero__owner-pill {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	background: rgba(142, 68, 32, 0.4);
	border: 1px solid rgba(198, 187, 60, 0.4);
	color: var(--color-cream);
	padding: 6px 14px;
	border-radius: var(--radius-full);
	font-family: var(--font-display);
	text-transform: uppercase;
	letter-spacing: 1px;
	font-size: 14px;
	margin-bottom: var(--sp-4);
}
.kfy-hero__owner-pill .kfy-icon {
	color: var(--color-gold);
	flex-shrink: 0;
}

.kfy-hero__subtitle {
	font-size: clamp(18px, 1vw + 16px, 21px);
	color: var(--color-cream);
	max-width: 560px;
	margin: 0 0 var(--sp-6);
	line-height: 1.6;
	text-shadow: 0 1px 2px rgba(27, 17, 12, 0.6);
}

/* Hero CTA pair — primary CALL + secondary QUOTE
   --------------------------------------------------------------------------
   UX/UI rules baked in here:
   - Equal grid columns (1fr 1fr) so both buttons share visual weight
   - IDENTICAL height + padding so they read as a deliberate pair, not two
     buttons that happen to sit next to each other
   - Single source-of-truth typography on both via .kfy-hero__ctas > .kfy-btn
     (the per-button rules below only set color / fill / border, never size)
   - Labels never hyphen-break; if a label is too long for one line at small
     widths it wraps as two clean balanced lines (text-wrap: balance) with
     `hyphens: none` to forbid the awkward "FLAT-/RATE" break we had before
   - Primary > secondary hierarchy preserved: orange-gradient fill vs ghost
     outline, with equal motion budget on hover (translateY(-2px)).
   ========================================================================= */
.kfy-hero__ctas {
	display: grid;
	/* 70/30 split — the CALL pill is the page's primary conversion
	   action (cheapest path to revenue), so it carries the visual
	   weight while GET MY FLAT-RATE QUOTE rides as a clear secondary
	   option. minmax(0, …) on both tracks keeps the ratio honest by
	   letting cells shrink past their content's intrinsic min-width
	   instead of bulging the row. The mobile override below (≤991px)
	   collapses this to a single column so the proportion only
	   applies on desktop, where there's room for both side-by-side. */
	grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
	align-items: stretch;
	gap: var(--sp-3);
	margin-bottom: var(--sp-6);
	max-width: 560px;
}
.kfy-hero__ctas > .kfy-btn {
	width: 100%;
	justify-content: center;
	gap: 10px;
	/* Override the global .kfy-btn defaults for the constrained 2-up
	   hero layout. Moderniz is too wide for "GET MY FLAT-RATE QUOTE"
	   inside a half-width grid cell, so we swap to the system body
	   stack at heavy weight, drop letter-spacing, and let the label
	   wrap onto a second balanced line as a graceful fallback. */
	font-family: var(--font-body);
	font-weight: 800;
	letter-spacing: 0.4px;
	font-size: clamp(13px, 0.55vw + 11px, 15px);
	padding: 16px 20px;
	white-space: normal;
	text-wrap: balance;
	hyphens: none;
	overflow-wrap: normal;
	word-break: normal;
	line-height: 1.2;
	min-height: 56px;
	min-width: 0; /* allows the grid cell to actually shrink */
	border-radius: var(--radius-md);
	transition:
		transform var(--dur-ui) var(--ease-default),
		box-shadow var(--dur-ui) var(--ease-default),
		background-color var(--dur-ui) var(--ease-default),
		border-color var(--dur-ui) var(--ease-default),
		color var(--dur-ui) var(--ease-default);
}
.kfy-hero__ctas > .kfy-btn .kfy-icon {
	flex-shrink: 0;
	transition: transform var(--dur-ui) var(--ease-default);
}

/* CALL — primary, dominant glove-red gradient (matches --pdu-glove*
   tokens / mascot's boxing gloves).
   The phone number itself never wraps (otherwise "(512) 555-0142" can
   break in awkward places like after "(512)"). The leading "Call" word
   may drop to its own line on very narrow widths, which still reads
   correctly as "Call / (512) 555-0142". */
.kfy-hero__cta-call.kfy-btn {
	background: linear-gradient(135deg, var(--pdu-glove-light) 0%, var(--pdu-glove) 55%, var(--pdu-glove-deep) 100%);
	color: var(--pdu-cream);
	border: 2px solid transparent;
	box-shadow:
		0 6px 18px rgba(178, 58, 44, 0.45),
		inset 0 1px 0 rgba(255, 255, 255, 0.18);
	text-shadow: 0 1px 1px rgba(60, 14, 9, 0.35);
}
.kfy-hero__cta-call.kfy-btn .kfy-icon { color: var(--pdu-cream); }
.kfy-hero__cta-call.kfy-btn > span {
	/* Keep the phone number itself on one line so it never breaks
	   between the area code and the local number. */
	white-space: nowrap;
}
.kfy-hero__cta-call.kfy-btn:hover,
.kfy-hero__cta-call.kfy-btn:focus-visible {
	transform: translateY(-2px);
	box-shadow:
		0 10px 28px rgba(178, 58, 44, 0.55),
		inset 0 1px 0 rgba(255, 255, 255, 0.22);
	color: var(--pdu-cream);
}
.kfy-hero__cta-call.kfy-btn:active {
	transform: translateY(0);
	box-shadow: 0 4px 12px rgba(142, 42, 32, 0.5);
}

/* QUOTE — cream-filled secondary button. Same height + padding as CALL
   so the two read as a matched pair, but the cream fill borrowed from
   the wordmark on the FullLogo lockup keeps the secondary button on-
   brand against the dark hero gradient (the previous transparent ghost
   variant disappeared into the eggplant background). The deep brown
   text matches the body copy color in the cream slabs elsewhere on the
   page so the button still reads as a clear brand element rather than
   a generic light pill. */
.kfy-hero__cta-quote.kfy-btn {
	background: var(--pdu-cream);
	color: var(--pdu-brown-deep);
	border: 1.5px solid rgba(251, 239, 217, 0.95);
	box-shadow:
		0 6px 18px rgba(15, 8, 6, 0.22),
		inset 0 -2px 0 rgba(41, 22, 16, 0.08);
}
.kfy-hero__cta-quote.kfy-btn:hover,
.kfy-hero__cta-quote.kfy-btn:focus-visible {
	background: #FFF6E1; /* one shade brighter than --pdu-cream so the lift reads */
	color: var(--pdu-brown-deep);
	border-color: var(--pdu-cream);
	transform: translateY(-2px);
	box-shadow:
		0 12px 28px rgba(15, 8, 6, 0.32),
		inset 0 -2px 0 rgba(41, 22, 16, 0.1);
}
.kfy-hero__cta-quote.kfy-btn:active {
	transform: translateY(0);
	box-shadow:
		0 4px 12px rgba(15, 8, 6, 0.22),
		inset 0 -2px 0 rgba(41, 22, 16, 0.08);
}
.kfy-hero__cta-quote .kfy-icon { color: currentColor; }
.kfy-hero__cta-quote:hover .kfy-icon,
.kfy-hero__cta-quote:focus-visible .kfy-icon {
	transform: translateX(3px);
}

/* Squeezed tier (992-1199px) — the right-hand form column eats half
   the width here, so the CTA cells are at their narrowest. Step the
   type and padding down so default 2-3 word labels (e.g. "GET MY
   FLAT-RATE QUOTE") fit cleanly on a single line, and any longer
   custom label still falls back to a balanced 2-line layout instead
   of mid-word breaks. */
@media (min-width: 992px) and (max-width: 1199px) {
	.kfy-hero__ctas > .kfy-btn {
		font-size: 13px;
		letter-spacing: 0.3px;
		padding: 14px 14px;
		gap: 8px;
	}
}

.kfy-hero__certs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2);
	margin-top: var(--sp-5);
}
.kfy-hero__cert {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	background: rgba(198, 187, 60, 0.1);
	color: var(--color-gold);
	border: 1px solid rgba(198, 187, 60, 0.3);
	padding: 6px 12px;
	border-radius: var(--radius-sm);
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1px;
}

.kfy-hero__coverage {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: var(--sp-4) 0 0;
	list-style: none;
	padding: 0;
}
.kfy-hero__coverage li {
	font-size: 14px;
	font-weight: 700;
	letter-spacing: 0.4px;
	background: rgba(58, 29, 56, 0.85); /* eggplant chip on warm hero */
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	color: var(--color-cream);
	padding: 5px 12px;
	border: 1px solid rgba(198, 187, 60, 0.55);
	border-radius: var(--radius-full);
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

/* Lead form mockup (right column on desktop) */
.kfy-hero__form-col {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	padding-bottom: 60px;
}
.kfy-hero__form-wrap {
	background: linear-gradient(160deg, var(--color-cream), #efe6cb);
	color: var(--text-on-light);
	border-radius: var(--radius-xl);
	padding: var(--sp-6);
	box-shadow: var(--shadow-xl);
	border: 1px solid rgba(142, 68, 32, 0.2);
	position: relative;
	overflow: hidden;
}
.kfy-hero__form-wrap::before {
	content: "";
	position: absolute;
	top: -40px; right: -40px;
	width: 180px; height: 180px;
	background: radial-gradient(circle, rgba(198, 187, 60, 0.4), transparent 70%);
	border-radius: 50%;
}

.kfy-hero__form-heading {
	font-family: var(--font-display);
	color: var(--color-warm-brown);
	margin: 0 0 var(--sp-2);
	font-size: clamp(22px, 2vw + 1rem, 28px);
	text-transform: uppercase;
}
.kfy-hero__form-sub {
	margin: 0 0 var(--sp-5);
	color: var(--text-muted);
	font-size: 15px;
}

.kfy-hero__form {
	display: grid;
	gap: var(--sp-3);
	position: relative;
}
.kfy-hero__form label {
	display: block;
	font-size: 14px;
	font-family: var(--font-display);
	letter-spacing: 1px;
	text-transform: uppercase;
	color: var(--color-dark-brown);
	margin-bottom: 6px;
}
.kfy-hero__form input,
.kfy-hero__form select,
.kfy-hero__form textarea {
	width: 100%;
	padding: 14px 14px;
	border: 1px solid rgba(142, 68, 32, 0.3);
	background: #fff;
	color: var(--color-dark-brown);
	border-radius: var(--radius-md);
	font-family: var(--font-body);
	/* 17px is well above the 16px iOS auto-zoom threshold and matches the
	   site's enhanced ADA-friendly body floor. */
	font-size: 17px;
	transition: border-color var(--ease-default), box-shadow var(--ease-default);
}
.kfy-hero__form input:focus,
.kfy-hero__form select:focus,
.kfy-hero__form textarea:focus {
	outline: none;
	border-color: var(--color-gold);
	box-shadow: 0 0 0 3px rgba(198, 187, 60, 0.25);
}

.kfy-hero__form-note {
	font-size: 14px;
	color: var(--text-muted);
	margin: 6px 0 0;
	text-align: center;
	font-style: italic;
	line-height: 1.5;
}

/* Hero kangaroo mascot — sits in the bottom-right of the hero, peeking
   from behind the form card. The mascot uses a NEGATIVE right offset
   so it sits past the form-col's right edge and out into the hero
   gutter, giving it more visual presence. The hero itself is
   overflow:hidden, so the mascot can never escape the hero box.
   Bottom offset is tuned so the tail and feet stay fully inside the
   hero (the hero min-height was bumped to give us extra room). */
.kfy-hero__mascot {
	position: absolute;
	right: -80px;
	bottom: -40px;
	width: 150px;
	height: auto;
	z-index: 5;
	filter: drop-shadow(0 14px 28px rgba(41, 22, 16, 0.55));
	animation: kfy-float 4s ease-in-out infinite;
	pointer-events: none;
}
@media (min-width: 768px) {
	.kfy-hero__mascot {
		width: 180px;
		right: -110px;
		bottom: -50px;
	}
}
@media (min-width: 1200px) {
	.kfy-hero__mascot {
		width: 200px;
		right: -140px;
		bottom: -55px;
	}
}
@media (min-width: 1440px) {
	.kfy-hero__mascot { width: 230px; right: -170px; bottom: -60px; }
}

@media (min-width: 992px) {
	.kfy-hero__inner {
		grid-template-columns: 1.2fr 1fr;
		gap: var(--sp-10);
	}
}

/* =========================================================================
   404 - PAGE NOT FOUND
   ========================================================================= */
.kfy-404 {
	position: relative;
	overflow: hidden;
	background-color: var(--pdu-eggplant-deep);
	background-image:
		radial-gradient(ellipse at 50% 0%, rgba(247, 199, 59, 0.18), transparent 55%),
		linear-gradient(180deg, #4A2426 0%, var(--pdu-eggplant) 60%, var(--pdu-eggplant-deep) 100%);
	background-size: cover;
	background-position: center 40%;
	background-repeat: no-repeat;
	color: var(--color-cream);
	min-height: calc(100svh - var(--kfy-header-h, 130px));
	display: flex;
	align-items: center;
	padding: clamp(var(--sp-8), 6vw, var(--sp-12)) 0;
}
.kfy-404::before {
	content: "";
	position: absolute;
	inset: 0;
	background:
		radial-gradient(ellipse at 80% 0%, rgba(198, 187, 60, 0.16), transparent 60%),
		radial-gradient(ellipse at 0% 100%, rgba(142, 68, 32, 0.30), transparent 60%);
	pointer-events: none;
	z-index: 1;
}
.kfy-404__inner {
	position: relative;
	z-index: 2;
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
	padding-inline: var(--sp-5);
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-8);
	align-items: center;
}
@media (min-width: 992px) {
	.kfy-404__inner {
		grid-template-columns: 1.4fr 1fr;
		gap: var(--sp-10);
	}
}

.kfy-404__content { max-width: 640px; }

.kfy-404__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	background: rgba(142, 68, 32, 0.4);
	border: 1px solid rgba(198, 187, 60, 0.4);
	color: var(--color-cream);
	padding: 6px 14px;
	border-radius: var(--radius-full);
	font-family: var(--font-display);
	text-transform: uppercase;
	letter-spacing: 1.5px;
	font-size: 14px;
	margin-bottom: var(--sp-5);
}
.kfy-404__eyebrow .kfy-icon { color: var(--color-gold); }

.kfy-404__numerals {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	font-family: var(--font-display);
	font-size: clamp(96px, 18vw, 200px);
	line-height: 0.85;
	color: var(--color-gold);
	margin: 0 0 var(--sp-4);
	text-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);
}
.kfy-404__numerals-paw {
	display: inline-grid;
	place-items: center;
	width: clamp(80px, 14vw, 160px);
	height: clamp(80px, 14vw, 160px);
	background: linear-gradient(135deg, var(--color-warm-brown), var(--color-burnt-orange));
	color: var(--color-cream);
	border-radius: 50%;
	box-shadow: 0 12px 32px rgba(41, 22, 16, 0.55);
	animation: kfy-pulse 3s ease-in-out infinite;
}
.kfy-404__numerals-paw .kfy-icon { width: 60%; height: 60%; }

.kfy-404__title {
	margin: 0 0 var(--sp-4);
	font-size: clamp(28px, 4vw + 0.5rem, 52px);
	line-height: 1.05;
	font-family: var(--font-display);
	text-transform: uppercase;
}
.kfy-404__title span { color: var(--color-gold); display: block; }

.kfy-404__subtitle {
	font-size: clamp(17px, 0.6vw + 16px, 20px);
	color: rgba(248, 243, 224, 0.85);
	margin: 0 0 var(--sp-6);
	line-height: 1.65;
}

.kfy-404__ctas {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-3);
	margin-bottom: var(--sp-6);
}

.kfy-404__helpful {
	background: rgba(11, 20, 24, 0.55);
	border: 1px solid rgba(198, 187, 60, 0.18);
	border-radius: var(--radius-lg);
	padding: var(--sp-4) var(--sp-5);
	margin-bottom: var(--sp-5);
}
.kfy-404__helpful-label {
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1.5px;
	text-transform: uppercase;
	color: var(--color-gold);
	margin: 0 0 var(--sp-3);
}
.kfy-404__helpful-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--sp-2) var(--sp-4);
}
@media (max-width: 540px) {
	.kfy-404__helpful-list { grid-template-columns: 1fr; }
}
.kfy-404__helpful-list a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--color-cream);
	font-size: 16px;
	padding: 8px 0;
	transition: color var(--ease-default), transform var(--ease-default);
}
.kfy-404__helpful-list a:hover {
	color: var(--color-gold);
	transform: translateX(3px);
}
.kfy-404__helpful-list .kfy-icon { color: var(--color-gold); }

.kfy-404__call {
	font-size: 16px;
	color: rgba(248, 243, 224, 0.7);
	margin: 0;
}
.kfy-404__call a {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	color: var(--color-gold);
	font-family: var(--font-display);
	letter-spacing: 0.5px;
	margin-left: 4px;
}
.kfy-404__call a:hover { color: var(--color-cream); }

.kfy-404__mascot-wrap {
	position: relative;
	display: grid;
	place-items: center;
	min-height: 260px;
}
.kfy-404__mascot {
	width: 100%;
	max-width: 340px;
	height: auto;
	filter: drop-shadow(0 18px 36px rgba(0, 0, 0, 0.55));
	animation: kfy-float 4s ease-in-out infinite;
}
.kfy-404__mascot-bubble {
	position: absolute;
	top: 8%;
	right: 0;
	background: var(--color-cream);
	color: var(--color-warm-brown);
	font-family: var(--font-display);
	text-transform: uppercase;
	letter-spacing: 1px;
	font-size: 15px;
	padding: 10px 18px;
	border-radius: var(--radius-full);
	box-shadow: var(--shadow-lg);
	border: 2px solid var(--color-gold);
	transform: rotate(-6deg);
}
.kfy-404__mascot-bubble::after {
	content: "";
	position: absolute;
	bottom: -8px;
	left: 22px;
	width: 16px;
	height: 16px;
	background: var(--color-cream);
	border-right: 2px solid var(--color-gold);
	border-bottom: 2px solid var(--color-gold);
	transform: rotate(45deg);
}
@media (max-width: 991px) {
	.kfy-404__mascot-wrap { order: -1; min-height: 220px; }
	.kfy-404__mascot { max-width: 240px; }
}

/* =========================================================================
   QUICK ACTIONS - Compact strip between hero and reviews
   ========================================================================= */
.kfy-quick-actions {
	position: relative;
	background: linear-gradient(180deg, var(--bg-secondary) 0%, var(--bg-primary) 100%);
	padding: var(--sp-6) 0;
	border-top: 1px solid rgba(198, 187, 60, 0.15);
	border-bottom: 1px solid rgba(198, 187, 60, 0.15);
}
.kfy-quick-actions__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-3);
}
@media (min-width: 600px) { .kfy-quick-actions__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 992px) { .kfy-quick-actions__grid { grid-template-columns: repeat(4, 1fr); } }

.kfy-qa-tile,
.kfy-qa-tile:hover,
.kfy-qa-tile:focus,
.kfy-qa-tile:focus-visible,
.kfy-qa-tile:active {
	/* Quick-action tiles are full-card surfaces, not link runs of body
	   copy — the global `a:hover { text-decoration: underline }` rule
	   would otherwise stripe the entire label/subtext on hover, which
	   reads as broken UI. Force-suppress it across every state. */
	text-decoration: none;
}
.kfy-qa-tile {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: center;
	gap: var(--sp-3);
	padding: var(--sp-4) var(--sp-4);
	background: rgba(248, 243, 224, 0.04);
	border: 1px solid rgba(248, 243, 224, 0.1);
	border-radius: var(--radius-lg);
	color: var(--color-cream);
	transition: transform var(--ease-default), background var(--ease-default), border-color var(--ease-default), box-shadow var(--ease-default);
	min-height: 88px;
}
.kfy-qa-tile:hover {
	transform: translateY(-3px);
	background: rgba(248, 243, 224, 0.08);
	border-color: var(--color-gold);
	box-shadow: var(--shadow-md);
	color: var(--color-cream);
}

.kfy-qa-tile__icon {
	width: 48px;
	height: 48px;
	display: grid;
	place-items: center;
	border-radius: var(--radius-md);
	background: linear-gradient(135deg, var(--color-warm-brown), var(--color-burnt-orange));
	color: var(--color-cream);
	flex-shrink: 0;
	transition: transform var(--ease-default);
}
.kfy-qa-tile:hover .kfy-qa-tile__icon { transform: scale(1.05) rotate(-3deg); }

.kfy-qa-tile__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kfy-qa-tile__label {
	font-family: var(--font-display);
	font-size: 16px;
	letter-spacing: 0.5px;
	text-transform: uppercase;
	color: var(--color-cream);
	line-height: 1.1;
}
.kfy-qa-tile__subtext {
	font-size: 14px;
	color: rgba(248, 243, 224, 0.7);
	line-height: 1.45;
}

.kfy-qa-tile__arrow {
	color: var(--color-gold);
	opacity: 0.6;
	transition: opacity var(--ease-default), transform var(--ease-default);
}
.kfy-qa-tile:hover .kfy-qa-tile__arrow {
	opacity: 1;
	transform: translateX(4px);
}

/* Glove-red highlight tile — same palette as .kfy-btn--primary so the
   "Get a Free Quote" tile reads as the same conversion ladder rung as
   every other primary CTA on the page. Cream type + dark text-shadow
   for readability on the bright red. */
.kfy-qa-tile--highlight {
	background: linear-gradient(135deg, var(--pdu-glove-light) 0%, var(--pdu-glove) 55%, var(--pdu-glove-deep) 100%);
	border-color: var(--pdu-glove-light);
	color: var(--pdu-cream);
	box-shadow:
		0 6px 18px rgba(178, 58, 44, 0.45),
		inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.kfy-qa-tile--highlight:hover {
	background: linear-gradient(135deg, var(--pdu-glove-light), var(--pdu-glove));
	color: var(--pdu-cream);
	border-color: var(--pdu-cream);
	box-shadow:
		0 10px 28px rgba(178, 58, 44, 0.55),
		inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.kfy-qa-tile--highlight .kfy-qa-tile__icon {
	background: rgba(15, 8, 6, 0.35);
	color: var(--pdu-cream);
}
.kfy-qa-tile--highlight .kfy-qa-tile__label,
.kfy-qa-tile--highlight .kfy-qa-tile__subtext { color: var(--pdu-cream); }
.kfy-qa-tile--highlight .kfy-qa-tile__subtext { color: rgba(251, 239, 217, 0.85); }
.kfy-qa-tile--highlight .kfy-qa-tile__arrow { color: var(--pdu-cream); opacity: 0.9; }

/* =========================================================================
   BLOCK 3 - SOCIAL PROOF
   ========================================================================= */
.kfy-social-proof {
	position: relative;
	background: var(--bg-secondary);
	/* New stacking context so the ::before scenery stays trapped behind
	   the section's content (review cards, badges, CTA) regardless of
	   what z-indices those children declare. */
	isolation: isolate;
	overflow: hidden;
}
/* Savanna scenery wash. Cream gradient stays dominant — the vector
   scene only whispers through the lower edge as a tonal hint of the
   warm horizon, never as foreground artwork. multiply blends the
   sunset palette into the cream surface so the cards/CTA always read
   on a calm cream backdrop, not a busy illustration. */
.kfy-social-proof::before {
	content: "";
	position: absolute;
	inset: 0;
	background-image:
		linear-gradient(
			180deg,
			var(--bg-secondary) 0%,
			rgba(251, 239, 217, 0.96) 25%,
			rgba(251, 239, 217, 0.85) 60%,
			rgba(251, 239, 217, 0.65) 100%
		),
		url('../img/vector scene.jpg');
	background-size: 100% auto, cover;
	background-position: top center, center bottom;
	background-repeat: no-repeat, no-repeat;
	mix-blend-mode: multiply;
	opacity: 0.75;
	pointer-events: none;
	z-index: 0;
}
.kfy-social-proof .kfy-review-card,
.kfy-social-proof .kfy-reviews__cell { isolation: isolate; }
.kfy-social-proof > * { position: relative; z-index: 1; }

/* Breathing room between the section header and the Google/Facebook badges,
   and between the badges and the review cards below. */
.kfy-social-proof .kfy-review-badges {
	margin-top: var(--sp-6);
	margin-bottom: var(--sp-8);
}
@media (max-width: 600px) {
	.kfy-social-proof .kfy-review-badges {
		margin-top: var(--sp-5);
		margin-bottom: var(--sp-6);
	}
}

/* ---- Review badges (Google + Facebook) ---- */
.kfy-review-badges {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--sp-4);
	margin: 0 auto var(--sp-8);
	max-width: 720px;
}

.kfy-review-badge {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: var(--sp-3);
	padding: 12px 20px 12px 14px;
	background: var(--color-cream);
	color: var(--text-on-light);
	border-radius: var(--radius-lg);
	border: 1px solid rgba(189, 188, 188, 0.4);
	box-shadow: 0 6px 20px rgba(58, 31, 18, 0.18);
	text-decoration: none;
	transition: transform var(--ease-default), box-shadow var(--ease-default), border-color var(--ease-default);
	min-width: 240px;
}
.kfy-review-badge:hover {
	transform: translateY(-3px);
	box-shadow: 0 12px 32px rgba(58, 31, 18, 0.28);
	border-color: var(--kfy-badge-accent, rgba(189, 188, 188, 0.4));
	/* v2.8: The base `.kfy-review-badge` rule already declares
	   text-decoration: none, but the global `a:hover` (line ~348)
	   re-applies an underline on every <a>, so the badge text was
	   getting underlined as soon as the user moused over. Re-asserting
	   `text-decoration: none` on hover (and matching color so the link
	   colour swap from the global rule doesn't flicker either) keeps
	   the badge looking like a chip, not a hyperlink. */
	text-decoration: none;
	color: var(--text-on-light);
}
.kfy-review-badge:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 3px;
}
.kfy-review-badge.is-static {
	cursor: default;
}
.kfy-review-badge.is-static:hover {
	transform: none;
	box-shadow: 0 6px 20px rgba(58, 31, 18, 0.18);
}

.kfy-review-badge--google   { --kfy-badge-accent: #4285F4; }
.kfy-review-badge--facebook { --kfy-badge-accent: #1877F2; }

.kfy-review-badge__logo {
	flex-shrink: 0;
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	background: #fff;
	border-radius: 50%;
	box-shadow: inset 0 0 0 1px rgba(58, 31, 18, 0.08);
}
.kfy-review-badge__logo svg { display: block; }

.kfy-review-badge__content {
	display: flex;
	flex-direction: column;
	gap: 2px;
	line-height: 1.1;
	/* Allow this flex child to shrink below its intrinsic content width so
	   long labels like "FACEBOOK REVIEWS" can wrap instead of pushing the
	   badge past its container. */
	min-width: 0;
	flex: 1 1 auto;
}
.kfy-review-badge__label {
	overflow-wrap: anywhere;
}
.kfy-review-badge__top {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}
.kfy-review-badge__score {
	font-family: var(--font-display);
	font-size: 22px;
	font-weight: 700;
	color: var(--color-near-black);
	letter-spacing: 0.5px;
}
.kfy-review-badge__stars {
	display: inline-flex;
	align-items: center;
	gap: 1px;
	color: var(--color-gold);
}
.kfy-review-badge__stars .kfy-icon { width: 16px; height: 16px; }
.kfy-review-badge__label {
	font-size: 14px;
	text-transform: uppercase;
	letter-spacing: 1.5px; /* 0.107em - meets caps tracking floor */
	color: var(--text-muted);
	font-family: var(--font-display);
}

@media (max-width: 600px) {
	/* Two columns on mobile so Google + Facebook always sit side by side.
	   The compact (--compact) and micro (--micro) variants set their own
	   display rules below and are unaffected. */
	.kfy-social-proof .kfy-review-badges {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: 10px;
		max-width: 520px;
		margin-inline: auto;
	}
	.kfy-social-proof .kfy-review-badge {
		min-width: 0;
		width: 100%;
		max-width: none;
		padding: 10px 12px 10px 10px;
		gap: 8px;
		border-radius: 14px;
	}
	.kfy-social-proof .kfy-review-badge__logo { width: 36px; height: 36px; }
	.kfy-social-proof .kfy-review-badge__score { font-size: 18px; }
	.kfy-social-proof .kfy-review-badge__top { gap: 6px; flex-wrap: wrap; }
	.kfy-social-proof .kfy-review-badge__stars { gap: 0; }
	.kfy-social-proof .kfy-review-badge__stars .kfy-icon { width: 12px; height: 12px; }
	.kfy-social-proof .kfy-review-badge__label {
		font-size: 14px;
		letter-spacing: 0.6px;
		/* Allow wrap so "FACEBOOK REVIEWS" doesn't overflow the chip on
		   narrow viewports. */
		white-space: normal;
		line-height: 1.15;
	}
}

/* Compact variant - used in tight contexts like the hero. Always 2 columns. */
.kfy-review-badges--compact {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 10px;
	max-width: 480px;
	margin: 0 0 var(--sp-4); /* left-aligned by default; mobile media query re-centers */
}
.kfy-review-badges--compact .kfy-review-badge {
	min-width: 0;
	gap: 8px;
	padding: 8px 12px 8px 8px;
	border-radius: 12px;
	box-shadow: 0 4px 14px rgba(58, 31, 18, 0.22);
}
.kfy-review-badges--compact .kfy-review-badge__logo {
	width: 32px;
	height: 32px;
}
.kfy-review-badges--compact .kfy-review-badge__score {
	font-size: 16px;
}
.kfy-review-badges--compact .kfy-review-badge__top { gap: 5px; flex-wrap: wrap; }
.kfy-review-badges--compact .kfy-review-badge__stars { gap: 0; }
.kfy-review-badges--compact .kfy-review-badge__stars .kfy-icon { width: 11px; height: 11px; }
.kfy-review-badges--compact .kfy-review-badge__label {
	font-size: 14px;
	letter-spacing: 0.4px;
	/* Wrap to 2 lines instead of overflowing the chip. */
	white-space: normal;
	line-height: 1.15;
}

/* Micro variant - used in the topbar. Single-line pill, no label. */
.kfy-review-badges--micro {
	display: inline-flex;
	gap: 8px;
	margin: 0;
	max-width: none;
}
.kfy-review-badges--micro .kfy-review-badge {
	min-width: 0;
	gap: 6px;
	padding: 3px 10px 3px 4px;
	border-radius: var(--radius-full);
	border: 1px solid rgba(248, 243, 224, 0.18);
	background: rgba(248, 243, 224, 0.06);
	box-shadow: none;
	color: var(--color-cream);
}
.kfy-review-badges--micro .kfy-review-badge:hover {
	transform: none;
	background: rgba(248, 243, 224, 0.10);
	border-color: var(--kfy-badge-accent, rgba(198, 187, 60, 0.6));
	box-shadow: none;
}
.kfy-review-badges--micro .kfy-review-badge.is-static:hover {
	box-shadow: none;
}
.kfy-review-badges--micro .kfy-review-badge__logo {
	width: 22px;
	height: 22px;
	box-shadow: inset 0 0 0 1px rgba(58, 31, 18, 0.12);
}
.kfy-review-badges--micro .kfy-review-badge__score {
	font-size: 14px;
	letter-spacing: 0.3px;
	color: var(--color-cream);
	line-height: 1;
	display: inline-flex;
	align-items: center;
}
.kfy-review-badges--micro .kfy-review-badge__stars {
	gap: 0;
	line-height: 1;
	align-items: center;
}
.kfy-review-badges--micro .kfy-review-badge__stars .kfy-icon {
	width: 9px;
	height: 9px;
	display: block;
}

.kfy-reviews {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-5);
}
@media (min-width: 768px) { .kfy-reviews { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .kfy-reviews { grid-template-columns: repeat(3, 1fr); } }

.kfy-review {
	background: var(--color-cream);
	color: var(--text-on-light);
	border-radius: var(--radius-lg);
	padding: var(--sp-5);
	box-shadow: var(--shadow-md);
	border: 1px solid rgba(189, 188, 188, 0.3);
	transition: transform var(--ease-default), box-shadow var(--ease-default);
	position: relative;
}
.kfy-review:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
.kfy-review--featured {
	border: 2px solid var(--color-gold);
	box-shadow: 0 8px 32px rgba(198, 187, 60, 0.25);
}
.kfy-review--faded { opacity: 0.85; }

.kfy-review__head {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	margin-bottom: var(--sp-3);
}
.kfy-review__avatar {
	width: 44px; height: 44px;
	display: grid; place-items: center;
	border-radius: 50%;
	background: linear-gradient(135deg, var(--color-warm-brown), var(--color-burnt-orange));
	color: var(--color-cream);
	font-family: var(--font-display);
	font-weight: bold;
	font-size: 16px;
}
.kfy-review__name { font-family: var(--font-display); text-transform: uppercase; font-size: 17px; margin: 0; line-height: 1.15; }
.kfy-review__meta { font-size: 14px; color: var(--text-muted); margin: 2px 0 0; }
.kfy-review__stars { color: var(--color-gold); display: flex; gap: 2px; margin-bottom: var(--sp-2); }
.kfy-review__quote { font-size: 17px; line-height: 1.6; margin: 0 0 var(--sp-3); color: var(--color-dark-brown); }
.kfy-review__date { font-size: 14px; color: var(--text-muted); }

.kfy-social-proof__cta {
	text-align: center;
	margin-top: var(--sp-8);
}
.kfy-social-proof__cta a {
	color: var(--color-gold);
	font-family: var(--font-display);
	letter-spacing: 1px;
	text-transform: uppercase;
	font-size: 15px;
	border-bottom: 1px solid var(--color-gold);
	padding-bottom: 2px;
}

/* =========================================================================
   BLOCK 4 - SERVICES
   ========================================================================= */
.kfy-services {
	background: var(--bg-light);
	color: var(--text-on-light);
	position: relative;
	overflow: hidden;
	isolation: isolate;
	/* v2.5: Extra top padding so the warm ribbon coming out of About
	   Overview has air to breathe before the Services eyebrow. */
	padding-top: clamp(var(--sp-12), 9vw, var(--sp-14));
}
/* v2.5: Subtle warm wash at the top of Services that picks up where the
   About Overview ribbon leaves off, so the eye reads one continuous
   warm transition rather than two unrelated cream slabs. */
.kfy-services::before {
	content: "";
	position: absolute;
	top: 0; left: 0; right: 0;
	height: 80px;
	background: linear-gradient(
		180deg,
		rgba(247, 199, 59, 0.10) 0%,
		rgba(247, 199, 59, 0) 100%
	);
	pointer-events: none;
	z-index: 0;
}

/* =========================================================================
   Halftone accents — vintage print-style dot patches in two diagonal
   corners (top-right + bottom-left) so the cream slab has visual
   rhythm without competing with the service cards. The pattern is a
   single radial-gradient tile (warm brown dots on transparent) that's
   masked into a soft circular fade so it dissolves into the bg.

   ADA: pointer-events:none + aria-hidden via decorative pseudo-element
   so screen readers and click targets are unaffected.
   ========================================================================= */
.kfy-services::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: 0;
	/* Two stacked dot layers in opposite corners. Each layer is a
	   radial-gradient tile sized to ~18px so the dots read as a
	   distinct "screen" pattern instead of a noisy texture. */
	background-image:
		/* Top-right halftone patch — warm brown */
		radial-gradient(circle, rgba(142, 68, 32, 0.55) 1.6px, transparent 2.2px),
		/* Bottom-left halftone patch — sunset orange */
		radial-gradient(circle, rgba(247, 199, 59, 0.55) 1.6px, transparent 2.2px);
	background-size: 18px 18px, 22px 22px;
	background-position: 100% 0%, 0% 100%;
	background-repeat: repeat, repeat;
	/* Mask each layer into a soft, off-canvas circular fade so the
	   dots only show in the targeted corner and dissolve elegantly
	   into the cream bg toward the center. */
	-webkit-mask-image:
		radial-gradient(circle at 100% 0%, #000 0%, transparent 38%),
		radial-gradient(circle at 0% 100%, #000 0%, transparent 42%);
	mask-image:
		radial-gradient(circle at 100% 0%, #000 0%, transparent 38%),
		radial-gradient(circle at 0% 100%, #000 0%, transparent 42%);
	-webkit-mask-composite: source-over;
	mask-composite: add;
	opacity: 0.85;
}
@media (max-width: 600px) {
	/* On small viewports the patches dominate the slab — shrink the
	   tile + fade radius so they read as small accents instead of a
	   wallpaper. */
	.kfy-services::after {
		background-size: 14px 14px, 16px 16px;
		-webkit-mask-image:
			radial-gradient(circle at 100% 0%, #000 0%, transparent 28%),
			radial-gradient(circle at 0% 100%, #000 0%, transparent 32%);
		mask-image:
			radial-gradient(circle at 100% 0%, #000 0%, transparent 28%),
			radial-gradient(circle at 0% 100%, #000 0%, transparent 32%);
	}
}

.kfy-services > .kfy-container { position: relative; z-index: 1; }

.kfy-services__grid {
	display: grid;
	gap: var(--sp-6);
	grid-template-columns: 1fr;
}
@media (min-width: 768px) { .kfy-services__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .kfy-services__grid { grid-template-columns: repeat(3, 1fr); } }

.kfy-service-card {
	background: #fff;
	border-radius: var(--radius-lg);
	overflow: hidden;
	box-shadow: var(--shadow-md);
	border: 1px solid rgba(142, 68, 32, 0.12);
	display: flex;
	flex-direction: column;
	transition: transform var(--ease-default), box-shadow var(--ease-default), border-color var(--ease-default);
	position: relative;
}
.kfy-service-card::before {
	content: "";
	position: absolute;
	top: 14px; right: 14px;
	width: 28px; height: 28px;
	background: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238E4420' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z'/%3E%3C/svg%3E") center / contain no-repeat;
	opacity: 0.2;
	transition: transform var(--ease-default), opacity var(--ease-default);
	z-index: 2;
}
.kfy-service-card:hover {
	transform: translateY(-6px);
	box-shadow: var(--shadow-lg);
	border-color: var(--color-warm-brown);
}
.kfy-service-card:hover::before { opacity: 0.55; transform: rotate(20deg) scale(1.1); }

.kfy-service-card__image {
	width: 100%;
	height: 200px;
	background: linear-gradient(135deg, var(--color-deep-brown), var(--color-warm-brown));
	background-size: cover;
	background-position: center;
	position: relative;
}
.kfy-service-card__image::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(180deg, transparent 50%, rgba(41, 22, 16, 0.5));
}

.kfy-service-card__body {
	padding: var(--sp-6);
	display: flex;
	flex-direction: column;
	flex: 1;
}

.kfy-service-card__icon {
	width: 56px; height: 56px;
	margin: -56px 0 var(--sp-4);
	background: linear-gradient(135deg, var(--color-gold), var(--color-burnt-orange));
	color: var(--color-near-black);
	border-radius: var(--radius-md);
	display: grid;
	place-items: center;
	font-size: 26px;
	box-shadow: var(--shadow-md);
	position: relative;
	z-index: 3;
}

.kfy-service-card__title {
	margin: 0 0 var(--sp-3);
	color: var(--color-dark-brown);
	font-size: clamp(20px, 1.5vw + 1rem, 26px);
	/* v2.8: Force this title onto the body sans stack instead of
	   --font-accent (Super Cedar). Super Cedar's bundled file ships
	   without digit glyphs (see the @font-face block near the top of
	   this stylesheet), and the local()-only digits fallback declared
	   beside it can silently fail when none of Georgia/Times/Cambria/
	   Noto Serif resolve — which is what was making "24/7 Emergency
	   Plumbing" render as "2 / Emergency Plumbing" (the 4 and 7 just
	   disappeared). The v2.5 attempt with font-variant-numeric only
	   helps when the font ships those numerals at all; here it doesn't.
	   System sans always has every digit, slash, and accented char,
	   so we trade a bit of brand voice on this one heading for a
	   guaranteed-readable title. Heavier weight + tighter line-height
	   keep it reading as a proper card title rather than body copy. */
	font-family: var(--font-body);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.2;
	font-variant-numeric: lining-nums tabular-nums;
	font-feature-settings: "lnum" 1, "tnum" 1, "kern" 1;
	text-wrap: balance;
}
.kfy-service-card__desc {
	color: var(--text-muted);
	margin: 0 0 var(--sp-5);
	flex: 1;
}
.kfy-service-card__link {
	color: var(--color-warm-brown);
	font-family: var(--font-display);
	text-transform: uppercase;
	letter-spacing: 1px;
	font-size: 14px;
	display: inline-flex;
	align-items: center;
	gap: 4px;
}
.kfy-service-card__link:hover { color: var(--color-burnt-orange); gap: 8px; }

/* =========================================================================
   BLOCK 5 - PROCESS
   ========================================================================= */
.kfy-process { background: var(--bg-primary); position: relative; }

.kfy-process__steps {
	display: grid;
	gap: var(--sp-6);
	grid-template-columns: 1fr;
	position: relative;
}
@media (min-width: 768px) {
	.kfy-process__steps { grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
	.kfy-process__steps::before {
		content: "";
		position: absolute;
		top: 38px;
		left: 16.6%;
		right: 16.6%;
		height: 2px;
		background: linear-gradient(90deg, var(--color-gold), var(--color-burnt-orange), var(--color-gold));
		opacity: 0.4;
		z-index: 0;
	}
}

.kfy-step {
	background: linear-gradient(180deg, rgba(58, 29, 56, 0.75), rgba(37, 19, 31, 0.55));
	border: 1px solid rgba(239, 126, 26, 0.25);
	border-radius: var(--radius-lg);
	padding: var(--sp-6);
	text-align: center;
	position: relative;
	z-index: 1;
	backdrop-filter: blur(6px);
}

.kfy-step__num {
	width: 76px;
	height: 76px;
	margin: 0 auto var(--sp-4);
	background: linear-gradient(135deg, var(--color-gold), var(--color-burnt-orange));
	color: var(--color-near-black);
	font-family: var(--font-display);
	font-size: 36px;
	display: grid;
	place-items: center;
	border-radius: 50%;
	box-shadow: 0 0 0 6px rgba(198, 187, 60, 0.15), var(--shadow-gold);
}

.kfy-step__title { margin: 0 0 var(--sp-3); color: var(--color-cream); }
.kfy-step__desc { color: var(--text-secondary); margin: 0 0 var(--sp-5); font-size: 17px; line-height: 1.6; }

.kfy-step__image {
	width: 100%;
	/* v2.6: bumped from 160px → ~200px so the new on-brand process
	   photos (book visit / on-site diagnosis / job done right) read
	   clearly without cropping the people in them. */
	aspect-ratio: 16 / 10;
	height: auto;
	min-height: 180px;
	border-radius: var(--radius-md);
	background-color: var(--color-deep-brown);
	background-size: cover;
	background-position: center;
	box-shadow:
		inset 0 0 0 1px rgba(239, 126, 26, 0.18),
		0 10px 24px -14px rgba(0, 0, 0, 0.55);
	margin-top: auto;
}
.kfy-step__image--placeholder {
	background-image: linear-gradient(135deg, var(--color-deep-brown), var(--color-dark-brown));
}

/* ---- Post-steps CTA pair ------------------------------------------------
   Sits below the timeline as the natural conversion punch line: "you've
   seen the 3 steps, here's how to start step 1". Tagline above carries
   the brand voice; the buttons below lead with the Get-Quote action and
   offer the phone as a faster fallback. The whole block is centered and
   capped so it reads as a single matched pair rather than two stray
   buttons floating in the section. */
.kfy-process__cta {
	margin-top: clamp(var(--sp-7), 6vw, var(--sp-9));
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--sp-4);
	text-align: center;
}
.kfy-process__cta-tagline {
	margin: 0;
	font-family: var(--font-display);
	text-transform: uppercase;
	letter-spacing: 1.6px;
	font-size: clamp(15px, 0.4vw + 14px, 17px);
	color: var(--pdu-sunset-yellow);
}
.kfy-process__cta-buttons {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: stretch;
	gap: var(--sp-3);
	width: 100%;
	max-width: 620px;
}
/* Override the global .kfy-btn lockup for this constrained pair. The
   shared rules use white-space: nowrap + 18/36 px padding (kfy-btn--lg)
   which causes long labels (e.g. "Get Free Quote") to overflow the
   pill inside a half-width flex cell. We mirror the recipe used by the
   hero CTAs so both rows of buttons feel like one design system:
   - allow natural wrapping with text-wrap: balance (so 2-line fallback
     stays evenly split instead of orphaning a single word)
   - drop letter-spacing 1px → 0.4px and step font 18 → 15px so two
     short words ("GET FREE QUOTE" / "CALL (512) 555-0142") fit on one
     line at the typical desktop column width
   - tighten padding so the icon + text live INSIDE the rounded fill,
     not bleeding past it
   - min-width: 0 so the flex cell can actually shrink past the
     content's intrinsic width when wrapping is needed. */
.kfy-process__cta-buttons > .kfy-btn {
	flex: 1 1 240px;
	justify-content: center;
	min-width: 0;
	padding: 16px 22px;
	font-size: clamp(14px, 0.45vw + 12px, 16px);
	letter-spacing: 0.4px;
	line-height: 1.2;
	min-height: 56px;
	white-space: normal;
	text-wrap: balance;
	hyphens: none;
	overflow-wrap: normal;
	word-break: normal;
	border-radius: var(--radius-md);
}
/* Phone button reads as one continuous "CALL (512) 555-0142" line.
   The whole label sits in a single <span> so the number can never
   detach from its prefix; tabular-nums + nowrap on that span keep
   "(512) 555-0142" intact even when the cell is narrow. */
.kfy-process__cta-call {
	gap: 10px;
}
.kfy-process__cta-call > span {
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}
@media (max-width: 480px) {
	.kfy-process__cta-buttons > .kfy-btn { flex-basis: 100%; }
}

/* The primary + outline buttons inside this pair both inherit the
   global glove-red recipe automatically (see .kfy-btn--primary and
   .kfy-btn--outline near the top of this stylesheet). No scoped
   colour overrides needed here — the only process-specific tweaks
   live above (padding/wrapping/min-width) and target both buttons
   uniformly via .kfy-process__cta-buttons > .kfy-btn. */

/* =========================================================================
   BLOCK 6 - TRUST
   ========================================================================= */
.kfy-trust {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	background-color: var(--pdu-eggplant);
	/* Eggplant base + warm orange glow top-right keeps the section feeling
	   warm-sunny while the eggplant base supplies the "touch of dark"
	   anchor that the maroon-only fallback was missing. */
	background-image:
		radial-gradient(ellipse at 100% 0%, rgba(239, 126, 26, 0.14), transparent 55%),
		linear-gradient(180deg, var(--pdu-maroon) 0%, var(--pdu-eggplant) 60%, var(--pdu-eggplant-deep) 100%);
}
/* =========================================================================
   Halftone accents — vintage print-style dot patches in two diagonal
   corners, same recipe as .kfy-services but recoloured for the dark
   eggplant slab: cream dots top-right and sunset-yellow dots bottom-
   left so they actually read against the deep maroon → eggplant
   gradient. Masked into soft circular fades so the centre of the
   section stays clean and the trust points / owner photo / stats /
   cert pills always read first.
   ========================================================================= */
.kfy-trust::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: 0;
	background-image:
		/* Top-right halftone patch — soft cream */
		radial-gradient(circle, rgba(251, 239, 217, 0.55) 1.6px, transparent 2.2px),
		/* Bottom-left halftone patch — sunset orange */
		radial-gradient(circle, rgba(247, 199, 59, 0.55) 1.6px, transparent 2.2px);
	background-size: 18px 18px, 22px 22px;
	background-position: 100% 0%, 0% 100%;
	background-repeat: repeat, repeat;
	-webkit-mask-image:
		radial-gradient(circle at 100% 0%, #000 0%, transparent 38%),
		radial-gradient(circle at 0% 100%, #000 0%, transparent 42%);
	mask-image:
		radial-gradient(circle at 100% 0%, #000 0%, transparent 38%),
		radial-gradient(circle at 0% 100%, #000 0%, transparent 42%);
	-webkit-mask-composite: source-over;
	mask-composite: add;
	opacity: 0.85;
}
@media (max-width: 600px) {
	.kfy-trust::before {
		background-size: 14px 14px, 16px 16px;
		-webkit-mask-image:
			radial-gradient(circle at 100% 0%, #000 0%, transparent 28%),
			radial-gradient(circle at 0% 100%, #000 0%, transparent 32%);
		mask-image:
			radial-gradient(circle at 100% 0%, #000 0%, transparent 28%),
			radial-gradient(circle at 0% 100%, #000 0%, transparent 32%);
	}
}
.kfy-trust > * { position: relative; z-index: 1; }

.kfy-trust__split {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-8);
	align-items: start;
}
@media (min-width: 992px) {
	.kfy-trust__split { grid-template-columns: 1.2fr 1fr; gap: var(--sp-10); }
}

.kfy-trust__points {
	display: grid;
	gap: var(--sp-5);
}

.kfy-trust-point {
	display: grid;
	grid-template-columns: 56px 1fr;
	gap: var(--sp-4);
	align-items: start;
}
.kfy-trust-point__icon {
	width: 56px; height: 56px;
	background: linear-gradient(135deg, var(--color-warm-brown), var(--color-burnt-orange));
	color: var(--color-cream);
	border-radius: var(--radius-md);
	display: grid;
	place-items: center;
	font-size: 26px;
}
.kfy-trust-point__title {
	font-family: var(--font-display);
	text-transform: uppercase;
	color: var(--color-cream);
	margin: 0 0 4px;
	font-size: 19px;
	letter-spacing: 0.5px;
}
.kfy-trust-point__desc { color: var(--text-secondary); margin: 0; font-size: 17px; line-height: 1.6; }

.kfy-trust__photo {
	width: 100%;
	/* Portrait orientation — was a near-square 420px box, which made
	   Joey's headshot read as a tightly cropped landscape. A 4:5
	   ratio gives the column a proper magazine-portrait silhouette
	   that balances the multi-row points list on the left without
	   towering over it. min/max-height clamps keep the proportion
	   honest at extreme container widths. */
	aspect-ratio: 4 / 5;
	max-height: 640px;
	min-height: 360px;
	border-radius: var(--radius-xl);
	background:
		radial-gradient(circle at 30% 20%, rgba(198, 187, 60, 0.18), transparent 55%),
		linear-gradient(135deg, var(--color-warm-brown) 0%, var(--color-deep-brown) 100%);
	background-size: cover;
	/* Bias toward the upper third of the source so the subject's
	   face stays anchored when the box gets tall. */
	background-position: center 22%;
	box-shadow: var(--shadow-xl);
	position: relative;
	overflow: hidden;
	border: 3px solid rgba(198, 187, 60, 0.25);
}
@media (min-width: 992px) {
	/* On desktop the photo column gets the smaller share (1fr next to
	   the 1.2fr points column). Allow the portrait to grow taller
	   here so it visually rhymes with the stacked trust points. */
	.kfy-trust__photo { max-height: 720px; }
}
.kfy-trust__photo--mascot {
	display: flex;
	align-items: flex-end;
	justify-content: center;
	padding: var(--sp-4);
}
.kfy-trust__photo--mascot img {
	max-width: 90%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
	filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.4));
	animation: kfy-float 5s ease-in-out infinite;
}

.kfy-trust__stats {
	margin-top: var(--sp-10);
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--sp-5);
	background: linear-gradient(135deg, rgba(142, 68, 32, 0.3), rgba(73, 44, 25, 0.4));
	padding: var(--sp-6);
	border-radius: var(--radius-lg);
	border: 1px solid rgba(198, 187, 60, 0.25);
}
/* v2.7.4: when there are 3 stats on the mobile 2-up grid the third one
   is left alone in the second row, hugging the left column. Span it
   across both tracks and centre it so the orphan stat reads as a
   deliberate row of its own instead of a misaligned leftover. */
.kfy-trust__stats > .kfy-stat:nth-child(3):last-child {
	grid-column: 1 / -1;
	justify-self: center;
}
@media (min-width: 768px) {
	.kfy-trust__stats { grid-template-columns: repeat(3, 1fr); }
	/* Tablet+ restores the 3-column row, so the spanning override above
	   is no longer needed — drop it back to a normal grid item. */
	.kfy-trust__stats > .kfy-stat:nth-child(3):last-child {
		grid-column: auto;
		justify-self: stretch;
	}
}

.kfy-stat { text-align: center; }
.kfy-stat__number {
	font-family: var(--font-display);
	font-size: clamp(36px, 4vw + 1rem, 56px);
	color: var(--color-gold);
	line-height: 1;
}
.kfy-stat__label {
	font-size: 14px;
	color: var(--text-secondary);
	font-family: var(--font-display);
	letter-spacing: 2px;
	text-transform: uppercase;
	margin-top: 6px;
}

.kfy-trust__certs {
	margin-top: var(--sp-8);
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--sp-3);
}
.kfy-trust-cert {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	background: var(--color-gold);
	color: var(--color-near-black);
	padding: 6px 14px;
	border-radius: var(--radius-full);
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1px;
}
.kfy-trust-cert::before {
	content: "";
	display: inline-block;
	width: 6px; height: 6px;
	background: var(--color-near-black);
	border-radius: 50%;
}

/* =========================================================================
   BLOCK 7 - SERVICE AREAS  (Coverage panel: map + overlapping eggplant card)
   =========================================================================
   Visual model:
     ┌─────────────────────────────────────────────────────────────┐
     │                  full-width Leaflet map                     │
     │            (mascot-head pins on every city)                 │
     │                                                             │
     │     ┌───────────────────────────────────────────────┐       │
     │     │                  eggplant card                │       │
     │     │   headline                                    │       │
     │     │   3-col city list (orange map-pins)           │       │
     │     │   primary CTA            ┌────────┐           │       │
     │     │                          │ mascot │           │       │
     │     └──────────────────────────┴────────┴───────────┘       │
     └─────────────────────────────────────────────────────────────┘
   The card is absolutely-margined to overlap the bottom of the map so it
   reads as a single unit instead of two stacked sections. Diagonal stripes
   on the card are pure CSS (no image asset needed). */

.kfy-service-areas {
	background: var(--bg-primary);
	padding: clamp(var(--sp-8), 7vw, var(--sp-12)) 0 0;
}
.kfy-service-areas__header {
	margin-bottom: var(--sp-8);
}

/* ---- Stage that contains both the map and the overlapping card ---- */
.kfy-service-areas__stage {
	position: relative;
	padding-bottom: clamp(var(--sp-10), 12vw, var(--sp-14));
}

/* ---- Map: full width of the page, taller aspect for breathing room ---- */
.kfy-service-areas__map {
	position: relative;
	width: 100%;
	height: clamp(460px, 52vw, 680px);
	background: linear-gradient(135deg, #d8e6ec, #c4d4dd);
	overflow: hidden;
	z-index: 1;
}
/* Fallback shown until/unless Leaflet boots — same shade as the OSM tiles
   so there's no visual flash when the map drops in. */
.kfy-service-areas__map-fallback {
	position: absolute;
	inset: 0;
	background:
		radial-gradient(circle at 30% 35%, rgba(255, 255, 255, 0.5), transparent 55%),
		radial-gradient(circle at 70% 65%, rgba(58, 31, 18, 0.10), transparent 60%);
}
/* Leaflet override: lock our wrapper height so Leaflet sizes correctly,
   and tone its default control chrome to brand. */
.kfy-service-areas__map .leaflet-container {
	width: 100%;
	height: 100%;
	background: transparent;
	font-family: var(--font-body);
}
.kfy-service-areas__map .leaflet-control-attribution {
	background: rgba(255, 255, 255, 0.85);
	color: var(--pdu-brown-soft);
	font-size: 11px;
}
.kfy-service-areas__map .leaflet-bar a {
	background: var(--pdu-cream);
	color: var(--pdu-brown-deep);
	border-color: rgba(58, 31, 18, 0.15);
}
.kfy-service-areas__map .leaflet-bar a:hover {
	background: var(--pdu-sand);
	color: var(--pdu-orange-accessible);
}

/* v2.8: Wheel-zoom opt-in hint. The map JS keeps scroll-wheel zoom OFF
   by default so a wheel scroll over the map doesn't hijack the page,
   then re-enables it once the user clicks into the map (mirrors the
   Google Maps "click to interact" UX). The little overlay below makes
   that contract visible:
     - .kfy-map--wheel-locked  → show the "Click to enable" pill
     - .kfy-map--wheel-active  → hide it (and keep an unobtrusive hover
                                 affordance so users know they can pan)
   Hidden on touch input via the (pointer: coarse) media query because
   touch users get pinch-zoom natively and don't need the prompt. */
.kfy-service-areas__map.kfy-map--wheel-locked::after {
	content: "Click map to interact";
	position: absolute;
	bottom: 14px;
	left: 50%;
	transform: translateX(-50%);
	z-index: 500;
	padding: 6px 14px;
	background: rgba(58, 31, 18, 0.78);
	color: var(--pdu-cream);
	font-family: var(--font-body);
	font-size: 12px;
	letter-spacing: 0.3px;
	border-radius: 999px;
	pointer-events: none;
	opacity: 0;
	transition: opacity 200ms var(--ease-default, ease);
}
.kfy-service-areas__map.kfy-map--wheel-locked:hover::after,
.kfy-service-areas__map.kfy-map--wheel-locked:focus-within::after {
	opacity: 1;
}
.kfy-service-areas__map.kfy-map--wheel-active {
	cursor: grab;
}
.kfy-service-areas__map.kfy-map--wheel-active:active {
	cursor: grabbing;
}
@media (pointer: coarse) {
	.kfy-service-areas__map.kfy-map--wheel-locked::after {
		display: none;
	}
}
/* Mascot pin icon — bare mascot head, no halo or border. A soft drop
   shadow keeps the head readable against pale OSM tile patches without
   adding visual chrome. */
.kfy-service-areas__pin {
	width: 44px;
	height: 44px;
	background-size: contain;
	background-position: center;
	background-repeat: no-repeat;
	filter: drop-shadow(0 3px 6px rgba(41, 22, 16, 0.45));
	transform: translate(-22px, -44px);
}

/* ---- Card wrapper sits on top of the bottom of the map ----
   We override .kfy-container's max-width here on purpose: the card needs
   a slightly tighter cap (1080px) than the global container so the
   mascot column has predictable width and the rounded corners stay
   visible at every viewport above ~1024px. */
.kfy-service-areas__card-wrap.kfy-container {
	position: relative;
	z-index: 2;
	margin-top: clamp(-180px, -16vw, -120px);
	max-width: 1080px;
}

/* ---- Eggplant coverage card ----
   Grid is biased ~1.3:1 so the headline + 3-col city list have room to
   breathe while the wide service-van image gets enough horizontal room
   on the right column to read clearly.

   Background layering (bottom → top):
     1. var(--kfy-coverage-bg) — the Australian outback sunset scene
        (set inline on the element via render.php).
     2. ::before pseudo — deep eggplant overlay at ~88% opacity. This is
        what gives white text its contrast; only the brightest sun rays
        from the scene peek through as a subtle radial accent (which
        echoes the radial sun-ray pattern in the supplied reference). */
.kfy-service-areas__card {
	--kfy-coverage-bg: none;
	position: relative;
	isolation: isolate;
	display: grid;
	/* v2.4: Rebalanced 1.3fr / 1fr → 1.1fr / 1fr so the bigger van column
	   has enough horizontal room to read without cropping. */
	grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
	gap: var(--sp-6);
	align-items: center;
	background-color: var(--pdu-eggplant-deep);
	background-image: var(--kfy-coverage-bg);
	background-size: cover;
	background-position: center;
	color: var(--pdu-cream);
	border-radius: var(--radius-xl, 24px);
	padding: clamp(var(--sp-6), 3.5vw, var(--sp-8));
	box-shadow: 0 24px 56px rgba(41, 22, 16, 0.40);
	overflow: hidden;
}
/* Eggplant overlay — significantly lighter than the original so the
   underlying scene (sunset orange, sun rays, acacia silhouettes) clearly
   shows through. We bias darker on the left where the headline lives
   (so the cream display type stays legible) and let the right side run
   light so the van composes naturally with the scene behind it.

   v2.4: Pulled lighter still (0.55 → 0.30 → 0.08) so the warm scene
   competes with the dark overlay rather than getting buried — matches
   the user's reference (the teal radial-rays card stays clearly bright).

   A short text-shadow is added on the headline + city items below to
   pick up the small contrast loss without forcing the overlay darker. */
.kfy-service-areas__card::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: linear-gradient(
		90deg,
		rgba(37, 19, 31, 0.55) 0%,
		rgba(37, 19, 31, 0.30) 50%,
		rgba(37, 19, 31, 0.08) 100%
	);
}
/* Cream display headline against a varied scene — a tight, low-opacity
   eggplant text-shadow guards readability without looking outlined. */
.kfy-service-areas__card-title,
.kfy-service-areas__city-name {
	text-shadow: 0 1px 2px rgba(37, 19, 31, 0.55);
}
/* Stripes element kept in markup for backward compatibility but neutralised
   visually — the radial sun-rays from the underlying scene now play the
   role the diagonal stripes used to. */
.kfy-service-areas__card-stripes {
	display: none;
}

.kfy-service-areas__card-text {
	position: relative;
	z-index: 1;
}
.kfy-service-areas__card-title {
	font-family: var(--font-display);
	font-size: clamp(20px, 1.6vw + 0.6rem, 28px);
	line-height: 1.15;
	color: var(--pdu-cream);
	margin: 0 0 var(--sp-5);
	text-wrap: balance;
	max-width: 24ch;
}

/* ---- City list — 3 column grid with orange map-pin icons ---- */
.kfy-service-areas__cities {
	list-style: none;
	margin: 0 0 var(--sp-6);
	padding: 0;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--sp-3) var(--sp-4);
}
@media (max-width: 720px) {
	.kfy-service-areas__cities { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 420px) {
	.kfy-service-areas__cities { grid-template-columns: minmax(0, 1fr); }
}
.kfy-service-areas__city {
	display: flex;
	align-items: center;
	gap: 10px;
	font-family: var(--font-body);
	font-size: 15px;
	font-weight: 600;
	color: var(--pdu-cream);
	line-height: 1.3;
}
.kfy-service-areas__city-pin {
	width: 18px;
	height: 18px;
	display: inline-grid;
	place-items: center;
	color: var(--pdu-brand-orange);
	flex-shrink: 0;
}
.kfy-service-areas__city-pin .kfy-icon {
	color: var(--pdu-brand-orange);
}
.kfy-service-areas__city--trailing .kfy-service-areas__city-name {
	font-style: italic;
	opacity: 0.9;
}

/* ---- Card CTA ---- */
.kfy-service-areas__cta {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	padding: 16px 28px;
	font-size: 15px;
	letter-spacing: 0.5px;
	min-height: 52px;
}
.kfy-service-areas__cta .kfy-icon {
	flex-shrink: 0;
}

/* ---- Vehicle column ----
   The default asset is the wide service-van (eggplant van wrapped with
   the mascot + brand logo), so we let the column run wide and the image
   sit nearly to the card edges. object-fit: contain handles taller
   mascot poses too if an editor swaps the image. */
.kfy-service-areas__card-mascot {
	position: relative;
	z-index: 1;
	display: flex;
	justify-content: center;
	align-items: center;
	height: 100%;
	min-height: 220px;
}
/* v2.4: Bumped max-width 440 → 600 and max-height 260 → 360 so the
   service van reads at a similar dominance to the reference (Hi Level
   Garage Doors), where the van takes up nearly the full right column. */
.kfy-service-areas__card-mascot img {
	width: 100%;
	max-width: 600px;
	max-height: 360px;
	height: auto;
	display: block;
	object-fit: contain;
	filter: drop-shadow(0 14px 24px rgba(0, 0, 0, 0.45));
}

/* ---- Mobile: stack mascot below the text, keep card readable ---- */
@media (max-width: 820px) {
	.kfy-service-areas__card {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--sp-4);
	}
	.kfy-service-areas__card-mascot {
		order: -1;
		min-height: 140px;
	}
	.kfy-service-areas__card-mascot img { max-width: 320px; max-height: 180px; }
	.kfy-service-areas__card-wrap { margin-top: clamp(-100px, -16vw, -60px); }
	.kfy-service-areas__cta { width: 100%; justify-content: center; }
}

/* =========================================================================
   BLOCK 8 - FINAL CTA
   ========================================================================= */
.kfy-final-cta {
	position: relative;
	background-color: var(--color-deep-brown);
	/* v2.8: Brown overlay was reading as a flat dark wash that muddied
	   the photo and flattened the headline. Dropped the linear-darken
	   alphas significantly (0.55/0.42 → 0.30/0.20) and warmed the tone
	   toward a softer caramel so the underlying photo (Joey + happy
	   customer) shines through. To keep the cream headline AAA-legible
	   on the now-brighter backdrop, added a centered radial vignette
	   behind .__inner — darker right where the type sits, fading out
	   to nothing by the section edges. Pair this with the text-shadow
	   on .__headline / .__sub below for proper "pop". */
	background-image:
		radial-gradient(ellipse at 20% 30%, rgba(247, 199, 59, 0.18), transparent 55%),
		radial-gradient(ellipse at 80% 70%, rgba(178, 58, 44, 0.22), transparent 55%),
		radial-gradient(ellipse at 50% 50%, rgba(41, 22, 16, 0.45) 0%, rgba(41, 22, 16, 0.18) 45%, transparent 75%),
		linear-gradient(135deg, rgba(112, 68, 38, 0.30) 0%, rgba(178, 96, 50, 0.20) 100%),
		var(--kfy-final-cta-bg-image, linear-gradient(135deg, #492C19 0%, #8E4420 100%));
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
	color: var(--color-cream);
	overflow: hidden;
	text-align: center;
	padding: clamp(var(--sp-12), 10vw, 160px) 0;
}
.kfy-final-cta::before {
	content: "";
	position: absolute;
	top: 10%;
	right: 8%;
	width: 240px; height: 240px;
	background: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F8F3E0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z'/%3E%3C/svg%3E") center / contain no-repeat;
	opacity: 0.08;
	transform: rotate(-25deg);
	animation: kfy-wrench-spin 18s linear infinite;
	pointer-events: none;
}
.kfy-final-cta__inner {
	position: relative;
	z-index: 2;
	max-width: 880px;
	margin-inline: auto;
	padding-inline: var(--sp-5);
}
.kfy-final-cta__headline {
	font-size: clamp(34px, 5vw + 1rem, 60px);
	margin: 0 0 var(--sp-4);
	line-height: 1.05;
	/* v2.8: With the brown overlay lightened so the photo can breathe,
	   we lean on a layered text-shadow (tight near-black for crisp
	   edges + soft warm-brown glow for ambient separation) to keep
	   cream + gold type popping cleanly off the new backdrop. */
	text-shadow:
		0 1px 2px rgba(0, 0, 0, 0.55),
		0 4px 18px rgba(41, 22, 16, 0.55);
}
.kfy-final-cta__headline span {
	color: var(--color-gold);
	display: block;
	text-shadow:
		0 1px 2px rgba(0, 0, 0, 0.6),
		0 4px 18px rgba(73, 44, 25, 0.55);
}
.kfy-final-cta__sub {
	font-size: clamp(17px, 1vw + 15px, 20px);
	color: rgba(248, 243, 224, 0.95);
	line-height: 1.6;
	margin: 0 0 var(--sp-8);
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.kfy-final-cta__buttons {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-3);
	justify-content: center;
}

/* =========================================================================
   BLOCK 9 - FOOTER
   ========================================================================= */
.kfy-footer {
	position: relative;
	isolation: isolate;
	background-color: var(--pdu-eggplant-deep);
	/* v2.7: Layered footer backdrop —
	   1. Brand vector "outback sunset" scene as the visual anchor.
	   2. A top→bottom darkening overlay (maroon → eggplant → near-black)
	      that keeps text legible against the photo (cream-on-eggplant
	      stays > 13:1, AAA, even where the scene is brightest).
	   3. Two soft warm radial highlights so the corners don't feel
	      like flat dark voids.
	   4. A subtle paw-print SVG pattern at very low opacity for tactile
	      brand texture without competing with copy.
	   The vector scene uses background-attachment: scroll (default) so
	   it stays put on iOS where `fixed` triggers paint glitches. */
	background-image:
		/* paw pattern — low-contrast textural noise */
		url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cg fill='%23F5E1C0' fill-opacity='0.035'%3E%3Cpath d='M40 90c0 5-3 9-7 9s-7-4-7-9 3-9 7-9 7 4 7 9zm38 0c0 5-3 9-7 9s-7-4-7-9 3-9 7-9 7 4 7 9zM52 70c0 4-2 8-6 8s-6-4-6-8 2-8 6-8 6 4 6 8zm12 0c0 4-2 8-6 8s-6-4-6-8 2-8 6-8 6 4 6 8zm-10 24c-7 0-13 6-13 13 0 4 3 7 7 7h12c4 0 7-3 7-7 0-7-6-13-13-13z'/%3E%3C/g%3E%3C/svg%3E"),
		/* warm corner highlights */
		radial-gradient(ellipse at 0% 0%, rgba(247, 199, 59, 0.10), transparent 50%),
		radial-gradient(ellipse at 100% 0%, rgba(239, 126, 26, 0.12), transparent 55%),
		/* darkening overlay that sits between the gradient and the scene */
		linear-gradient(180deg,
			rgba(77, 38, 69, 0.92) 0%,
			rgba(58, 29, 56, 0.94) 45%,
			rgba(37, 19, 31, 0.97) 100%
		),
		/* the brand outback sunset scene as the footer's anchor */
		url("../img/vector%20scene%20base.jpg");
	background-position:
		center top,
		left top,
		right top,
		center top,
		center bottom;
	background-size:
		160px 160px,
		auto,
		auto,
		100% 100%,
		cover;
	background-repeat: repeat, no-repeat, no-repeat, no-repeat, no-repeat;
	color: var(--color-cream);
	padding: clamp(var(--sp-12), 9vw, var(--sp-14)) 0 var(--sp-6);
	border-top: 0;
}

/* v2.7: Top wave divider — a warm sunset ribbon that gives the footer
   a clean visible boundary as it comes out of the final CTA section.
   Echoes the same wave-cut technique used on About Overview so the
   page reads as one coherent design system. */
.kfy-footer::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 18px;
	background: linear-gradient(
		90deg,
		var(--pdu-brand-orange) 0%,
		var(--pdu-sunset-amber) 45%,
		var(--pdu-sunset-yellow) 70%,
		var(--pdu-brand-orange) 100%
	);
	-webkit-mask: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 18' preserveAspectRatio='none'%3E%3Cpath d='M0 11 C 240 0 480 18 720 9 C 960 0 1200 18 1440 9 L 1440 0 L 0 0 Z' fill='black'/%3E%3C/svg%3E") center top / 100% 100% no-repeat;
	mask: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 18' preserveAspectRatio='none'%3E%3Cpath d='M0 11 C 240 0 480 18 720 9 C 960 0 1200 18 1440 9 L 1440 0 L 0 0 Z' fill='black'/%3E%3C/svg%3E") center top / 100% 100% no-repeat;
	pointer-events: none;
	z-index: 2;
	opacity: 0.92;
}

/* v2.7: Soft fade at the very bottom of the scene so the deepening
   gradient ends in pure ink — keeps the © line and legal links from
   competing with the warm tones above. */
.kfy-footer::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 140px;
	background: linear-gradient(180deg,
		transparent 0%,
		rgba(15, 10, 8, 0.55) 100%);
	pointer-events: none;
	z-index: 0;
}

.kfy-footer > * {
	position: relative;
	z-index: 1;
}

.kfy-footer__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-8);
}
@media (min-width: 600px) { .kfy-footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .kfy-footer__grid { grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr; gap: var(--sp-6); } }

.kfy-footer__col h3 {
	font-family: var(--font-display);
	color: var(--color-gold);
	text-transform: uppercase;
	font-size: 17px;
	letter-spacing: 1.5px;
	line-height: 1.2;
	margin: 0 0 var(--sp-4);
	padding-bottom: var(--sp-2);
	border-bottom: 1px solid rgba(198, 187, 60, 0.25);
}

/* Brand column - center the Plumber Down Under logo (and the supporting tag/owner
   line + social icons) inside its own column at every breakpoint. The
   column is the leftmost cell of the desktop grid and the first stacked
   item on mobile, so without centering the logo floats to the left and
   reads as misaligned against the rest of the footer. */
.kfy-footer__col--brand {
	text-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
}
.kfy-footer__brand-mark {
	display: inline-block;
	margin: 0 auto var(--sp-4);
	line-height: 0;
}
.kfy-footer__brand-mark img {
	width: 100%;
	/* Mobile: bump the lockup so it carries proper visual weight at
	   the top of the stacked footer. The desktop cap stays at 260px
	   because the brand column shrinks to 1.5fr in the 5-col grid
	   and a larger mark would crowd the neighbouring sitemap cols. */
	max-width: 360px;
	height: auto;
	margin-inline: auto;
	filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.4));
	transition: transform var(--ease-default);
}
@media (min-width: 600px) {
	.kfy-footer__brand-mark img { max-width: 320px; }
}
@media (min-width: 1024px) {
	.kfy-footer__brand-mark img { max-width: 260px; }
}
.kfy-footer__brand-mark:hover img {
	transform: scale(1.03);
}
.kfy-footer__tag { color: var(--text-secondary); font-size: 16px; margin: 0 0 var(--sp-3); font-style: italic; line-height: 1.55; }
.kfy-footer__owner { color: var(--text-secondary); font-size: 15px; margin: 0 0 var(--sp-4); line-height: 1.55; }

.kfy-footer__socials {
	display: flex;
	gap: var(--sp-2);
	flex-wrap: wrap;
}
.kfy-footer__social {
	width: 38px; height: 38px;
	display: grid; place-items: center;
	border-radius: var(--radius-md);
	background: rgba(248, 243, 224, 0.08);
	color: var(--color-cream);
	font-size: 16px;
	transition: background var(--ease-default), transform var(--ease-default);
}
.kfy-footer__social:hover {
	background: var(--color-gold);
	color: var(--color-near-black);
	transform: translateY(-2px);
}

.kfy-footer__list { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-2); }
.kfy-footer__list a { color: var(--text-secondary); font-size: 16px; line-height: 1.55; }
.kfy-footer__list a:hover { color: var(--color-gold); }
.kfy-footer__list--plain span {
	/* Plain (non-link) footer items — used for cities now that we no longer
	   have per-city pages. Matches the link rhythm so the column visually
	   reads as a clean list, not a half-broken hyperlinks block. */
	color: var(--text-secondary);
	font-size: 16px;
	line-height: 1.55;
}

.kfy-footer__contact { display: grid; gap: var(--sp-3); font-size: 16px; }
.kfy-footer__contact a, .kfy-footer__contact span { color: var(--text-secondary); }
.kfy-footer__contact a:hover { color: var(--color-gold); }
.kfy-footer__contact-row {
	display: grid;
	grid-template-columns: 20px 1fr;
	gap: 12px;
	align-items: start;
	font-size: 16px;
	line-height: 1.55;
}
.kfy-footer__contact-icon { color: var(--color-gold); margin-top: 3px; }

.kfy-footer__hours-row {
	display: flex;
	justify-content: space-between;
	gap: var(--sp-2);
	font-size: 15px;
	color: var(--text-secondary);
	padding: 6px 0;
	border-bottom: 1px dashed rgba(248, 243, 224, 0.08);
}
.kfy-footer__hours-row strong {
	color: var(--color-cream);
	/* v2.8: Day labels (Mon, Tue, …) used to render in the display
	   font with 1px tracking, so they read as a separate typographic
	   register from the time values beside them ("Mon" looked like
	   eyebrow type, "7:00 AM – 6:00 PM" looked like body). Switching
	   to inherit (= the row's body font) plus a normal letter-spacing
	   unifies the row into one voice while <strong>'s default bold
	   weight keeps the day visually anchored on the left. */
	font-family: inherit;
	font-weight: 700;
	letter-spacing: normal;
	min-width: 48px;
}

.kfy-footer__bottom {
	margin-top: var(--sp-10);
	padding-top: var(--sp-5);
	border-top: 1px solid rgba(248, 243, 224, 0.08);
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: var(--sp-3);
	font-size: 14px;
	color: var(--text-secondary);
}
.kfy-footer__bottom a { color: var(--text-secondary); }
.kfy-footer__bottom a:hover { color: var(--color-gold); }
.kfy-footer__legal { display: flex; gap: var(--sp-4); flex-wrap: wrap; }

/* =========================================================================
   Quote / Contact Modal
   ========================================================================= */
.kfy-modal {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	width: 100vw;
	height: 100vh;
	height: 100dvh;
	z-index: 1000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--sp-4);
	visibility: hidden;
	opacity: 0;
	transition: opacity 200ms ease, visibility 0s linear 200ms;
	pointer-events: none;
}
.kfy-modal.is-open {
	visibility: visible;
	opacity: 1;
	pointer-events: auto;
	transition: opacity 200ms ease, visibility 0s linear 0s;
}
.kfy-modal__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(15, 10, 8, 0.72);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
}
.kfy-modal__dialog {
	position: relative;
	width: 100%;
	max-width: 540px;
	max-height: calc(100vh - var(--sp-6));
	overflow-y: auto;
	background: var(--color-cream);
	color: var(--color-near-black);
	border-radius: var(--radius-lg, 16px);
	box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(198, 187, 60, 0.25);
	padding: clamp(20px, 4vw, 32px);
	transform: translateY(12px) scale(0.98);
	transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.kfy-modal.is-open .kfy-modal__dialog { transform: translateY(0) scale(1); }

.kfy-modal__close {
	position: absolute;
	top: 12px;
	right: 12px;
	width: 38px;
	height: 38px;
	border-radius: 50%;
	background: transparent;
	color: var(--color-near-black);
	border: 1px solid rgba(27, 17, 12, 0.15);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition: background 160ms ease, border-color 160ms ease, color 160ms ease, transform 160ms ease;
}
.kfy-modal__close:hover {
	background: rgba(27, 17, 12, 0.06);
	border-color: var(--color-gold);
	color: var(--color-burnt-orange);
	transform: rotate(90deg);
}
.kfy-modal__close:focus-visible {
	outline: 2px solid var(--color-gold);
	outline-offset: 2px;
}

.kfy-modal__header { margin-bottom: var(--sp-4); padding-right: 44px; }
.kfy-modal__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-size: 14px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 1.2px;
	color: var(--color-burnt-orange);
	margin-bottom: 8px;
}
.kfy-modal__eyebrow .kfy-icon { color: var(--color-burnt-orange); }
.kfy-modal__title {
	font-family: var(--font-display);
	font-size: clamp(22px, 2.4vw, 28px);
	line-height: 1.15;
	margin: 0 0 6px;
	color: var(--color-near-black);
}
.kfy-modal__subtitle {
	margin: 0;
	font-size: 16px;
	color: rgba(27, 17, 12, 0.72);
	line-height: 1.55;
}

.kfy-modal__form .kfy-hero__form-note,
.kfy-modal__form .kfy-hero__form-note a {
	color: rgba(27, 17, 12, 0.7);
}
.kfy-modal__form .kfy-hero__form-note a {
	color: var(--color-burnt-orange);
	font-weight: 600;
	text-decoration: none;
}
.kfy-modal__form .kfy-hero__form-note a:hover { text-decoration: underline; }

/* Lock body scroll while the modal or mobile menu is open */
body.kfy-modal-open,
body.kfy-menu-open { overflow: hidden; }

@media (max-width: 480px) {
	.kfy-modal { padding: var(--sp-2); align-items: flex-end; }
	.kfy-modal__dialog {
		max-height: 92vh;
		border-radius: var(--radius-lg, 16px) var(--radius-lg, 16px) 0 0;
		padding: 22px 18px 24px;
	}
}

/* Honor reduced-motion preferences */
@media (prefers-reduced-motion: reduce) {
	.kfy-modal,
	.kfy-modal__dialog,
	.kfy-modal__close { transition: none; }
}

/* Sticky mobile call bar - hidden by default, slides up once the user
   scrolls past the hero (the hero has its own large Call CTA). Uses the
   same glove-red palette as .kfy-btn--primary so the persistent footer
   action reads as the site's primary CTA, matching the "Get A Fast Quote"
   pill in the quote band and the call button inside the mobile drawer. */
.kfy-mobile-callbar {
	position: fixed;
	left: 0; right: 0; bottom: 0;
	z-index: 999;
	background: linear-gradient(135deg, var(--pdu-glove-light) 0%, var(--pdu-glove) 55%, var(--pdu-glove-deep) 100%);
	color: var(--pdu-cream);
	padding: 14px;
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 8px;
	font-family: var(--font-display);
	font-size: 16px;
	text-transform: uppercase;
	letter-spacing: 1px;
	text-shadow: 0 1px 1px rgba(60, 14, 9, 0.35);
	box-shadow:
		0 -4px 16px rgba(41, 22, 16, 0.3),
		inset 0 1px 0 rgba(255, 255, 255, 0.18);
	transform: translateY(110%);
	transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
	pointer-events: none;
}
.kfy-mobile-callbar.is-visible {
	transform: translateY(0);
	pointer-events: auto;
}
.kfy-mobile-callbar a { color: var(--pdu-cream); display: inline-flex; align-items: center; gap: 6px; }
.kfy-mobile-callbar .kfy-icon { color: var(--pdu-cream); }

@media (min-width: 768px) {
	.kfy-mobile-callbar { display: none; }
}

/* =========================================================================
   MOBILE OPTIMIZATIONS (≤767px)
   - Hide the lead form to push users to call
   - Make "Call Now" the dominant, full-width CTA
   - Show a compact mobile mascot inside the hero content
   - Tighten section padding & make primary CTAs full-width
   ========================================================================= */

/* Mobile-only mascot inside hero content (hidden on tablet/desktop) */
.kfy-hero__mascot--mobile { display: none; }

@media (max-width: 767px) {
	/* ---- Hero ---- */
	.kfy-hero {
		min-height: 0;
		/* v2.7.3: top padding now keys off --kfy-header-h (72px on mobile)
		   plus a ~24px breath, so the Google/Facebook review chips at the
		   very top of the hero content clear the floating header island
		   instead of being clipped under it. */
		padding: calc(var(--kfy-header-h, 72px) + var(--sp-4)) 0 var(--sp-8);
	}
	.kfy-hero__inner {
		gap: var(--sp-5);
		grid-template-columns: 1fr;
	}
	.kfy-hero__content {
		text-align: center;
		display: flex;
		flex-direction: column;
		align-items: center;
	}
	.kfy-hero__title {
		font-size: clamp(30px, 8vw + 4px, 42px);
		text-wrap: balance;
	}
	.kfy-hero__subtitle {
		font-size: 16px;
		line-height: 1.6;
		margin: 0 auto var(--sp-5);
	}
	.kfy-hero__owner-pill { font-size: 14px; padding: 6px 12px; }

	/* Tuck the original right-column form + big mascot away */
	.kfy-hero__form-col { display: none; }

	/* Mobile mascot - sits below the credentials, centered */
	.kfy-hero__mascot--mobile {
		display: block;
		position: static;
		width: 180px;
		height: auto;
		margin: var(--sp-5) auto 0;
		filter: drop-shadow(0 14px 24px rgba(41, 22, 16, 0.55));
		animation: kfy-float 4s ease-in-out infinite;
		pointer-events: none;
	}

	/* CTAs: stack 1-column on mobile (Call dominant, Contact Us subtle) */
	.kfy-hero__ctas {
		grid-template-columns: minmax(0, 1fr);
		align-self: stretch;
		max-width: none;
		gap: var(--sp-2);
		margin-bottom: var(--sp-5);
	}
	/* The call wrapper is inline-flex (to anchor the van decoration), so on
	   mobile we have to explicitly stretch it - otherwise it shrinks to its
	   content while the sibling Quote button fills the grid cell, making the
	   primary CTA look smaller than the secondary one. */
	.kfy-hero__cta-call-wrap {
		display: flex;
		width: 100%;
	}
	.kfy-hero__cta-call-wrap > .kfy-hero__cta-call {
		width: 100%;
	}
	.kfy-hero__cta-call.kfy-btn {
		padding: 18px 18px;
		font-size: 17px;
		line-height: 1.15;
		min-height: 56px;
	}
	.kfy-hero__cta-quote.kfy-btn {
		padding: 14px 18px;
		font-size: 15px;
		min-height: 48px;
		opacity: 0.9;
	}

	/* Trim hero secondary content + center inline groups on mobile */
	.kfy-hero__coverage {
		justify-content: center;
		margin-top: var(--sp-3);
	}
	.kfy-hero__coverage li { font-size: 14px; padding: 4px 10px; }
	.kfy-hero__certs {
		justify-content: center;
		margin-top: var(--sp-4);
	}
	.kfy-hero__review-badges {
		/* Keep the Google + FB review chips left-aligned on mobile, even
		   though the surrounding hero content is centered. align-self
		   beats the parent's `align-items: center` for this one item. */
		justify-content: flex-start;
		align-self: flex-start;
		margin: 0 0 var(--sp-3);
	}

	/* ---- Sections ---- */
	.kfy-section { padding: var(--sp-10) 0; }
	.kfy-section-header { margin-bottom: var(--sp-8); }
	.kfy-container { padding-inline: var(--sp-4); }

	/* ---- Final CTA: stack buttons full-width ---- */
	.kfy-final-cta { padding: var(--sp-12) 0; }
	.kfy-final-cta__buttons {
		flex-direction: column;
		align-items: stretch;
	}
	.kfy-final-cta__buttons .kfy-btn { width: 100%; justify-content: center; }

	/* ---- Trust: less ornament ---- */
	.kfy-trust__photo { display: none; }
	.kfy-trust__split { gap: var(--sp-6); }

	/* ---- Quick actions: tighter cards ---- */
	.kfy-quick-actions__grid { gap: var(--sp-3); }

	/* ---- Mobile callbar: bigger tap target + iOS safe-area ---- */
	.kfy-mobile-callbar {
		font-size: 16px;
		padding: 14px;
		padding-bottom: max(14px, env(safe-area-inset-bottom));
	}
	/* Only reserve space when the bar is actually showing */
	body:has(.kfy-mobile-callbar.is-visible) {
		padding-bottom: calc(64px + env(safe-area-inset-bottom));
	}
}

/* Very small phones - tighten further */
@media (max-width: 380px) {
	.kfy-hero__mascot--mobile { width: 150px; }
	.kfy-hero__title { font-size: 28px; }
	.kfy-review-badges--compact { gap: 8px; }
	.kfy-review-badges--compact .kfy-review-badge { padding: 6px 8px; gap: 6px; }
	.kfy-review-badges--compact .kfy-review-badge__logo { width: 28px; height: 28px; }
}

/* =====================================================================
   kfy/local-faq - accordion (used on service & city pages for SEO Q&A)
   ===================================================================== */
.kfy-local-faq {
	background: var(--bg-light);
	color: var(--text-on-light);
}

.kfy-local-faq__list {
	display: flex;
	flex-direction: column;
	gap: var(--sp-3);
}

.kfy-local-faq__item {
	background: var(--color-cream);
	border: 1px solid var(--color-soft-tan);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-sm);
	overflow: hidden;
	transition: box-shadow var(--ease-default), border-color var(--ease-default);
}

.kfy-local-faq__item:hover {
	box-shadow: var(--shadow-md);
	border-color: var(--color-warm-brown);
}

.kfy-local-faq__item[open] {
	border-color: var(--color-gold);
}

.kfy-local-faq__q {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-3);
	padding: var(--sp-4) var(--sp-5);
	cursor: pointer;
	font-family: var(--font-accent);
	font-weight: 600;
	font-size: 18px;
	line-height: 1.4;
	color: var(--text-on-light);
	list-style: none;
	user-select: none;
	transition: color var(--ease-default);
}

.kfy-local-faq__q::-webkit-details-marker { display: none; }
.kfy-local-faq__q::marker { content: ''; }

.kfy-local-faq__q:hover { color: var(--color-deep-brown); }

.kfy-local-faq__q-text { flex: 1; }

.kfy-local-faq__q-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	color: var(--color-gold);
	transition: transform var(--ease-default);
}

.kfy-local-faq__item[open] .kfy-local-faq__q-icon {
	transform: rotate(90deg);
}

.kfy-local-faq__a {
	padding: 0 var(--sp-5) var(--sp-5);
	color: var(--text-on-light);
	font-size: 17px;
	line-height: 1.65;
	animation: kfyFaqOpen 0.22s ease-out;
}

.kfy-local-faq__a p { margin: 0; }

@keyframes kfyFaqOpen {
	from { opacity: 0; transform: translateY(-4px); }
	to   { opacity: 1; transform: translateY(0); }
}

@media (max-width: 600px) {
	.kfy-local-faq__q { padding: var(--sp-3) var(--sp-4); font-size: 17px; }
	.kfy-local-faq__a { padding: 0 var(--sp-4) var(--sp-4); font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
	.kfy-local-faq__a { animation: none; }
	.kfy-local-faq__item,
	.kfy-local-faq__q-icon { transition: none; }
}

/* =========================================================================
   Long-copy + symptom-list groups (service & area leaf-page intros)
   ========================================================================= */
.kfy-long-copy,
.kfy-symptom-list {
	background: var(--bg-primary);
	color: var(--text-primary);
	padding: clamp(var(--sp-8), 6vw, var(--sp-12)) var(--sp-5);
	max-width: 880px;
	margin-inline: auto;
	box-sizing: content-box;
}

.kfy-long-copy .kfy-container--narrow,
.kfy-symptom-list .kfy-container--narrow {
	max-width: 820px;
	margin-inline: auto;
}

.kfy-long-copy h2,
.kfy-symptom-list h2 {
	font-family: var(--font-display);
	font-size: clamp(1.625rem, 2.5vw + 0.75rem, 2.25rem);
	color: var(--color-cream);
	text-transform: uppercase;
	line-height: 1.15;
	margin: 0 0 var(--sp-4);
}

.kfy-long-copy h3 {
	font-family: var(--font-display);
	font-size: clamp(1.25rem, 1.5vw + 0.75rem, 1.5rem);
	color: var(--color-gold);
	text-transform: uppercase;
	line-height: 1.2;
	margin: var(--sp-7) 0 var(--sp-3);
}

.kfy-long-copy p,
.kfy-symptom-list li {
	font-size: var(--fs-base);
	line-height: 1.75;
	color: var(--text-primary);
	margin: 0 0 var(--sp-4);
}

.kfy-long-copy p:last-child { margin-bottom: 0; }

.kfy-long-copy a,
.kfy-symptom-list a {
	color: var(--color-gold);
	text-decoration: underline;
	text-underline-offset: 3px;
}
.kfy-long-copy a:hover,
.kfy-symptom-list a:hover { color: var(--color-burnt-orange); }

.kfy-symptom-list ul {
	list-style: none;
	padding: 0;
	margin: var(--sp-4) 0 0;
	display: grid;
	gap: var(--sp-2);
}

.kfy-symptom-list li {
	position: relative;
	padding-left: var(--sp-6);
	margin: 0;
}

.kfy-symptom-list li::before {
	content: '';
	position: absolute;
	left: 0;
	top: 0.7em;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--color-gold);
}

/* =========================================================================
   Simple page wrapper (legal, contact, generic user-created pages)
   ========================================================================= */
.kfy-simple-page {
	color: var(--text-primary);
	max-width: 800px;
	margin: 0 auto;
}
.kfy-simple-page h1 {
	margin: 0 0 var(--sp-6);
	color: var(--color-cream);
}
.kfy-simple-page h2 { margin: var(--sp-8) 0 var(--sp-3); color: var(--color-cream); }
.kfy-simple-page h3 { margin: var(--sp-6) 0 var(--sp-2); color: var(--color-cream); }
.kfy-simple-page p,
.kfy-simple-page li { line-height: 1.7; color: var(--text-primary); }
.kfy-simple-page a { color: var(--color-gold); text-decoration: underline; }
.kfy-simple-page a:hover { color: var(--color-burnt-orange); }

/* =========================================================================
   kfy/contact - Contact page form + info section
   ========================================================================= */
.kfy-contact {
	background: var(--bg-primary);
	color: var(--text-primary);
	padding: clamp(var(--sp-10), 8vw, var(--sp-12)) var(--sp-5);
	position: relative;
	overflow: hidden;
}
.kfy-contact::before {
	content: "";
	position: absolute;
	inset: 0;
	background:
		radial-gradient(circle at 15% 20%, rgba(198, 187, 60, 0.08), transparent 45%),
		radial-gradient(circle at 85% 80%, rgba(186, 103, 51, 0.10), transparent 50%);
	pointer-events: none;
	z-index: 1;
}
.kfy-contact__inner {
	position: relative;
	max-width: 1200px;
	margin: 0 auto;
	z-index: 2;
}

/* ---------- Wrap-background (page-hero) modifier ----------
   Used when the block sits at the top of a page (e.g. /contact/) and
   needs to carry the same brand presence as the standard kfy/hero.

   Background recipe (mirrors .kfy-hero / .kfy-quote-band so the page
   reads as continuous brand surface, not a flat eggplant slab):
     1. background-color = near-black (final fallback)
     2. .kfy-contact__scene = vector scene photo (z 0)
     3. ::before = warm sunset overlay, alphas tuned so the photo
        reads through (z 1)
     4. .kfy-contact__clouds = drifting cloud puffs (z 2)
     5. .kfy-contact__inner = header + info + form (z 3)

   Layout (>=960px): two columns - header + info card on the left,
   form spanning full height on the right - so the entire contact UI
   fits inside one viewport on standard desktops without scrolling. */
.kfy-contact--wrap-bg {
	background-color: var(--color-near-black);
	color: var(--color-cream);
	/* v2.7.4: top padding now keys off --kfy-header-h (72px on mobile,
	   142px on desktop) plus a 32px breath, so the eyebrow + H1 always
	   clear the floating header island instead of being clipped by it. */
	padding-top: calc(var(--kfy-header-h, 72px) + var(--sp-5));
	padding-bottom: clamp(var(--sp-6), 4vw, var(--sp-9));
	min-height: calc(100svh - var(--kfy-header-h, 120px));
	display: flex;
	align-items: center;
	isolation: isolate;
}
.kfy-contact__scene {
	position: absolute;
	inset: 0;
	z-index: 0;
	background-repeat: no-repeat;
	background-position: center 35%;
	background-size: cover;
	pointer-events: none;
}
.kfy-contact--wrap-bg::before {
	content: "";
	position: absolute;
	inset: 0;
	/* v2.7.4: same warm sunset → dusk recipe as the hero, but the linear
	   scrim alphas were trimmed (~25%) so the vector scene photo behind
	   it reads through instead of being completely flattened. */
	background:
		radial-gradient(ellipse at 80% 0%,  rgba(247, 199, 59, 0.18), transparent 60%),
		radial-gradient(ellipse at 0% 100%, rgba(178, 58, 44, 0.22),  transparent 60%),
		linear-gradient(180deg,
			rgba(92, 58, 40, 0.55) 0%,
			rgba(89, 31, 41, 0.62) 45%,
			rgba(58, 29, 56, 0.72) 78%,
			rgba(39, 19, 38, 0.82) 100%
		);
	z-index: 1;
	pointer-events: none;
}
/* Drifting cloud layer — re-uses the inline-SVG puff + drift keyframe
   already defined for .kfy-quote-band__cloud, just scoped to the
   contact section so the timings + opacities can drift independently
   if we ever want to retune them. */
.kfy-contact__clouds {
	position: absolute;
	inset: 0;
	z-index: 2;
	overflow: hidden;
	pointer-events: none;
}
.kfy-contact__cloud {
	position: absolute;
	top: 0;
	display: block;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80'><g fill='%23ffffff' opacity='0.92'><ellipse cx='50' cy='52' rx='40' ry='22'/><ellipse cx='100' cy='38' rx='52' ry='30'/><ellipse cx='150' cy='52' rx='40' ry='22'/></g></svg>");
	will-change: transform;
}
.kfy-contact__cloud--1 { top: 12%; width: 220px; height: 88px;  opacity: 0.50; }
.kfy-contact__cloud--2 { top: 22%; width: 160px; height: 64px;  opacity: 0.36; }
.kfy-contact__cloud--3 { top: 6%;  width: 280px; height: 112px; opacity: 0.58; }
@media (prefers-reduced-motion: no-preference) {
	.kfy-contact__cloud--1 { animation: kfy-cloud-drift 75s linear infinite;  animation-delay: -10s; }
	.kfy-contact__cloud--2 { animation: kfy-cloud-drift 110s linear infinite; animation-delay: -55s; }
	.kfy-contact__cloud--3 { animation: kfy-cloud-drift 90s linear infinite;  animation-delay: -30s; }
}
@media (prefers-reduced-motion: reduce) {
	.kfy-contact__cloud--1 { transform: translate3d(15vw, 0, 0); }
	.kfy-contact__cloud--2 { transform: translate3d(55vw, 0, 0); }
	.kfy-contact__cloud--3 { transform: translate3d(78vw, 0, 0); }
}
.kfy-contact--wrap-bg .kfy-contact__inner {
	width: 100%;
	position: relative;
	z-index: 3;
}

/* Compact, left-aligned header so the form sits beside it on desktop. */
.kfy-contact--wrap-bg .kfy-contact__header {
	max-width: 56ch;
	margin: 0 0 var(--sp-5);
	text-align: left;
}
.kfy-contact--wrap-bg .kfy-contact__owner-pill {
	margin-bottom: var(--sp-3);
}
.kfy-contact--wrap-bg .kfy-contact__title {
	font-size: clamp(28px, 3.2vw + 0.25rem, 48px);
	line-height: 1.05;
	margin-bottom: var(--sp-3);
}
.kfy-contact--wrap-bg .kfy-contact__intro {
	color: var(--color-cream);
	text-shadow: 0 1px 2px rgba(27, 17, 12, 0.6);
	font-size: clamp(15px, 0.5vw + 0.85rem, 17px);
	line-height: 1.55;
}

/* Two-column hero layout: header(L-top) + info(L-bottom) | form(R, full).
   Below 960px we fall back to the single-column stack defined below. */
@media (min-width: 960px) {
	.kfy-contact--wrap-bg .kfy-contact__inner {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(380px, 0.95fr);
		grid-template-rows: auto 1fr;
		grid-template-areas:
			"header form"
			"info   form";
		column-gap: clamp(var(--sp-6), 3vw, var(--sp-10));
		row-gap: var(--sp-5);
		align-items: start;
	}
	.kfy-contact--wrap-bg .kfy-contact__header { grid-area: header; }
	.kfy-contact--wrap-bg .kfy-contact__grid { display: contents; }
	.kfy-contact--wrap-bg .kfy-contact__info { grid-area: info; }
	.kfy-contact--wrap-bg .kfy-contact__form-col { grid-area: form; align-self: stretch; }

	/* v2.8: Stretch the form card to match the combined height of
	   header + info on the left. The earlier (v2.7.4) attempt used
	   `flex: 1 1 auto` chains, but .kfy-hero__form is `display: grid`
	   (see line ~2274), so the flex hints on its children were silently
	   ignored — the textarea stayed at ~80px and the form bottomed out
	   well above the info card, leaving the visible "extra spacing" the
	   page kept showing.

	   Fix: in wrap-bg mode on desktop we explicitly switch the form to
	   `display: flex; flex-direction: column;` so the grow chain
	   actually resolves, then make the textarea's wrapping div the
	   single flex-grow row. The textarea fills the slack instead of
	   the form leaving a vertical gap. */
	.kfy-contact--wrap-bg .kfy-contact__form-col {
		display: flex;
		flex-direction: column;
	}
	.kfy-contact--wrap-bg .kfy-contact__form-wrap {
		flex: 1 1 auto;
		display: flex;
		flex-direction: column;
	}
	.kfy-contact--wrap-bg .kfy-contact__form {
		display: flex;
		flex-direction: column;
		flex: 1 1 auto;
		gap: var(--sp-3);
	}
	.kfy-contact--wrap-bg .kfy-contact__form > div:has(textarea) {
		flex: 1 1 auto;
		display: flex;
		flex-direction: column;
	}
	.kfy-contact--wrap-bg .kfy-contact__form textarea {
		flex: 1 1 auto;
		min-height: 220px;
	}
}

/* Tighten the info card so the left column comfortably fits beside the
   form. Hours laid out in two columns saves ~120px of vertical space. */
.kfy-contact--wrap-bg .kfy-contact__info {
	padding: var(--sp-4) var(--sp-5);
}
.kfy-contact--wrap-bg .kfy-contact__badge {
	margin-bottom: var(--sp-3);
	font-size: 12px;
	padding: 6px 12px;
}
.kfy-contact--wrap-bg .kfy-contact__channels {
	gap: var(--sp-3);
	margin-bottom: var(--sp-4);
}
.kfy-contact--wrap-bg .kfy-contact__channel {
	padding-bottom: var(--sp-3);
}
.kfy-contact--wrap-bg .kfy-contact__channel-value {
	font-size: 16px;
}
.kfy-contact--wrap-bg .kfy-contact__hours {
	margin-bottom: var(--sp-3);
	padding: var(--sp-3) var(--sp-4);
}
.kfy-contact--wrap-bg .kfy-contact__hours-title {
	margin-bottom: var(--sp-2);
}
.kfy-contact--wrap-bg .kfy-contact__hours-list {
	gap: 2px;
}
.kfy-contact--wrap-bg .kfy-contact__hours-row {
	font-size: 13px;
	padding: 2px 0;
}

/* Tighten the form card - form fields keep their 17px font (above the iOS
   16px auto-zoom threshold) but the surrounding card breathes less.
   The form heading + subtitle are visually hidden in wrap-bg mode because
   the page-level H1 + intro already establish the section context; we keep
   them in the DOM for screen-reader users so the form still has a labeled
   heading. */
.kfy-contact--wrap-bg .kfy-hero__form-wrap,
.kfy-contact--wrap-bg .kfy-contact__form-wrap {
	padding: var(--sp-5);
}
.kfy-contact--wrap-bg .kfy-hero__form-heading,
.kfy-contact--wrap-bg .kfy-hero__form-sub {
	border: 0;
	clip: rect(1px, 1px, 1px, 1px);
	-webkit-clip-path: inset(50%);
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
	white-space: nowrap;
}
.kfy-contact--wrap-bg .kfy-hero__form,
.kfy-contact--wrap-bg .kfy-contact__form {
	gap: var(--sp-3);
}
.kfy-contact--wrap-bg .kfy-hero__form input,
.kfy-contact--wrap-bg .kfy-hero__form select,
.kfy-contact--wrap-bg .kfy-hero__form textarea {
	padding: 11px 13px;
}
.kfy-contact--wrap-bg .kfy-hero__form label {
	margin-bottom: 4px;
}
/* v2.8: Mobile-only baseline — on desktop (>=960px) the textarea uses
   `flex: 1 1 auto; min-height: 220px;` from the media query above so it
   can grow to fill the right-column slack. Scoping this baseline to the
   small-screen breakpoint prevents it from clobbering the desktop value
   via source-order specificity (which was the silent culprit behind the
   tall empty gap below the form). */
@media (max-width: 959.98px) {
	.kfy-contact--wrap-bg .kfy-contact__form textarea {
		min-height: 110px;
	}
}
.kfy-contact--wrap-bg .kfy-contact__required-hint {
	margin-bottom: var(--sp-2);
}
.kfy-contact--wrap-bg .kfy-hero__form-note {
	margin-top: 4px;
	font-size: 13px;
}

.kfy-contact__header {
	max-width: 760px;
	margin: 0 auto var(--sp-10);
	text-align: center;
}
.kfy-contact__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--color-gold);
	font-family: var(--font-display);
	letter-spacing: 2px;
	text-transform: uppercase;
	font-size: 14px;
	margin-bottom: var(--sp-3);
}
.kfy-contact__title {
	font-family: var(--font-display);
	text-transform: uppercase;
	font-size: clamp(32px, 4vw + 1rem, 52px);
	line-height: 1.05;
	margin: 0 0 var(--sp-4);
	color: var(--color-cream);
}
.kfy-contact__title-accent {
	display: block;
	color: var(--color-gold);
}
.kfy-contact__intro {
	font-size: clamp(16px, 1vw + 0.8rem, 18px);
	line-height: 1.65;
	color: var(--text-secondary);
	margin: 0;
}

.kfy-contact__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--sp-8);
	align-items: start;
}
@media (min-width: 880px) {
	.kfy-contact__grid {
		grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
		gap: var(--sp-10);
	}
}

/* ---------- Info card (left) ---------- */
.kfy-contact__info {
	background: linear-gradient(165deg, rgba(58, 29, 56, 0.95), rgba(58, 31, 18, 0.88));
	border: 1px solid rgba(239, 126, 26, 0.22);
	border-radius: var(--radius-xl);
	padding: var(--sp-6);
	box-shadow: var(--shadow-lg);
	position: relative;
}
.kfy-contact__badge {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	background: linear-gradient(135deg, var(--color-red), #a72820);
	color: #fff;
	font-family: var(--font-display);
	font-size: 13px;
	letter-spacing: 1.5px;
	text-transform: uppercase;
	padding: 8px 14px;
	border-radius: var(--radius-full);
	margin-bottom: var(--sp-5);
	box-shadow: 0 4px 14px rgba(205, 54, 44, 0.35);
}

.kfy-contact__channels {
	list-style: none;
	margin: 0 0 var(--sp-6);
	padding: 0;
	display: grid;
	gap: var(--sp-4);
}
.kfy-contact__channel {
	display: flex;
	align-items: flex-start;
	gap: var(--sp-3);
	padding-bottom: var(--sp-4);
	border-bottom: 1px solid rgba(198, 187, 60, 0.12);
}
.kfy-contact__channel:last-child { border-bottom: 0; padding-bottom: 0; }

.kfy-contact__channel-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px; height: 38px;
	flex-shrink: 0;
	background: rgba(198, 187, 60, 0.12);
	color: var(--color-gold);
	border-radius: var(--radius-md);
}
.kfy-contact__channel-body {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}
.kfy-contact__channel-label {
	font-family: var(--font-display);
	letter-spacing: 1.5px;
	text-transform: uppercase;
	font-size: 12px;
	color: var(--text-secondary);
}
.kfy-contact__channel-value {
	color: var(--color-cream);
	font-size: 17px;
	line-height: 1.35;
	word-break: break-word;
}
a.kfy-contact__channel-value {
	text-decoration: none;
	transition: color var(--ease-default);
}
a.kfy-contact__channel-value:hover { color: var(--color-gold); }

.kfy-contact__channel-sub {
	color: var(--color-gold);
	font-size: 13px;
	text-decoration: none;
	margin-top: 2px;
	border-bottom: 1px dashed rgba(198, 187, 60, 0.4);
	align-self: flex-start;
	transition: color var(--ease-default), border-color var(--ease-default);
}
.kfy-contact__channel-sub:hover {
	color: var(--color-burnt-orange);
	border-bottom-color: var(--color-burnt-orange);
}

/* ---------- Hours block ---------- */
.kfy-contact__hours {
	background: rgba(0, 0, 0, 0.2);
	border-radius: var(--radius-md);
	padding: var(--sp-4);
	margin-bottom: var(--sp-5);
}
.kfy-contact__hours-title {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0 0 var(--sp-3);
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1.5px;
	text-transform: uppercase;
	color: var(--color-gold);
}
.kfy-contact__hours-list {
	list-style: none;
	margin: 0; padding: 0;
	display: grid;
	gap: 4px;
}
.kfy-contact__hours-row {
	display: flex;
	justify-content: space-between;
	gap: var(--sp-3);
	font-size: 14px;
	color: var(--text-primary);
	padding: 4px 0;
}
.kfy-contact__hours-day {
	color: var(--text-secondary);
}
.kfy-contact__hours-row.is-today {
	color: var(--color-gold);
	font-weight: 600;
}
.kfy-contact__hours-row.is-today .kfy-contact__hours-day {
	color: var(--color-gold);
}
.kfy-contact__hours-row.is-today::after {
	content: "TODAY";
	font-family: var(--font-display);
	font-size: 10px;
	letter-spacing: 1.5px;
	background: var(--color-gold);
	color: var(--color-near-black);
	padding: 2px 6px;
	border-radius: var(--radius-sm);
	margin-left: 8px;
	align-self: center;
}

.kfy-contact__credentials {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2) var(--sp-4);
}
.kfy-contact__cred {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-size: 13px;
	color: var(--text-secondary);
}
.kfy-contact__cred svg {
	color: var(--color-gold);
}

/* ---------- Form column (right) - reuses .kfy-hero__form-wrap ---------- */
.kfy-contact__form-col {
	min-width: 0;
}
.kfy-contact__form-wrap {
	scroll-margin-top: 96px; /* account for sticky header on anchor jump */
}
.kfy-contact__form { gap: var(--sp-4); }
.kfy-contact__row {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--sp-4);
}
@media (min-width: 560px) {
	.kfy-contact__row {
		grid-template-columns: 1fr 1fr;
	}
}
.kfy-contact__form textarea {
	width: 100%;
	padding: 14px;
	border: 1px solid rgba(142, 68, 32, 0.3);
	background: #fff;
	color: var(--color-dark-brown);
	border-radius: var(--radius-md);
	font-family: var(--font-body);
	font-size: 17px;
	line-height: 1.5;
	resize: vertical;
	min-height: 110px;
	transition: border-color var(--ease-default), box-shadow var(--ease-default);
}
.kfy-contact__form textarea:focus {
	outline: none;
	border-color: var(--color-gold);
	box-shadow: 0 0 0 3px rgba(198, 187, 60, 0.25);
}
.kfy-contact__form label span[aria-hidden="true"] {
	color: var(--color-red);
	margin-left: 2px;
}

/* Honeypot - visually + accessibly hidden, but still POSTs to the server */
.kfy-contact__honeypot {
	position: absolute !important;
	left: -10000px !important;
	top: auto !important;
	width: 1px !important;
	height: 1px !important;
	overflow: hidden !important;
}

/* Visually-hidden helper for assistive-tech-only text. Mirrors the WordPress
   .screen-reader-text pattern but namespaced so it's safe inside any block. */
.kfy-sr-only {
	border: 0 !important;
	clip: rect(1px, 1px, 1px, 1px) !important;
	-webkit-clip-path: inset(50%) !important;
	clip-path: inset(50%) !important;
	height: 1px !important;
	margin: -1px !important;
	overflow: hidden !important;
	padding: 0 !important;
	position: absolute !important;
	width: 1px !important;
	white-space: nowrap !important;
}

/* Required-field legend at the top of the form. */
.kfy-contact__required-hint {
	margin: 0 0 var(--sp-3);
	font-size: 13px;
	color: var(--text-muted);
	line-height: 1.4;
}
.kfy-contact__required-hint span[aria-hidden="true"] {
	color: var(--color-red);
	font-weight: 700;
	margin-right: 4px;
}

/* Explicit visible focus on every interactive surface inside the contact
   block - WCAG 2.4.7 (Focus Visible) compliance, especially for keyboard
   users on the dark wrap-bg variant where the default browser ring blends
   into the background. */
.kfy-contact a:focus-visible,
.kfy-contact button:focus-visible {
	outline: 3px solid var(--color-gold);
	outline-offset: 3px;
	border-radius: var(--radius-sm);
}
.kfy-contact .kfy-hero__form input:focus-visible,
.kfy-contact .kfy-hero__form select:focus-visible,
.kfy-contact .kfy-hero__form textarea:focus-visible,
.kfy-contact__form textarea:focus-visible {
	outline: 3px solid var(--color-gold);
	outline-offset: 1px;
}

/* ---------- Result banners ---------- */
.kfy-contact__banner {
	display: flex;
	align-items: flex-start;
	gap: var(--sp-3);
	padding: var(--sp-4);
	border-radius: var(--radius-md);
	margin-bottom: var(--sp-4);
	font-size: 15px;
	line-height: 1.45;
}
.kfy-contact__banner > div {
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.kfy-contact__banner strong {
	font-family: var(--font-display);
	letter-spacing: 1px;
	text-transform: uppercase;
	font-size: 14px;
}
.kfy-contact__banner svg {
	flex-shrink: 0;
	margin-top: 2px;
}
.kfy-contact__banner--success {
	background: rgba(110, 167, 89, 0.18);
	border: 1px solid rgba(110, 167, 89, 0.4);
	color: #2f5121;
}
.kfy-contact__banner--success strong { color: #2f5121; }
.kfy-contact__banner--success svg { color: #2f5121; }

.kfy-contact__banner--error {
	background: rgba(205, 54, 44, 0.12);
	border: 1px solid rgba(205, 54, 44, 0.4);
	color: #7a1c16;
}
.kfy-contact__banner--error strong { color: #7a1c16; }
.kfy-contact__banner--error svg { color: var(--color-red); }

/* =========================================================================
 * §11. Volt Vikings Blend - Architecture & Brand-Voice Layer
 * (per design_spec.md §11)
 *
 * Adds:
 *   .kfy-tm                 Trademarked-ritual term (kfy_tm helper)
 *   .kfy-page-hero          Eyebrow + headline + supporting hero
 *   .kfy-values-pillars     4-pillar Down Under Code grid
 *   .kfy-positioning-panel  Full-bleed maroon brand statement
 *   .kfy-why-choose         6-card icon-free reasons grid
 *   .kfy-area-sweep         Long-form text city list
 * ========================================================================= */

/* --- Trademarked ritual term (DownUnder Check™ etc.) ---------------------- */
.kfy-tm {
	white-space: nowrap;
	color: var(--pdu-brown-deep);
	font-weight: 600;
}
.kfy-section--dark .kfy-tm,
.kfy-positioning-panel .kfy-tm,
.kfy-trust .kfy-tm,
.kfy-footer .kfy-tm {
	color: var(--pdu-cream);
}
/* v2.7.3: dropped the orange highlight on the FIRST trademark mention.
   It was reading off-brand inside the hero subtitle (a single orange
   word floating in a cream paragraph). The dotted underline-on-hover
   is kept so the term still announces itself as a coined ritual term
   without colouring outside the surrounding copy. */
.kfy-tm--first {
	color: inherit;
	border-bottom: 1px dotted transparent;
	transition: border-color 160ms ease;
}
.kfy-tm--first:hover { border-bottom-color: currentColor; }
.kfy-tm__mark {
	font-size: 0.6em;
	margin-left: 1px;
	font-weight: 600;
	vertical-align: super;
	line-height: 1;
}

/* --- Page hero (non-homepage) ---------------------------------------------
   The floating header (.kfy-header is position:fixed) sits over the top
   of every page. We bump the page-hero TOP padding so the eyebrow/title
   never tucks behind the nav island. The bottom padding keeps the
   original generous rhythm. ~160px clears the ~144px header zone with
   a little breathing room on every breakpoint. */
.kfy-page-hero {
	padding: clamp(160px, 14vw, 200px) 0 clamp(var(--sp-10), 8vw, var(--sp-12));
	background:
		radial-gradient(ellipse at 80% 0%, rgba(247, 199, 59, 0.12), transparent 60%),
		radial-gradient(ellipse at 0% 100%, rgba(178, 58, 44, 0.18), transparent 60%),
		linear-gradient(180deg, var(--pdu-brown-deep) 0%, #2A1810 100%);
	color: var(--text-primary);
	border-bottom: 4px solid var(--pdu-brand-orange);
}
.kfy-page-hero--center { text-align: center; }
.kfy-page-hero--left   { text-align: left; }

.kfy-page-hero__eyebrow {
	display: inline-flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 8px 12px;
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 2.5px;
	text-transform: uppercase;
	color: var(--pdu-sunset-yellow);
	background: rgba(247, 199, 59, 0.10);
	border: 1px solid rgba(247, 199, 59, 0.35);
	padding: 6px 14px;
	border-radius: var(--radius-full);
	margin: 0 0 var(--sp-5);
}
/* CSS-managed proof-point separator (see kfy-helpers.php → kfy_page_hero).
   Renders a small filled circle between adjacent <span>s so the markup
   never depends on the U+00B7 glyph existing in any custom font. */
.kfy-page-hero__eyebrow-item {
	display: inline-flex;
	align-items: center;
}
.kfy-page-hero__eyebrow-item + .kfy-page-hero__eyebrow-item::before {
	content: "";
	display: inline-block;
	width: 4px;
	height: 4px;
	margin-right: 12px;
	background: currentColor;
	border-radius: 50%;
	opacity: 0.7;
}
.kfy-page-hero__headline {
	font-family: var(--font-display);
	font-size: var(--fs-h1);
	line-height: 1.05;
	margin: 0 0 var(--sp-4);
	color: var(--pdu-cream);
	text-wrap: balance;
}
.kfy-page-hero__supporting {
	font-family: var(--font-body);
	font-size: clamp(18px, 1vw + 16px, 22px);
	line-height: 1.55;
	color: var(--text-secondary);
	max-width: 56ch;
	margin: 0 auto;
}
.kfy-page-hero--left .kfy-page-hero__supporting { margin: 0; }
.kfy-page-hero__cta { margin-top: var(--sp-6); }

/* --- §11.2 Values Pillars (Down Under Code) ------------------------------- */
.kfy-values-pillars {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background:
		radial-gradient(ellipse at 50% 0%, rgba(77, 38, 69, 0.45), transparent 70%),
		linear-gradient(180deg, var(--pdu-brown-deep) 0%, #2A1810 100%);
	color: var(--text-primary);
}
/* v2.7: Faded vector-scene texture sits behind the dark gradient so the
   section picks up the same warm Australian-outback identity as the
   rest of the brand surfaces. mix-blend-mode: screen lifts the warm
   amber tones onto the eggplant base without bleaching the cream copy
   stacked above. Opacity 0.10 keeps the pattern as a subliminal accent —
   it reads as warmth, not a competing photograph. */
.kfy-values-pillars::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: url("../img/vector%20scene.jpg");
	background-position: center;
	background-size: cover;
	background-repeat: no-repeat;
	opacity: 0.10;
	mix-blend-mode: screen;
	pointer-events: none;
	z-index: 0;
}
.kfy-values-pillars > .kfy-container { position: relative; z-index: 1; }
.kfy-section-label--on-dark {
	color: var(--pdu-sunset-yellow);
	background: rgba(247, 199, 59, 0.10);
	border-color: rgba(247, 199, 59, 0.35);
}
.kfy-section-title--on-dark { color: var(--pdu-cream); }
.kfy-values-pillars__intro {
	font-size: var(--fs-body-lg);
	line-height: 1.6;
	color: var(--text-secondary);
	max-width: 60ch;
	margin: var(--sp-4) auto 0;
}
.kfy-values-pillars__grid {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	/* v2.7: tightened gap so the new vertical divider hairlines visually
	   anchor the columns instead of floating in dead space between cards. */
	gap: var(--sp-3);
	margin-top: var(--sp-8);
}
@media (max-width: 960px) {
	.kfy-values-pillars__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--sp-4);
	}
}
@media (max-width: 540px) {
	.kfy-values-pillars__grid {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--sp-4);
	}
}
.kfy-values-pillar {
	background: rgba(251, 239, 217, 0.04);
	border: 1px solid rgba(251, 239, 217, 0.10);
	border-top: 3px solid var(--pdu-brand-orange);
	border-radius: var(--radius-md, 12px);
	/* v2.7: trimmed vertical padding by one step so the cards read as
	   "panels in a row" rather than floating chips, per the reference
	   layout. Horizontal padding stays at sp-6 for breathing room. */
	padding: var(--sp-5) var(--sp-6);
	display: flex;
	flex-direction: column;
	/* v2.7: center icon + title + body so the pillars match the
	   reference layout (centered icon medallion above centered copy)
	   instead of left-aligning everything to the card edge. */
	align-items: center;
	text-align: center;
	gap: var(--sp-3);
	transition: transform 200ms ease, border-color 200ms ease, background 200ms ease, box-shadow 200ms ease;
	/* Single low-opacity drop instead of the default uplift so dividers
	   read as the dominant visual rhythm between columns. */
	box-shadow: 0 4px 12px -8px rgba(15, 8, 6, 0.45);
}
.kfy-values-pillar:hover {
	transform: translateY(-4px);
	background: rgba(251, 239, 217, 0.07);
	border-color: rgba(251, 239, 217, 0.18);
	box-shadow: 0 10px 24px -12px rgba(15, 8, 6, 0.55);
}
/* Hairline vertical dividers between columns at the 4-up breakpoint
   only — below 961px the cards stack to 2-up or 1-up and the dividers
   would otherwise appear *between rows*, which reads as broken UI.
   Sits 1px to the right of every pillar except the last in each row of
   four (and the very last pillar). */
@media (min-width: 961px) {
	.kfy-values-pillar:not(:nth-child(4n)):not(:last-child)::after {
		content: "";
		position: absolute;
		top: 16%;
		bottom: 16%;
		right: calc(var(--sp-3) / -2);
		width: 1px;
		background: linear-gradient(
			180deg,
			rgba(251, 239, 217, 0) 0%,
			rgba(251, 239, 217, 0.18) 30%,
			rgba(251, 239, 217, 0.18) 70%,
			rgba(251, 239, 217, 0) 100%
		);
		pointer-events: none;
	}
	.kfy-values-pillar { position: relative; }
}
.kfy-values-pillar__icon {
	width: 56px;
	height: 56px;
	border-radius: var(--radius-full);
	background: rgba(247, 199, 59, 0.14);
	color: var(--pdu-sunset-yellow);
	display: inline-flex;
	align-items: center;
	justify-content: center;
}
.kfy-values-pillar__title {
	font-family: var(--font-display);
	font-size: var(--fs-h4);
	line-height: 1.15;
	color: var(--pdu-cream);
	margin: 0;
	letter-spacing: 0.5px;
}
.kfy-values-pillar__body {
	font-size: var(--fs-body);
	line-height: 1.6;
	color: var(--text-secondary);
	margin: 0;
	max-width: 32ch;
	margin-inline: auto;
}
.kfy-values-pillars__cta {
	text-align: center;
	margin-top: var(--sp-8);
}

/* --- §11.6 Positioning Panel ---------------------------------------------- */
.kfy-positioning-panel {
	background:
		radial-gradient(ellipse at 0% 0%, rgba(247, 199, 59, 0.10), transparent 55%),
		radial-gradient(ellipse at 100% 100%, rgba(178, 58, 44, 0.20), transparent 60%),
		linear-gradient(135deg, var(--pdu-maroon) 0%, #3A1F37 60%, #2A1A28 100%);
	color: var(--pdu-cream);
	padding: clamp(var(--sp-10), 8vw, var(--sp-12)) 0;
	border-block: 4px solid var(--pdu-brand-orange);
	position: relative;
	overflow: hidden;
}
.kfy-positioning-panel::before {
	content: "";
	position: absolute;
	inset: 0;
	background:
		radial-gradient(circle at 20% 20%, rgba(247, 199, 59, 0.05), transparent 40%);
	pointer-events: none;
}
.kfy-positioning-panel__inner {
	position: relative;
	max-width: 800px;
	margin: 0 auto;
	text-align: center;
}
.kfy-positioning-panel__headline {
	font-family: var(--font-display);
	font-size: var(--fs-h2);
	line-height: 1.1;
	color: var(--pdu-cream);
	margin: 0 0 var(--sp-5);
	text-wrap: balance;
	letter-spacing: 0.5px;
}
.kfy-positioning-panel__body {
	font-size: clamp(18px, 1vw + 16px, 22px);
	line-height: 1.6;
	color: var(--text-secondary);
	margin: 0;
	text-wrap: pretty;
}

/* --- About Overview (why-us conversion panel, sits above Services) -------
   Solution-aware pivot block. Two-column layout: short positioning copy +
   flat checkmark differentiator list + single primary CTA on the left,
   happy-homeowners photo on the right. Visual reference = clean cream
   panel (no card tiles around bullets, no photo glow). The panel acts as
   a calm light-band between the dark hero/quick-actions stack above and
   the photo-led services grid below.
   ------------------------------------------------------------------------ */
.kfy-about-overview {
	background: var(--pdu-cream);
	color: var(--text-on-light);
	/* v2.5: padding-top intentionally heavier than padding-bottom so the
	   panel has visible breathing room from the dark Quick Actions strip
	   above (the previous build relied on undefined --sp-14 and silently
	   collapsed to 0). The bottom padding is a touch lighter because the
	   wave divider on ::after handles the visual hand-off into Services. */
	padding: clamp(var(--sp-12), 9vw, var(--sp-14)) 0
	         clamp(var(--sp-10), 7vw, var(--sp-12));
	position: relative;
	overflow: hidden;
	isolation: isolate;
}
/* Top accent — soft amber wash that fades out, so the section opens with
   a warm halo instead of a hard cream slab when it lands under the dark
   Quick Actions strip. */
.kfy-about-overview::before {
	content: "";
	position: absolute;
	top: 0; left: 0; right: 0;
	height: 120px;
	background:
		linear-gradient(
			180deg,
			rgba(239, 126, 26, 0.10) 0%,
			rgba(239, 126, 26, 0) 100%
		);
	pointer-events: none;
	z-index: 0;
}
/* v2.5: Bottom transition ribbon — Services and About Overview share the
   same cream surface, so a flat hairline disappeared and made the two
   sections feel like one giant uncut block. This adds a visible warm
   ribbon (brand orange → amber, drawn as a wave) at the bottom of
   About Overview that reads as a deliberate "section ends here" cue
   and echoes the brand sunset palette without darkening the panel. */
.kfy-about-overview::after {
	content: "";
	position: absolute;
	left: 0; right: 0;
	bottom: 0;
	height: 14px;
	background:
		linear-gradient(
			90deg,
			var(--pdu-brand-orange) 0%,
			var(--pdu-sunset-amber) 45%,
			var(--pdu-sunset-yellow) 70%,
			var(--pdu-brand-orange) 100%
		);
	-webkit-mask: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 14' preserveAspectRatio='none'%3E%3Cpath d='M0 7 C 240 0 480 14 720 7 C 960 0 1200 14 1440 7 L 1440 14 L 0 14 Z' fill='black'/%3E%3C/svg%3E") center bottom / 100% 100% no-repeat;
	mask: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 14' preserveAspectRatio='none'%3E%3Cpath d='M0 7 C 240 0 480 14 720 7 C 960 0 1200 14 1440 7 L 1440 14 L 0 14 Z' fill='black'/%3E%3C/svg%3E") center bottom / 100% 100% no-repeat;
	pointer-events: none;
	z-index: 3;
	opacity: 0.85;
}
/* Re-assert text/photo above the decorative layers so they aren't
   covered by the new wash + ribbon. */
.kfy-about-overview > .kfy-container { position: relative; z-index: 1; }

.kfy-about-overview__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-8);
	/* v2.6: stretch (not center) so the photo column matches the height
	   of the text column on desktop instead of floating mid-panel. */
	align-items: stretch;
	max-width: 1100px;
	margin: 0 auto;
}
@media (min-width: 900px) {
	.kfy-about-overview__grid {
		grid-template-columns: 1fr 1fr;
		gap: var(--sp-10);
	}
}

/* ---- Text column ---- */
.kfy-about-overview__text {
	max-width: 540px;
}

.kfy-about-overview__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin: 0 0 var(--sp-5);
	padding: 6px 14px;
	background: rgba(239, 126, 26, 0.12);
	color: var(--pdu-orange-accessible);
	border: 1px solid rgba(239, 126, 26, 0.35);
	border-radius: var(--radius-full);
	font-family: var(--font-display);
	font-size: 13px;
	letter-spacing: 1px;
	text-transform: uppercase;
	font-variant-numeric: lining-nums tabular-nums;
}
.kfy-about-overview__eyebrow .kfy-icon { color: var(--pdu-brand-orange); }

.kfy-about-overview__headline {
	font-family: var(--font-display);
	font-size: clamp(28px, 3vw + 0.5rem, 40px);
	line-height: 1.1;
	color: var(--pdu-brown-deep);
	margin: 0 0 var(--sp-4);
	text-wrap: balance;
	letter-spacing: 0.2px;
}

.kfy-about-overview__body {
	font-size: clamp(15px, 0.4vw + 14px, 17px);
	line-height: 1.65;
	color: var(--pdu-brown-soft);
	margin: 0 0 var(--sp-6);
	max-width: 56ch;
	text-wrap: pretty;
}

/* ---- Differentiator bullets (flat checkmark list, no tiles) ---- */
.kfy-about-overview__bullets {
	list-style: none;
	margin: 0 0 var(--sp-7);
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--sp-3);
}
.kfy-about-overview__bullet {
	display: flex;
	align-items: center;
	gap: 12px;
	background: transparent;
	border: 0;
	box-shadow: none;
	padding: 0;
	border-radius: 0;
}
.kfy-about-overview__bullet-icon {
	width: 24px;
	height: 24px;
	display: inline-grid;
	place-items: center;
	color: var(--pdu-brand-orange);
	flex-shrink: 0;
	background: none;
	box-shadow: none;
	border-radius: 0;
}
.kfy-about-overview__bullet-icon .kfy-icon {
	color: var(--pdu-brand-orange);
	stroke-width: 3;
}
.kfy-about-overview__bullet-text {
	font-family: var(--font-body);
	font-weight: 700;
	font-size: clamp(15px, 0.3vw + 14px, 17px);
	line-height: 1.4;
	color: var(--pdu-brown-deep);
}

/* ---- CTA button (sits below bullets, left-aligned with text) ---- */
.kfy-about-overview__cta {
	margin-top: var(--sp-2);
	display: inline-flex;
	align-items: center;
	gap: 10px;
	padding: 16px 28px;
	font-size: 15px;
	letter-spacing: 0.5px;
	min-height: 56px;
}
.kfy-about-overview__cta .kfy-icon {
	flex-shrink: 0;
}

/* ---- Photo column (full photograph, height-matched to text column) ----
   v2.6: The previous image was a transparent PNG cut-out, so it was
   "anchored to the ground" with a negative bottom margin. The current
   image is a full landscape photograph — anchoring it to the bottom
   edge would crop the homeowners and look broken. Instead the photo
   column now stretches to match the height of the text column (grid
   align-items: stretch is on by default for the parent), the image
   object-fits inside a rounded card, and a soft warm border + shadow
   sit it cleanly on the cream surface. */
.kfy-about-overview__photo {
	position: relative;
	display: flex;
	justify-content: center;
	align-items: stretch;
	align-self: stretch;
	min-height: 320px;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--pdu-sand);
	border: 1px solid rgba(142, 68, 32, 0.18);
	box-shadow:
		0 1px 2px rgba(58, 31, 18, 0.08),
		0 18px 40px -18px rgba(58, 31, 18, 0.28);
}
.kfy-about-overview__photo-img {
	position: relative;
	z-index: 1;
	width: 100%;
	height: 100%;
	max-width: none;
	display: block;
	object-fit: cover;
	/* Bias the crop slightly toward the upper portion of the photo so
	   the homeowners' faces stay in the safe area at any aspect ratio. */
	object-position: center 30%;
}

/* Mobile: photo stacks above the text. Cap its height so the page
   doesn't open with a 100vh photo on small phones, but let it grow on
   tablets where there's more vertical room. */
@media (max-width: 899px) {
	.kfy-about-overview__text { max-width: none; }
	.kfy-about-overview__photo {
		order: -1;
		min-height: 0;
		height: clamp(260px, 55vw, 420px);
		align-items: stretch;
	}
	.kfy-about-overview__headline { font-size: clamp(24px, 6vw, 30px); }
	.kfy-about-overview__cta { width: 100%; justify-content: center; }
}

/* --- §11.7 Why Choose grid (no icons, copy-first) ------------------------- */
.kfy-why-choose {
	padding: clamp(var(--sp-10), 8vw, var(--sp-12)) 0;
	background: var(--pdu-cream);
	color: var(--text-on-light);
}
.kfy-why-choose__grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--sp-5);
	margin-top: var(--sp-8);
}
@media (max-width: 900px) {
	.kfy-why-choose__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 540px) {
	.kfy-why-choose__grid { grid-template-columns: minmax(0, 1fr); }
}
.kfy-why-choose__card {
	background: var(--pdu-white);
	border: 1px solid rgba(58, 31, 18, 0.10);
	border-left: 4px solid var(--pdu-brand-orange);
	border-radius: var(--radius-md, 10px);
	padding: var(--sp-6);
	box-shadow: var(--shadow-sm);
	transition: transform 200ms ease, box-shadow 200ms ease;
}
.kfy-why-choose__card:hover {
	transform: translateY(-2px);
	box-shadow: var(--shadow-md);
}
.kfy-why-choose__title {
	font-family: var(--font-accent);
	font-size: var(--fs-h4);
	line-height: 1.2;
	color: var(--pdu-brown-deep);
	margin: 0 0 var(--sp-3);
}
.kfy-why-choose__body {
	font-size: var(--fs-body);
	line-height: 1.55;
	color: var(--text-muted);
	margin: 0;
}

/* --- §11.8 Area Sweep (text-only city list) ------------------------------- */
.kfy-area-sweep {
	padding: clamp(var(--sp-10), 8vw, var(--sp-12)) 0;
	background: var(--pdu-sand);
	color: var(--text-on-light);
}
.kfy-area-sweep__intro {
	font-size: var(--fs-body-lg);
	line-height: 1.6;
	color: var(--text-muted);
	max-width: 60ch;
	margin: var(--sp-4) auto 0;
}
.kfy-area-sweep__list {
	list-style: none;
	margin: var(--sp-8) auto 0;
	padding: 0;
	max-width: 720px;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--sp-3) var(--sp-2);
	font-family: var(--font-accent);
	font-size: clamp(18px, 1vw + 16px, 22px);
	line-height: 1.5;
	color: var(--pdu-brown-deep);
	text-align: center;
}
.kfy-area-sweep__item {
	display: inline-flex;
	align-items: center;
}
.kfy-area-sweep__item:not(:last-child)::after {
	content: "·";
	margin-left: var(--sp-2);
	color: var(--pdu-brand-orange);
	font-weight: 700;
}
.kfy-area-sweep__city {
	color: var(--pdu-brown-deep);
}
.kfy-area-sweep__city--link {
	color: var(--pdu-orange-accessible);
	text-decoration: none;
	border-bottom: 1px dotted transparent;
	transition: border-color 160ms ease, color 160ms ease;
}
.kfy-area-sweep__city--link:hover,
.kfy-area-sweep__city--link:focus-visible {
	border-bottom-color: currentColor;
	color: var(--pdu-brown-deep);
}
.kfy-area-sweep__city--link:focus-visible {
	outline: 2px solid var(--pdu-brand-orange);
	outline-offset: 4px;
	border-radius: 2px;
}
.kfy-area-sweep__trailing {
	font-style: italic;
	color: var(--text-muted);
	font-size: 0.9em;
}
.kfy-area-sweep__cta {
	text-align: center;
	margin-top: var(--sp-8);
}

/* =========================================================================
   2.1.1 — Real photography wiring (services, trust, final-CTA, about)
   ========================================================================= */

/* Service-card image: lift the photo a touch and ensure the bottom scrim
   reads against any photo, not just the brown gradient placeholder. */
.kfy-service-card__image {
	background-color: var(--color-deep-brown); /* fallback while image loads */
}
.kfy-service-card__image--placeholder {
	background: linear-gradient(135deg, var(--color-deep-brown), var(--color-warm-brown));
}

/* =========================================================================
   About story slab — full-bleed cream + halftone + two-column grid (v2.7)
   --------------------------------------------------------------------------
   The whole section is a full-viewport-width cream band (matches the other
   full-bleed sections on the site like .kfy-services / .kfy-trust). Inside,
   a 4-column grid with auto gutter columns keeps the actual reading area
   centred at ~1040px, with the sticky owner photo pinned in the left
   content column and the H2 + paragraph chunks flowing into the right.

   The .kfy-about-story node is a wp-block-group with `is-layout-constrained`
   AND inline `style="padding-*"` from WP's spacing controls, which together
   would otherwise (a) cap it inside the post-content content-size and (b)
   add WP's own side padding on top of our grid gutters. We escape the
   constrained parent with the negative-margin / 100vw trick, and override
   the inline padding with !important padding-inline: 0 (vertical padding
   stays from the inline style — it just sets the cream slab's height).
   ========================================================================= */
.kfy-about-story {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	/* Escape the constrained post-content wrapper so the cream slab spans
	   the full viewport. 100vw can introduce a tiny horizontal scroll on
	   sub-pixel rounding at certain widths — overflow: hidden above plus
	   the parent's existing overflow handling absorbs that safely. */
	width: 100vw;
	max-width: 100vw;
	margin-inline: calc(50% - 50vw);
	/* Wipe WP's injected horizontal padding so the grid gutter columns
	   are the single source of truth for inner alignment. The vertical
	   padding from the inline style controls the slab height. */
	padding-inline: 0 !important;
	background: var(--pdu-cream);
	color: var(--text-on-light);
	display: grid;
	/* | left gutter | photo (380px) | copy (max ~660px) | right gutter |
	   v2.7.1: bumped photo column 300 → 380 so the founder portrait
	   reads as a proper magazine-feature image, not a thumbnail. */
	grid-template-columns:
		minmax(var(--sp-5), 1fr)
		380px
		minmax(0, 660px)
		minmax(var(--sp-5), 1fr);
	column-gap: var(--sp-8);
	row-gap: 0;
	align-items: start;
}

/* Halftone patch — same recipe as .kfy-services::after, recoloured for the
   cream About slab: warm-brown dots top-right, sunset-orange dots bottom-
   left, masked into circular fades so the centre stays clean for copy. */
.kfy-about-story::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: 0;
	background-image:
		radial-gradient(circle, rgba(142, 68, 32, 0.55) 1.6px, transparent 2.2px),
		radial-gradient(circle, rgba(247, 199, 59, 0.55) 1.6px, transparent 2.2px);
	background-size: 18px 18px, 22px 22px;
	background-position: 100% 0%, 0% 100%;
	background-repeat: repeat, repeat;
	-webkit-mask-image:
		radial-gradient(circle at 100% 0%, #000 0%, transparent 32%),
		radial-gradient(circle at 0% 100%, #000 0%, transparent 36%);
	mask-image:
		radial-gradient(circle at 100% 0%, #000 0%, transparent 32%),
		radial-gradient(circle at 0% 100%, #000 0%, transparent 36%);
	-webkit-mask-composite: source-over;
	mask-composite: add;
	opacity: 0.7;
}

/* All direct story chunks (H2, P) land in the copy column (3rd grid track).
   Lifted above the halftone via z-index. Margins are owned by the headings
   and paragraphs themselves so the rhythm reads like prose, not a UI list. */
.kfy-about-story > * {
	grid-column: 3;
	position: relative;
	z-index: 1;
	margin: 0;
}
.kfy-about-story > h2 {
	font-family: var(--font-display);
	font-size: var(--fs-h3);
	color: var(--text-on-light);
	margin-top: var(--sp-6);
	margin-bottom: var(--sp-3);
	letter-spacing: 0.5px;
	/* v2.7.2: always centre the chapter headings — on desktop they
	   anchor each story chunk inside the 660px copy column, on mobile
	   they read as a poster intro above the body. */
	text-align: center;
}
.kfy-about-story > h2:first-of-type { margin-top: 0; }
.kfy-about-story > p {
	font-size: var(--fs-body);
	line-height: 1.7;
	color: var(--text-on-light);
	margin-bottom: var(--sp-4);
}
.kfy-about-story > p:last-child { margin-bottom: 0; }

/* Sticky owner photo pinned in the PHOTO column (2nd grid track — track 1
   is the left gutter). grid-row spans every row of the copy column so the
   sticky context covers the full reading distance. align-self: start keeps
   the photo from stretching to the tallest grid track. */
.kfy-about-story > .kfy-about-owner-photo {
	grid-column: 2;
	grid-row: 1 / span 99;
	position: sticky;
	top: var(--sp-6);
	align-self: start;
	margin: 0;
}
.kfy-about-story > .kfy-about-owner-photo img {
	width: 100%;
	height: auto;
	/* v2.7.1: bumped 420 → 560 so the portrait fills the wider 380px
	   photo column with a proper 2:3 magazine ratio (~380 × ~560).
	   object-position keeps Joey's face anchored at the top third when
	   the photo crops on shorter viewports. */
	max-height: 560px;
	object-fit: cover;
	object-position: center 25%;
	border-radius: var(--radius-lg, 16px);
	box-shadow: 0 16px 40px rgba(41, 22, 16, 0.22);
}
.kfy-about-story > .kfy-about-owner-photo .wp-element-caption {
	margin-top: var(--sp-3);
	text-align: center;
	font-family: var(--font-accent);
	font-size: 0.95rem;
	color: var(--text-muted);
	font-style: italic;
}

/* Tablet: collapse the 2-up content to a single centred column with auto
   gutters. Photo unhooks from sticky, sits on top of the copy block. */
@media (max-width: 860px) {
	.kfy-about-story {
		grid-template-columns:
			minmax(var(--sp-5), 1fr)
			minmax(0, 700px)
			minmax(var(--sp-5), 1fr);
		column-gap: 0;
	}
	.kfy-about-story > * { grid-column: 2; }
	.kfy-about-story > .kfy-about-owner-photo {
		position: static;
		grid-row: auto;
		max-width: 360px;
		margin: 0 auto var(--sp-5);
	}
}

/* =========================================================================
   VISUAL POLISH — sand-grain texture + hairline borders on dark sections
   v2.3 (2026-04). Reuses --pdu-grain (defined in :root) on every dark
   surface to add an "outback paper" warmth without touching the cream
   light sections (Quick Actions, Services, Social Proof, Process, FAQ,
   About Overview). Borders alternate between full hairlines (dark cards)
   and etched top/bottom dividers (full-bleed sections) so the design
   reads as a unified system without becoming monotonous.
   ========================================================================= */

/* ---- Grain layer applied via ::after on each dark surface. ---------
   - mix-blend-mode: overlay tints existing pixels rather than covering
     them, so the grain warms dark surfaces without lifting their value.
   - pointer-events: none keeps every interactive element underneath
     fully clickable.
   - opacity 0.55 reads as fine paper grain at 100% zoom and dissolves
     gracefully at 50% zoom (no visible aliasing).
   - z-index: 1 on full-width sections matches the existing scrim layer
     so the grain paints just above the scrim and under .kfy-*__inner
     content (which already sits at z-index: 2). */
.kfy-hero::after,
.kfy-trust::after,
.kfy-final-cta::after,
.kfy-service-areas__card::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: var(--pdu-grain);
	background-repeat: repeat;
	mix-blend-mode: overlay;
	opacity: 0.55;
	pointer-events: none;
	z-index: 1;
}

/* The Service Areas card already z-stacks: ::before eggplant-gradient
   (z -1), card surface (z 0), card content (z 1). Grain sits at z 0
   (above the gradient overlay, below text) and inherits the rounded
   corners so it doesn't bleed past the card edge. */
.kfy-service-areas__card::after {
	z-index: 0;
	border-radius: inherit;
}

/* ---- Hairline borders on dark cards ---- */
/* v2.4: Bumped from 1px hairline → 4px solid brand-orange frame on all
   sides so the card reads as a confidently framed unit (matches the
   reference's prominent teal/navy border around the coverage card).
   The orange ties to the sunset scene inside and the brand palette;
   pairing it with an inner 1px cream highlight gives the frame a
   subtle "two-line" depth without using a true CSS double border. */
.kfy-service-areas__card {
	border: 4px solid var(--pdu-brand-orange);
	box-shadow:
		inset 0 0 0 1px rgba(243, 230, 196, 0.28),
		0 24px 56px rgba(41, 22, 16, 0.45);
}

/* ---- Etched dividers on full-bleed dark sections ---- */
.kfy-trust,
.kfy-final-cta {
	/* Cream highlight on top + dark groove on bottom = "etched into the
	   page" effect that gives each band a clear edge without using
	   harsh full-saturation lines. */
	border-top: 1px solid rgba(243, 230, 196, 0.10);
	border-bottom: 1px solid rgba(0, 0, 0, 0.35);
}
.kfy-hero {
	/* Hero only gets the bottom edge (its top is the page edge under
	   the floating header island). */
	border-bottom: 1px solid rgba(0, 0, 0, 0.35);
}

/* =========================================================================
   kfy-quote-band — Sunset hero with inline lead form.
   --------------------------------------------------------------------------
   Used at the top of /services/ as a friendlier, conversion-focused
   replacement for the standard kfy/page-hero. Visually echoes the
   homepage hero (warm sunset palette + drifting clouds) but in a
   slim, single-row layout where the headline sits above a 3-field
   form (Name / Email / Phone) and a glove-red CTA.

   Background recipe (matches .kfy-hero):
     1. background-color = eggplant-deep (final fallback)
     2. .kfy-quote-band__scene = vector scene photo (z 0)
     3. .kfy-quote-band__scene::after = warm sunset overlay (z 0)
        Same warm radials + linear darken as the homepage hero, but
        ~25% lighter on the linear scrim so the bg still reads as
        "bright sunset" rather than "dusk".
   ========================================================================= */
.kfy-quote-band {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	padding: clamp(140px, 12vw, 180px) 0 clamp(var(--sp-10), 8vw, var(--sp-12));
	color: var(--color-cream);
	border-bottom: 4px solid var(--pdu-brand-orange);
	background-color: var(--pdu-eggplant-deep);
	/* Sunset-fallback gradient mirrors .kfy-hero so the band still
	   reads on-brand if the vector scene image fails to load. */
	background-image:
		radial-gradient(ellipse at 80% 0%,  rgba(247, 199, 59, 0.28), transparent 60%),
		radial-gradient(ellipse at 0% 100%, rgba(178, 58, 44, 0.32),  transparent 60%),
		linear-gradient(180deg,
			#5C3A28 0%,
			var(--pdu-maroon) 45%,
			var(--pdu-eggplant) 78%,
			var(--pdu-eggplant-deep) 100%
		);
	background-size: cover;
	background-position: center;
}

.kfy-quote-band__scene {
	position: absolute;
	inset: 0;
	z-index: 0;
	background-repeat: no-repeat;
	background-position: center 35%;
	background-size: cover;
}
/* Warm sunset overlay — matches .kfy-hero::before exactly so the
   page-to-page atmosphere is identical: warm yellow glow at top
   right, maroon ground-glow at bottom left, gentle 0.20 → 0.55
   linear darken from top to bottom for AA cream-text contrast. */
.kfy-quote-band__scene::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		radial-gradient(ellipse at 80% 0%,  rgba(247, 199, 59, 0.10), transparent 60%),
		radial-gradient(ellipse at 0% 100%, rgba(142, 68, 32, 0.20), transparent 60%),
		linear-gradient(180deg,
			rgba(41, 22, 16, 0.20) 0%,
			rgba(41, 22, 16, 0.35) 60%,
			rgba(41, 22, 16, 0.55) 100%
		);
	pointer-events: none;
}

/* Drifting clouds — same SVG silhouette + keyframes as the homepage
   hero so the brand language stays consistent. Opacity is bumped a
   touch higher here because the bg has more saturation. */
.kfy-quote-band__clouds {
	position: absolute;
	inset: 0;
	z-index: 1;
	overflow: hidden;
	pointer-events: none;
}
.kfy-quote-band__cloud {
	position: absolute;
	top: 0;
	display: block;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80'><g fill='%23ffffff' opacity='0.92'><ellipse cx='50' cy='52' rx='40' ry='22'/><ellipse cx='100' cy='38' rx='52' ry='30'/><ellipse cx='150' cy='52' rx='40' ry='22'/></g></svg>");
	will-change: transform;
}
.kfy-quote-band__cloud--1 { top: 12%; width: 220px; height: 88px;  opacity: 0.55; }
.kfy-quote-band__cloud--2 { top: 22%; width: 160px; height: 64px;  opacity: 0.40; }
.kfy-quote-band__cloud--3 { top: 6%;  width: 280px; height: 112px; opacity: 0.65; }
@media (prefers-reduced-motion: no-preference) {
	.kfy-quote-band__cloud--1 { animation: kfy-cloud-drift 75s linear infinite;  animation-delay: -10s; }
	.kfy-quote-band__cloud--2 { animation: kfy-cloud-drift 110s linear infinite; animation-delay: -55s; }
	.kfy-quote-band__cloud--3 { animation: kfy-cloud-drift 90s linear infinite;  animation-delay: -30s; }
}
@media (prefers-reduced-motion: reduce) {
	.kfy-quote-band__cloud--1 { transform: translate3d(15vw, 0, 0); }
	.kfy-quote-band__cloud--2 { transform: translate3d(55vw, 0, 0); }
	.kfy-quote-band__cloud--3 { transform: translate3d(78vw, 0, 0); }
}

.kfy-quote-band__inner {
	position: relative;
	z-index: 2;
	text-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--sp-4);
}

/* Eyebrow — rendered as inline-flex spans with a CSS-managed dot
   between them. Avoids relying on a literal U+00B7 in the source
   string (which historically leaked "u00b7" placeholder text).
   Visually matches .kfy-hero__owner-pill: warm-brown chip with a
   sunset-yellow border and cream text — same brand language as the
   homepage hero's "Family-Owned" pill. */
.kfy-quote-band__eyebrow {
	margin: 0 0 var(--sp-2);
	display: inline-flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 8px 12px;
	font-family: var(--font-display);
	font-size: 14px;
	letter-spacing: 1px;
	text-transform: uppercase;
	color: var(--color-cream);
	background: rgba(142, 68, 32, 0.4);
	border: 1px solid rgba(198, 187, 60, 0.4);
	padding: 6px 14px;
	border-radius: var(--radius-full);
}
.kfy-quote-band__eyebrow-item {
	position: relative;
	display: inline-flex;
	align-items: center;
}
.kfy-quote-band__eyebrow-item + .kfy-quote-band__eyebrow-item::before {
	content: "";
	display: inline-block;
	width: 4px;
	height: 4px;
	margin-right: 12px;
	background: var(--color-gold);
	border-radius: 50%;
	opacity: 0.85;
}

/* Headline — uses the same typography contract as .kfy-hero__title
   (var(--font-hero), weight 900, mixed-case, size scale + letter
   spacing) so the page-to-page voice stays consistent. */
.kfy-quote-band__headline {
	margin: 0 0 var(--sp-3);
	font-family: var(--font-hero);
	font-weight: 900;
	font-size: clamp(28px, 3.4vw + 0.5rem, 44px);
	line-height: 1.08;
	letter-spacing: -0.005em;
	color: var(--color-cream);
	text-wrap: balance;
	hyphens: manual;
	overflow-wrap: break-word;
	word-spacing: -0.01em;
	max-width: 22ch;
	/* Cream display on the warm sunset scrim — same text-shadow
	   safety net used on .kfy-hero so the headline is legible even
	   over the brightest pixels of the sun area. */
	text-shadow:
		0 1px 2px  rgba(15, 8, 6, 0.85),
		0 2px 12px rgba(15, 8, 6, 0.55);
}

/* Supporting line — mirrors .kfy-hero__subtitle exactly. */
.kfy-quote-band__supporting {
	margin: 0;
	max-width: 560px;
	font-family: var(--font-body);
	font-size: clamp(18px, 1vw + 16px, 21px);
	line-height: 1.6;
	color: var(--color-cream);
	text-shadow: 0 1px 2px rgba(27, 17, 12, 0.6);
}

/* Match .kfy-hero__title size scaling tiers so the headline never
   drops out of rhythm with the rest of the brand at the same
   breakpoints. */
@media (min-width: 992px) and (max-width: 1199px) {
	.kfy-quote-band__headline { font-size: clamp(26px, 3vw + 0.25rem, 36px); }
}
@media (min-width: 1200px) {
	.kfy-quote-band__headline { font-size: clamp(40px, 3.2vw + 0.25rem, 56px); }
}

/* Inline lead form — single row on desktop, stacks on mobile.
   Cream "card" sits on the warm sunset bg so the inputs read as a
   distinct, friendly surface (same cream tone as .kfy-hero__form-wrap). */
.kfy-quote-band__form {
	width: 100%;
	max-width: 880px;
	margin-top: var(--sp-3);
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
	gap: 12px;
	padding: 12px;
	background: linear-gradient(160deg, var(--color-cream), #efe6cb);
	border: 1px solid rgba(142, 68, 32, 0.22);
	border-radius: 18px;
	box-shadow:
		0 24px 56px -28px rgba(15, 8, 6, 0.55),
		0 6px 14px -8px rgba(15, 8, 6, 0.30);
}
.kfy-quote-band__field { min-width: 0; }
.kfy-quote-band__form input {
	width: 100%;
	padding: 14px 18px;
	border: 1px solid rgba(142, 68, 32, 0.22);
	background: #fff;
	color: var(--color-dark-brown);
	border-radius: 12px;
	font-family: var(--font-body);
	/* 17px stays above the 16px iOS auto-zoom threshold and matches
	   the rest of the site's enhanced ADA-friendly body floor. */
	font-size: 17px;
	transition: border-color var(--ease-default), box-shadow var(--ease-default);
}
.kfy-quote-band__form input::placeholder {
	color: rgba(75, 35, 12, 0.55);
}
.kfy-quote-band__form input:focus {
	outline: none;
	border-color: var(--pdu-glove);
	box-shadow: 0 0 0 3px rgba(201, 52, 42, 0.18);
}

/* CTA matches the global glove-red primary button but compresses a
   touch so it sits flush with the input row. */
.kfy-quote-band__submit {
	white-space: nowrap;
	padding: 14px 22px;
	font-size: 15px;
	letter-spacing: 1.2px;
	text-transform: uppercase;
	border-radius: 12px;
}

.kfy-quote-band__note {
	margin: var(--sp-2) 0 0;
	font-size: 13px;
	color: rgba(251, 239, 217, 0.78);
	font-style: italic;
	text-shadow: 0 1px 2px rgba(15, 8, 6, 0.40);
}

/* --- Quote band: quick-actions variant ----------------------------------
   Used on the About page in place of the inline lead form. The tiles
   themselves inherit the standalone .kfy-qa-tile contract (icon chip +
   label + subtext + arrow + glove-red highlight) — we just lay them out
   in the same 1 / 2 / 4 column ladder as .kfy-quick-actions__grid and
   give them a touch more contrast against the warm sunset scrim so the
   cream surfaces don't get washed out by the orange backdrop.
   ----------------------------------------------------------------------- */
.kfy-quote-band__quick-actions {
	width: 100%;
	max-width: 880px;
	margin-top: var(--sp-3);
	display: grid;
	grid-template-columns: 1fr;
	gap: 12px;
}
@media (min-width: 600px) {
	.kfy-quote-band__quick-actions { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 992px) {
	.kfy-quote-band__quick-actions { grid-template-columns: repeat(4, 1fr); }
}
/* Lift the non-highlight tiles off the warm sunset scene with a slightly
   denser cream surface + warm-brown border so they read as deliberate
   surfaces rather than translucent ghost cards. The highlight tile keeps
   its glove-red gradient untouched. */
.kfy-quote-band .kfy-qa-tile:not(.kfy-qa-tile--highlight) {
	background: rgba(251, 239, 217, 0.14);
	border-color: rgba(251, 239, 217, 0.28);
	backdrop-filter: blur(2px);
	-webkit-backdrop-filter: blur(2px);
	box-shadow: 0 6px 18px -10px rgba(15, 8, 6, 0.55);
}
.kfy-quote-band .kfy-qa-tile:not(.kfy-qa-tile--highlight):hover {
	background: rgba(251, 239, 217, 0.22);
	border-color: var(--color-gold);
}

/* --- Quote band: tablet (≤ 900px) --------------------------------- */
@media (max-width: 900px) {
	.kfy-quote-band__form {
		/* 2x2 grid: name + email on row 1, phone + CTA on row 2. */
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	}
	.kfy-quote-band__submit {
		grid-column: 1 / -1;
		justify-self: stretch;
	}
}

/* --- Quote band: mobile (≤ 560px) --------------------------------- */
@media (max-width: 560px) {
	.kfy-quote-band {
		padding-top: clamp(120px, 28vw, 160px);
	}
	.kfy-quote-band__form {
		grid-template-columns: 1fr;
		padding: 12px;
	}
	.kfy-quote-band__cloud--1 { width: 160px; height: 64px; }
	.kfy-quote-band__cloud--2 { width: 120px; height: 48px; }
	.kfy-quote-band__cloud--3 { width: 200px; height: 80px; }
}
