/*
 * WCP 2026 - main stylesheet
 * ---------------------------------------------------------------------------
 * The full design system: reset, layout, header/footer, hero, buttons, cards
 * and the migrated block content vocabulary, mobile-first with light/dark
 * modes driven entirely by the custom properties in tokens.css (loaded
 * immediately before this file). No frameworks. No raw hex colours outside
 * the two documented on-brand-fill ink exceptions below (--btn-ink), which
 * are local to this file precisely so they never masquerade as a tokens.css
 * miss.
 *
 * Breakpoints (mobile-first, min-width): 480 / 768 / 1280. The header's
 * mobile<->desktop nav switch moved from 1024 to 1100 in Task 10 (logo-crush
 * fix), then from 1100 to 1280 in the round-2 polish (nav-wrap fix -- see the
 * .wcp-navtoggle block).
 *
 * Contents:
 *   1.  Reset & base
 *   2.  Accessibility (skip link, focus, screen-reader-text, motion)
 *   3.  Layout primitives
 *   4.  Typography scale
 *   5.  Buttons
 *   6.  Icon buttons (toggle / nav-toggle / close)
 *   7.  Site header
 *   8.  Primary nav (desktop dropdowns + mobile slide-in panel)
 *   9.  Site footer
 *   10. Breadcrumbs
 *   11. Hero
 *   12. Trust strip
 *   13. CTA band
 *   14. Page / single article shell
 *   15. Archive grid + pagination
 *   16. 404
 *   17. Search form
 *   18. Content vocabulary - core blocks
 *   19. Content vocabulary - custom components
 *   20. Section variants (is-service / is-product / is-city)
 *   21. Scroll reveal
 *   22. Print
 * ----------------------------------------------------------------------- */

/* ==========================================================================
   1. Reset & base
   ========================================================================== */

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

html {
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
	scroll-padding-top: 96px;
}

body {
	margin: 0;
	min-height: 100vh;
	background: var(--c-bg);
	color: var(--c-text);
	font-family: var(--font-sans);
	font-size: 1rem;
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

img,
picture,
svg,
video,
iframe {
	max-width: 100%;
	display: block;
}

/*
 * Inline icons. wcp_icon() emits a viewBox and deliberately no width/height
 * attributes, so an unsized <svg> falls back to the CSS default of `auto`,
 * resolves against its container and inflates to fill it - the trust strip
 * rendered four ~250px billboards before this rule existed. Every icon now
 * carries a real box by default; the component rules further down override
 * it where a different size is wanted (buttons, icon buttons, utility bar,
 * footer NAP, form notices, trust strip).
 */
.wcp-icon {
	width: 20px;
	height: 20px;
	flex: none;
}

button,
input,
select,
textarea {
	font-family: inherit;
	font-size: inherit;
	color: inherit;
}

a {
	color: var(--c-primary-hover);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.15em;
}

[data-theme="dark"] a {
	color: var(--c-primary);
}

a:hover {
	/* var(--c-accent-hover) on a light bg is ~2.8:1, below AA - use the
	   already-verified 6.81:1 primary-hover instead (matches every other
	   hover rule in this file). Dark mode's --c-accent already passes
	   (7.36:1) and is unchanged below. */
	color: var(--c-primary-hover);
}

[data-theme="dark"] a:hover {
	color: var(--c-accent);
}

ul,
ol {
	margin: 0;
	padding: 0;
}

::selection {
	background: var(--c-accent);
	color: var(--c-navy);
}

/* ==========================================================================
   2. Accessibility
   ========================================================================== */

.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.wcp-skip {
	position: absolute;
	top: -100px;
	left: var(--space-3);
	z-index: 1000;
	padding: var(--space-2) var(--space-4);
	background: var(--c-primary-hover);
	color: #fff;
	border-radius: var(--radius-sm);
	font-weight: 600;
	transition: top 0.15s ease;
}

[data-theme="dark"] .wcp-skip {
	background: var(--c-primary);
	color: var(--c-bg);
}

.wcp-skip:focus {
	top: var(--space-3);
}

:focus-visible {
	outline: 3px solid var(--c-primary);
	outline-offset: 2px;
	border-radius: var(--radius-sm);
}

[data-theme="dark"] :focus-visible {
	outline-color: var(--c-primary);
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}

/* ==========================================================================
   3. Layout primitives
   ========================================================================== */

.container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--space-3);
}

@media (min-width: 768px) {
	.container {
		padding-inline: var(--space-4);
	}
}

.wcp-main {
	display: block;
	overflow-x: clip;
}

/* Core align-wide / align-full breakout, scoped to migrated content only. */
.wcp-content .alignwide {
	max-width: min(100%, calc(var(--container) + 2 * var(--space-6)));
	margin-inline: auto;
}

.wcp-content .alignfull {
	width: 100vw;
	max-width: 100vw;
	margin-inline: calc(50% - 50vw);
}

/* ==========================================================================
   4. Typography scale
   ========================================================================== */

h1,
h2,
h3,
h4,
h5,
h6 {
	margin: 0 0 var(--space-3);
	font-weight: 700;
	line-height: 1.2;
	color: var(--c-text);
}

h1 {
	font-size: clamp(1.875rem, 1.55rem + 1.4vw, 2.75rem);
}

h2 {
	font-size: clamp(1.5rem, 1.3rem + 1vw, 2.25rem);
}

h3 {
	font-size: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
}

h4 {
	font-size: clamp(1.125rem, 1.075rem + 0.25vw, 1.25rem);
}

h5,
h6 {
	font-size: 1rem;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

p {
	margin: 0 0 var(--space-3);
}

small,
.wcp-meta {
	font-size: 0.875rem;
	color: var(--c-text-muted);
}

/* ==========================================================================
   5. Buttons
   ========================================================================== */

:root {
	/*
	 * Button ink. Fill colours come straight from the token layer; the two
	 * inks below are the only literal colours in this file - both are the
	 * documented AA remedy from the Task 3 review (light buttons: white ink
	 * on --c-primary-hover; dark buttons: dark ink on --c-primary). The dark
	 * value is not hardcoded twice - it reuses --c-bg, which is already
	 * exactly #0B1622 in the dark block of tokens.css.
	 */
	--btn-fill: var(--c-primary-hover);
	--btn-fill-hover: var(--c-primary);
	--btn-ink: #fff;
}

[data-theme="dark"] {
	--btn-fill: var(--c-primary);
	--btn-fill-hover: var(--c-primary-hover);
	--btn-ink: var(--c-bg);
}

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	min-height: 48px;
	padding: var(--space-2) var(--space-4);
	border: 2px solid transparent;
	border-radius: var(--radius-sm);
	font-weight: 600;
	font-size: 0.9375rem;
	line-height: 1.2;
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.btn:active {
	transform: translateY(1px);
}

.btn .wcp-icon {
	width: 1.1em;
	height: 1.1em;
	flex-shrink: 0;
}

.btn--primary {
	background: var(--btn-fill);
	color: var(--btn-ink);
	border-color: var(--btn-fill);
}

/*
 * Every primary CTA is an <a>, so the generic dark link colour at the top of
 * this file - [data-theme="dark"] a, specificity (0,1,1) - outranks the plain
 * .btn--primary (0,1,0) above and repaints the label in --c-primary: the exact
 * colour of its own --btn-fill background, i.e. an invisible label. These two
 * dark-scoped rules restate the ink at (0,2,0) and (0,3,0) so they win, and
 * mirror how .btn--ghost below already guards itself. Do not delete them
 * without also scoping the generic anchor rules away from .btn.
 */
[data-theme="dark"] .btn--primary {
	color: var(--btn-ink);
}

.btn--primary:hover,
.btn--primary:focus-visible {
	background: var(--btn-fill-hover);
	border-color: var(--btn-fill-hover);
	color: var(--btn-ink);
}

[data-theme="dark"] .btn--primary:hover,
[data-theme="dark"] .btn--primary:focus-visible {
	color: var(--btn-ink);
}

.btn--ghost {
	background: transparent;
	color: var(--c-primary-hover);
	border-color: var(--c-border);
}

[data-theme="dark"] .btn--ghost {
	color: var(--c-primary);
}

.btn--ghost:hover,
.btn--ghost:focus-visible {
	background: var(--c-surface-2);
	border-color: var(--c-primary-hover);
}

[data-theme="dark"] .btn--ghost:hover,
[data-theme="dark"] .btn--ghost:focus-visible {
	border-color: var(--c-primary);
}

.btn--block {
	width: 100%;
}

.btn--lg {
	min-height: 52px;
	padding: var(--space-3) var(--space-5);
	font-size: 1rem;
}

/* ==========================================================================
   6. Icon buttons (theme toggle / nav toggle / nav close)
   ========================================================================== */

.wcp-iconbtn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	flex-shrink: 0; /* never let a squeezed flex ancestor compress this below the 44px floor */
	padding: 0;
	background: transparent;
	color: var(--c-text);
	border: 1px solid transparent;
	border-radius: var(--radius-sm);
	cursor: pointer;
	transition: background-color 0.15s ease, border-color 0.15s ease;
}

.wcp-iconbtn:hover,
.wcp-iconbtn:focus-visible {
	background: var(--c-surface-2);
	border-color: var(--c-border);
}

.wcp-iconbtn .wcp-icon {
	width: 22px;
	height: 22px;
}

.wcp-toggle__sun,
.wcp-toggle__moon {
	display: inline-flex;
}

.wcp-toggle__sun {
	display: none;
}

[data-theme="dark"] .wcp-toggle__sun {
	display: inline-flex;
}

[data-theme="dark"] .wcp-toggle__moon {
	display: none;
}

.wcp-navtoggle__open,
.wcp-navtoggle__close {
	display: inline-flex;
}

.wcp-navtoggle__close {
	display: none;
}

body.nav-open .wcp-navtoggle__open {
	display: none;
}

body.nav-open .wcp-navtoggle__close {
	display: inline-flex;
}

#wcp-nav-close {
	display: none;
}

/*
 * TASK 10 FIX moved this from 1024px to 1100px (logo-crush fix, see git
 * history). ROUND-2 POLISH moved it again, 1100px -> 1280px:
 *
 * At 1100-1279px the desktop nav row (.wcp-nav, 6 top-level items, ~648px
 * unwrapped) plus the pinned CTA/tools controls (~394px) plus the brand's
 * own natural width (~88px logo) plus inner gaps (~48px) add up to ~1178px
 * of content wanting a single line, inside a .wcp-header__inner that is
 * capped at .container's 1200px content width (1152px usable after
 * padding) at best, and *less* than that below 1200px viewport. Because
 * both .wcp-header__brand and .wcp-nav carry flex-shrink (brand is meant to
 * be the only compressible item, but .wcp-nav's `flex: 1 1 auto` shrinks
 * too), the deficit lands on the nav row's own menu-item links, whose text
 * has no white-space:nowrap - so "Plumbing Services" and "Water Treatment"
 * wrap onto a second line instead of the brand alone compressing. Forcing
 * nowrap on the links without fixing the width budget just moves the
 * deficit onto the brand instead (measured: crushed to ~0px at 1100px).
 *
 * Fix is two parts, both in this file: (1) this switch moves to 1280px -
 * already a documented breakpoint in this design system - so the whole
 * 1024-1279px band stays on the mobile/hamburger layout, where the nav is
 * an off-canvas column and the wrap math above never applies; (2) the
 * .wcp-header__inner max-width override further down gives the row extra
 * width beyond the 1200px content cap once the desktop row *is* showing,
 * so the full 1178px content fits with the brand at its full natural size
 * at every width from 1280px up, not just barely.
 *
 * Kept in lockstep with the other two @media(min-width:1280px) header
 * blocks below and main.js's deskMQ - all three switch the header between
 * mobile and desktop mode together and must never drift apart.
 */
@media (min-width: 1280px) {
	.wcp-navtoggle {
		display: none;
	}
}

/* ==========================================================================
   7. Site header
   ========================================================================== */

.wcp-header {
	position: sticky;
	top: 0;
	z-index: 200;
	background: var(--c-bg);
	border-bottom: 1px solid var(--c-border);
}

/*
 * TASK 5 HOOK: main.js may add .is-scrolled to #wcp-header past a scroll
 * threshold for a more compact header. No-op today; rule below is ready.
 */
.wcp-header.is-scrolled .wcp-header__utility {
	max-height: 0;
	padding-block: 0;
	opacity: 0;
	overflow: hidden;
}

.wcp-header__utility {
	background: var(--c-navy);
	color: #fff;
	/* TASK 10 FIX: was 0.8125rem (13px) -- tools/audit.mjs Step 4 flagged this
	 * against the >=14px text-size gate (license/24-7/email strip, all pages). */
	font-size: 0.875rem;
	transition: max-height 0.2s ease, opacity 0.2s ease, padding 0.2s ease;
}

.wcp-header__utility-inner {
	display: none;
	align-items: center;
	gap: var(--space-4);
	padding-block: var(--space-1);
}

@media (min-width: 768px) {
	.wcp-header__utility-inner {
		display: flex;
	}
}

.wcp-utility__item {
	display: inline-flex;
	align-items: center;
	gap: var(--space-1);
	margin: 0;
	white-space: nowrap;
}

.wcp-utility__link {
	color: #fff;
	text-decoration: none;
	margin-left: auto;
	/* Task 10 fix: same padding/negative-margin hit-area expansion as the
	   footer/breadcrumb links -- this is the only <a> in the persistent
	   utility strip (the other two items are plain <p> text), always
	   visible at >=768px, so it's a real, reachable control. */
	padding-block: 11px;
	margin-block: -11px;
}

.wcp-utility__link:hover {
	text-decoration: underline;
}

.wcp-utility__item .wcp-icon {
	width: 15px;
	height: 15px;
}

.wcp-header__bar {
	padding-block: var(--space-2);
}

.wcp-header__inner {
	display: flex;
	align-items: center;
	/* Tight at the 360px floor; widens once the CTA labels grow at 480px. */
	gap: var(--space-2);
}

@media (min-width: 480px) {
	.wcp-header__inner {
		gap: var(--space-3);
	}
}

/*
 * Brand is the only header-row item allowed to compress. .wcp-header__cta
 * and .wcp-header__tools are pinned to flex: 0 0 auto below specifically so
 * the 44/48px accessible controls they contain can never be squeezed - if
 * the row is ever tighter than expected, the logo/wordmark shrinks (and, as
 * a last resort, the wordmark text ellipsizes) before anything else moves.
 * See the Task 4 fix report for the worst-case 360px arithmetic.
 */
.wcp-header__brand {
	flex: 1 1 auto;
	min-width: 0;
	max-width: 160px;
	overflow: hidden;
}

@media (min-width: 480px) {
	.wcp-header__brand {
		max-width: 220px;
	}
}

.wcp-header__brand img {
	height: auto;
	max-height: 56px;
	max-width: 100%;
	width: auto;
}

.wcp-wordmark {
	display: flex;
	flex-direction: column;
	line-height: 1.15;
	text-decoration: none;
	color: var(--c-text);
	min-width: 0;
}

.wcp-wordmark__lead,
.wcp-wordmark__sub {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.wcp-wordmark__lead {
	font-weight: 700;
	font-size: 1.05rem;
}

.wcp-wordmark__sub {
	font-size: 0.7rem;
	font-weight: 500;
	color: var(--c-text-muted);
}

.wcp-header__cta {
	display: flex;
	align-items: center;
	gap: var(--space-1);
	margin-left: auto;
	flex: 0 0 auto;
}

@media (min-width: 480px) {
	.wcp-header__cta {
		gap: var(--space-2);
	}
}

.wcp-header__quote {
	padding-inline: var(--space-2);
}

@media (min-width: 480px) {
	.wcp-header__quote {
		padding-inline: var(--space-3);
	}
}

.wcp-header__quote-long {
	display: none;
}

.wcp-header__quote-short {
	display: inline;
}

@media (min-width: 480px) {
	.wcp-header__quote-long {
		display: inline;
	}

	.wcp-header__quote-short {
		display: none;
	}
}

.wcp-phone {
	padding-inline: var(--space-2);
	/* TASK 10 FIX: below 480px .wcp-phone__number is display:none (icon-only),
	 * which left the tap target at ~37px wide -- under the 44px gate. Floor it
	 * without changing the visible icon size or its centering. */
	min-width: 44px;
	justify-content: center;
}

.wcp-phone__number {
	display: none;
}

@media (min-width: 480px) {
	.wcp-phone__number {
		display: inline;
	}

	.wcp-phone {
		padding-inline: var(--space-3);
	}
}

.wcp-header__tools {
	display: flex;
	align-items: center;
	gap: var(--space-1);
	flex: 0 0 auto;
}

/* ROUND-2 FIX: 1100px -> 1280px, see the .wcp-navtoggle block above. */
@media (min-width: 1280px) {
	.wcp-header__inner {
		flex-wrap: nowrap;
		/*
		 * The header row needs more than .container's 1200px content cap
		 * once the full desktop nav is inline (see the .wcp-navtoggle
		 * comment for the arithmetic) - 1320px gives it ~94px of slack
		 * beyond the ~1178px the row actually asks for, so the brand logo
		 * never compresses below its natural size and there's headroom for
		 * a future menu item without reopening this fix.
		 */
		max-width: 1320px;
	}
}

/* ==========================================================================
   8. Primary nav
   ========================================================================== */

/* Bonus (final review): main.js module 2 already toggles body.nav-open on
   open/close - this was the missing half, so the page behind the open
   panel doesn't scroll. scrollbar-gutter keeps the layout from jumping
   sideways when the scrollbar disappears. */
body.nav-open {
	overflow: hidden;
	scrollbar-gutter: stable;
}

.wcp-nav-scrim {
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, 0.55);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.25s ease;
	z-index: 210;
}

body.nav-open .wcp-nav-scrim {
	opacity: 1;
	pointer-events: auto;
}

.wcp-nav {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	width: min(88vw, 360px);
	display: flex;
	flex-direction: column;
	background: var(--c-bg);
	box-shadow: var(--shadow-2);
	transform: translateX(100%);
	transition: transform 0.3s ease;
	z-index: 220;
	overflow-y: auto;
	padding: var(--space-4);
}

body.nav-open .wcp-nav {
	transform: translateX(0);
}

.wcp-nav__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: var(--space-4);
}

.wcp-nav__title {
	font-weight: 700;
	font-size: 1.1rem;
}

body.nav-open #wcp-nav-close {
	display: inline-flex;
}

.wcp-menu {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
}

.wcp-menu .menu-item {
	border-bottom: 1px solid var(--c-border);
}

.wcp-menu .menu-item > a {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 48px;
	padding-block: var(--space-2);
	color: var(--c-text);
	font-weight: 500;
	text-decoration: none;
}

.wcp-menu .menu-item > a:hover,
.wcp-menu .menu-item > a:focus-visible {
	color: var(--c-primary-hover);
}

[data-theme="dark"] .wcp-menu .menu-item > a:hover,
[data-theme="dark"] .wcp-menu .menu-item > a:focus-visible {
	color: var(--c-primary);
}

.wcp-menu .menu-item-has-children > a::after {
	content: "";
	width: 0.5em;
	height: 0.5em;
	margin-left: var(--space-2);
	border-right: 2px solid currentColor;
	border-bottom: 2px solid currentColor;
	transform: rotate(45deg);
	flex-shrink: 0;
	opacity: 0.6;
}

.wcp-menu .sub-menu {
	list-style: none;
	margin: 0 0 var(--space-2);
	padding-left: var(--space-4);
}

.wcp-menu .sub-menu a {
	display: flex;
	min-height: 44px;
	align-items: center;
	color: var(--c-text-muted);
	text-decoration: none;
}

.wcp-nav__foot {
	margin-top: var(--space-4);
}

/* ROUND-2 FIX: 1100px -> 1280px, see the .wcp-navtoggle block above. */
@media (min-width: 1280px) {
	.wcp-nav-scrim {
		display: none;
	}

	.wcp-nav {
		position: static;
		flex: 1 1 auto;
		flex-direction: row;
		width: auto;
		background: transparent;
		box-shadow: none;
		transform: none;
		transition: none;
		padding: 0;
		overflow: visible;
	}

	.wcp-nav__head,
	.wcp-nav__foot {
		display: none;
	}

	.wcp-menu {
		flex-direction: row;
		align-items: center;
		gap: var(--space-1);
	}

	.wcp-menu .menu-item {
		border-bottom: 0;
		position: relative;
	}

	.wcp-menu .menu-item > a {
		min-height: 44px;
		padding: var(--space-2);
		border-radius: var(--radius-sm);
	}

	.wcp-menu .menu-item > a:hover,
	.wcp-menu .menu-item > a:focus-visible {
		background: var(--c-surface-2);
	}

	/*
	 * TASK 5 HOOK: this is a CSS-only hover/focus-within dropdown. On a
	 * touch device at this breakpoint (docked tablet, touch laptop) there is
	 * no hover, so the first tap on a parent item navigates straight through
	 * without ever showing the submenu. main.js should add a tap-to-expand
	 * affordance at >=1280px on pointer:coarse - open on first tap, follow
	 * the link on a second tap on an already-open parent.
	 */
	.wcp-menu .sub-menu {
		position: absolute;
		top: 100%;
		left: 0;
		min-width: 220px;
		margin: 0;
		padding: var(--space-2);
		background: var(--c-bg);
		border: 1px solid var(--c-border);
		border-radius: var(--radius-sm);
		box-shadow: var(--shadow-2);
		opacity: 0;
		visibility: hidden;
		transform: translateY(-6px);
		transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
	}

	.wcp-menu .menu-item:hover > .sub-menu,
	.wcp-menu .menu-item:focus-within > .sub-menu {
		opacity: 1;
		visibility: visible;
		transform: translateY(0);
	}

	.wcp-menu .sub-menu a {
		min-height: 44px;
		padding-inline: var(--space-2);
		border-radius: var(--radius-sm);
	}

	.wcp-menu .sub-menu a:hover,
	.wcp-menu .sub-menu a:focus-visible {
		background: var(--c-surface-2);
		color: var(--c-primary-hover);
	}

	[data-theme="dark"] .wcp-menu .sub-menu a:hover,
	[data-theme="dark"] .wcp-menu .sub-menu a:focus-visible {
		color: var(--c-primary);
	}
}

/* ==========================================================================
   9. Site footer
   ========================================================================== */

.wcp-footer {
	background: var(--c-surface);
	border-top: 1px solid var(--c-border);
	margin-top: var(--space-8);
}

.wcp-footer__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--space-6);
	padding-block: var(--space-7);
}

@media (min-width: 768px) {
	.wcp-footer__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 1024px) {
	.wcp-footer__grid {
		grid-template-columns: 1.4fr 1fr 1fr 1fr;
	}
}

.wcp-footer__logo img {
	max-height: 48px;
	width: auto;
}

.wcp-footer__about {
	color: var(--c-text-muted);
	max-width: 34ch;
}

.wcp-footer__badge {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	font-weight: 600;
	margin-bottom: var(--space-3);
}

.wcp-footer__social {
	display: flex;
	gap: var(--space-3);
}

.wcp-footer__social a {
	font-weight: 600;
	/* Task 10 fix: expand the tap target to >=44px on both axes via padding,
	   then cancel the layout footprint with an equal negative margin so the
	   visible footer is unchanged (getBoundingClientRect includes padding,
	   not margin, so this satisfies the >=44px gate without a redesign). */
	display: inline-block;
	padding: 10px 8px;
	margin: -10px -8px;
}

.wcp-footer__heading {
	font-size: 1rem;
	margin-bottom: var(--space-3);
}

.wcp-footer__list {
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
}

.wcp-footer__list a,
.wcp-footer__list span {
	color: var(--c-text-muted);
	text-decoration: none;
}

.wcp-footer__list a {
	/* Task 10 fix: same padding/negative-margin hit-area expansion as the
	   social icons above -- these are dense sitemap-style link lists (site
	   nav + 16 service-area cities), so growing the link box itself instead
	   of the box would blow the footer's height out; this keeps the
	   compact list while giving each link a >=44px tap target on both
	   axes (some city names, e.g. "FAQ"/"Estero", are under 44px wide too).
	   The 7px horizontal reach is comfortably inside the cities grid's
	   16px column gap (--space-3), so it never overlaps the next column. */
	display: inline-block;
	padding: 10.5px 7px;
	margin: -10.5px -7px;
}

.wcp-footer__list a:hover {
	color: var(--c-primary-hover);
}

[data-theme="dark"] .wcp-footer__list a:hover {
	color: var(--c-primary);
}

.wcp-footer__list--cities {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--space-2) var(--space-3);
}

.wcp-footer__nap {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	margin: 0 0 var(--space-4);
	font-style: normal;
}

.wcp-footer__nap-item {
	display: flex;
	align-items: flex-start;
	gap: var(--space-2);
	margin: 0;
	color: var(--c-text-muted);
}

.wcp-footer__nap-item a {
	color: inherit;
	/* Task 10 fix: phone/email links are already wide enough (>=44px);
	   only the block axis needs the padding/negative-margin expansion.
	   align-items:flex-start on the parent means this doesn't shift the
	   icon's vertical position (the link's layout-box height is
	   unchanged by the canceling negative margin). */
	display: inline-block;
	padding-block: 10px;
	margin-block: -10px;
}

.wcp-footer__nap-item .wcp-icon {
	flex-shrink: 0;
	width: 18px;
	height: 18px;
	margin-top: 0.15em;
}

.wcp-footer__legal {
	border-top: 1px solid var(--c-border);
	padding-block: var(--space-3);
	font-size: 0.875rem; /* meta floor is 14px on mobile - this text has no larger override */
	color: var(--c-text-muted);
	text-align: center;
}

.wcp-footer__legal p {
	margin: 0;
}

/* ==========================================================================
   10. Breadcrumbs
   ========================================================================== */

.wcp-breadcrumbs {
	border-bottom: 1px solid var(--c-border);
	background: var(--c-surface);
}

.wcp-breadcrumbs__list {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-1);
	padding-block: var(--space-2);
	font-size: 0.875rem;
	color: var(--c-text-muted);
}

.wcp-breadcrumbs__item a {
	color: var(--c-text-muted);
	text-decoration: none;
	/* Task 10 fix: same padding/negative-margin hit-area expansion as the
	   footer links -- breadcrumbs are real navigation but the trail's
	   compact 14px-row look is worth keeping, so the tap target grows
	   invisibly instead of the visible row height. */
	display: inline-block;
	padding: 12px 7px;
	margin: -12px -7px;
}

.wcp-breadcrumbs__item a:hover {
	color: var(--c-primary-hover);
	text-decoration: underline;
}

[data-theme="dark"] .wcp-breadcrumbs__item a:hover {
	color: var(--c-primary);
}

.wcp-breadcrumbs__item + .wcp-breadcrumbs__item::before {
	content: "\203A";
	margin-right: var(--space-1);
	opacity: 0.6;
}

.wcp-breadcrumbs__item[aria-current] {
	color: var(--c-text);
}

.wcp-breadcrumbs__item span[aria-current] {
	font-weight: 500;
}

/* ==========================================================================
   11. Hero
   ========================================================================== */

/*
 * Composition: copy left, the company van right, a wave divider closing the
 * section into the trust strip. Layering is deliberate and only three deep -
 * canvas (0), wave (1), content (2) - so the photograph crosses the wave crest
 * instead of being clipped by it. That crossing is the "overlap into the
 * section below": everything under the crest is already painted --c-surface,
 * the trust strip's own colour.
 *
 * `overflow: hidden` is NOT set on .wcp-hero (it was, before the media column
 * existed) - it would cut the chip off. Nothing here escapes the box anyway,
 * and .wcp-main already carries overflow-x: clip.
 */

.wcp-hero {
	position: relative;
	isolation: isolate;
	background: linear-gradient(135deg, var(--c-hero-grad-a), var(--c-hero-grad-b));
	color: #fff;
	padding-block: var(--space-7) calc(var(--space-7) + 48px);
}

.wcp-hero__canvas {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
}

.wcp-hero__inner {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-6);
	align-items: center;
}

.wcp-hero__copy {
	max-width: 40rem;
}

.wcp-hero__headline {
	color: #fff;
	font-size: clamp(2rem, 1.5rem + 3vw, 3.5rem);
	letter-spacing: -0.015em;
	text-wrap: balance;
	margin-bottom: var(--space-4);
}

.wcp-hero__sub {
	font-size: clamp(1rem, 0.95rem + 0.4vw, 1.1875rem);
	color: rgba(255, 255, 255, 0.92);
	max-width: 52ch;
	margin-bottom: var(--space-5);
}

.wcp-hero__ctas {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin-bottom: 0;
}

.wcp-hero .btn--ghost {
	color: #fff;
	border-color: rgba(255, 255, 255, 0.55);
	background: rgba(255, 255, 255, 0.08);
}

.wcp-hero .btn--ghost:hover,
.wcp-hero .btn--ghost:focus-visible {
	background: rgba(255, 255, 255, 0.18);
	border-color: #fff;
}

/* --- hero media: the real company van, art-directed --- */

.wcp-hero__media {
	position: relative;
	/* Keeps the photo from becoming a billboard on a phone or small tablet. */
	max-width: 520px;
	width: 100%;
}

.wcp-hero__frame {
	position: relative;
	margin: 0;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	/* Asymmetric mask - the deep corner sits under the chip and stops the
	   rectangle reading as a stock content image. */
	border-radius: var(--radius) var(--radius) calc(var(--radius) * 4) var(--radius);
	border: 1px solid rgba(255, 255, 255, 0.22);
	box-shadow: 0 18px 48px rgba(0, 0, 0, 0.34), 0 2px 6px rgba(0, 0, 0, 0.2);
}

.wcp-hero__frame::after {
	/* A touch of the hero's own navy dropped into the shadow side of the photo,
	   so the picture belongs to the gradient instead of sitting on top of it. */
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(200deg, rgba(0, 60, 111, 0) 45%, rgba(0, 42, 78, 0.42));
	pointer-events: none;
}

.wcp-hero__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

.wcp-hero__chip {
	position: absolute;
	left: var(--space-3);
	bottom: calc(var(--space-4) * -1);
	z-index: 1;
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	margin: 0;
	padding: var(--space-2) var(--space-4);
	/* Token surfaces, so the pill is AA in both modes without a second rule. */
	background: var(--c-bg);
	color: var(--c-text);
	border-radius: 999px;
	box-shadow: var(--shadow-2);
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.01em;
	white-space: nowrap;
}

.wcp-hero__chip .wcp-icon {
	width: 18px;
	height: 18px;
	color: var(--c-primary-hover);
}

[data-theme="dark"] .wcp-hero__chip .wcp-icon {
	color: var(--c-primary);
}

/* --- wave divider --- */

.wcp-hero__wave {
	position: absolute;
	left: 0;
	right: 0;
	/* -1px kills the sub-pixel seam between the path and the trust strip. */
	bottom: -1px;
	z-index: 1;
	width: 100%;
	height: 48px;
	fill: var(--c-surface);
	pointer-events: none;
}

.wcp-hero__wave-back {
	opacity: 0.28;
}

@media (min-width: 768px) {
	.wcp-hero {
		padding-block: var(--space-8) calc(var(--space-8) + 32px);
	}

	.wcp-hero__wave {
		height: 72px;
	}
}

@media (min-width: 1024px) {
	.wcp-hero__inner {
		/* Copy gets the wider share; the photo still lands near a 4:5 of the row. */
		grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
		gap: var(--space-7);
	}

	.wcp-hero__media {
		max-width: none;
		/* The photograph reaches down through the wave crest. */
		margin-bottom: -40px;
	}

	/* Room to hang off the frame only once the gutter exists to hang into. */
	.wcp-hero__chip {
		left: calc(var(--space-4) * -1);
	}

	.wcp-hero__frame {
		aspect-ratio: 4 / 3;
	}

	.wcp-hero__wave {
		height: 88px;
	}
}

@media (min-width: 1280px) {
	.wcp-hero__media {
		margin-bottom: -56px;
	}
}

/* Reduced motion keeps every static treatment above; only the canvas mount is
   torn down (hero-canvas.js), and the gradient behind it is the fallback. */

/* ==========================================================================
   12. Trust strip
   ========================================================================== */

/*
 * One confident band of four credentials, not four billboards. The strip is
 * deliberately short (a single 64-72px row from 1024px up) and the icons are
 * explicitly sized - see the .wcp-icon base rule in section 1 for why an
 * unsized inline SVG used to blow up to ~250px here.
 */

.wcp-trust {
	background: var(--c-surface);
	border-bottom: 1px solid var(--c-border);
}

.wcp-trust__list {
	list-style: none;
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--space-3);
	padding-block: var(--space-4);
	/* Stacked, the four rows are one centred block with their icons in a
	   column - centring each row independently left a ragged left edge. */
	width: max-content;
	max-width: 100%;
	margin-inline: auto;
}

@media (min-width: 640px) {
	.wcp-trust__list {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--space-3) var(--space-4);
		width: auto;
	}

	.wcp-trust__item {
		justify-content: center;
	}
}

@media (min-width: 1024px) {
	.wcp-trust__list {
		grid-template-columns: repeat(4, 1fr);
		gap: 0;
		padding-block: var(--space-3);
	}
}

.wcp-trust__item {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	min-height: 40px;
	font-weight: 600;
	font-size: 0.9375rem;
	line-height: 1.25;
	justify-content: flex-start;
	text-align: left;
}

/* 28px: reads as a credential mark next to 15px/600 text without becoming
   the loudest thing in the band. */
.wcp-trust__item .wcp-icon {
	width: 28px;
	height: 28px;
	color: var(--c-primary-hover);
	flex: none;
}

[data-theme="dark"] .wcp-trust__item .wcp-icon {
	color: var(--c-primary);
}

/* Hairline rules turn four cells into one continuous line. Only once the row
   is genuinely a row - stacked, they would read as list bullets. */
@media (min-width: 1024px) {
	.wcp-trust__item + .wcp-trust__item {
		border-left: 1px solid var(--c-border);
	}

	.wcp-trust__item {
		/* 16px, not 24px: "Family Owned & Operated" is the longest label and
		   wrapped to two lines at 24px, which broke the single-line read. */
		padding-inline: var(--space-3);
	}
}

/* ==========================================================================
   13. CTA band
   ========================================================================== */

.wcp-cta-band {
	padding-block: var(--space-7);
}

.wcp-cta-band__inner {
	background: var(--c-surface-2);
	border-radius: var(--radius);
	box-shadow: var(--shadow-2);
	padding: var(--space-6);
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
	text-align: center;
	align-items: center;
}

.wcp-cta-band__copy h2 {
	margin-bottom: var(--space-2);
}

.wcp-cta-band__copy p {
	color: var(--c-text-muted);
	margin-bottom: 0;
	max-width: 56ch;
}

.wcp-cta-band__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	justify-content: center;
}

@media (min-width: 768px) {
	.wcp-cta-band__inner {
		flex-direction: row;
		justify-content: space-between;
		text-align: left;
		padding: var(--space-7);
	}

	.wcp-cta-band__actions {
		justify-content: flex-end;
		flex-shrink: 0;
	}
}

/* ==========================================================================
   14. Page / single article shell
   ========================================================================== */

.wcp-page__inner {
	padding-block: var(--space-6) var(--space-8);
}

.wcp-page__header {
	margin-bottom: var(--space-5);
}

.wcp-page__title {
	margin-bottom: 0;
}

.wcp-single__meta {
	color: var(--c-text-muted);
	font-size: 0.875rem;
}

.wcp-single__thumb {
	margin-bottom: var(--space-5);
	border-radius: var(--radius);
	overflow: hidden;
	aspect-ratio: 16 / 9;
}

.wcp-single__thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.wcp-single__tags {
	margin-top: var(--space-5);
	padding-top: var(--space-4);
	border-top: 1px solid var(--c-border);
	font-size: 0.875rem;
	color: var(--c-text-muted);
}

.wcp-single__tags a {
	/* Task 10 fix: get_the_tag_list() renders these as plain inline text
	   ("Tag One, Tag Two, ..."), so the same padding/negative-margin trick
	   used on the footer/breadcrumb links applies here too -- each tag
	   becomes its own inline-block hit target while the comma-separated
	   text still wraps exactly as before (the ", " separators are plain
	   text nodes outside the <a>, unaffected by this). */
	display: inline-block;
	padding: 12px 4px;
	margin: -12px -4px;
}

/* B1 fix (final review): the comments list itself. Renders only already-
   approved legacy comments - see comments.php and wcp_comment_item() - and
   no form ever prints beneath it while comments are closed site-wide. */
.wcp-comments {
	margin-top: var(--space-7);
	padding-top: var(--space-6);
	border-top: 1px solid var(--c-border);
}

.wcp-comments__title {
	margin-bottom: var(--space-4);
}

.wcp-comments__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-5);
}

.wcp-comments__item + .wcp-comments__item {
	padding-top: var(--space-5);
	border-top: 1px solid var(--c-border);
}

.wcp-comments__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--space-2);
	margin-bottom: var(--space-2);
}

.wcp-comments__author {
	font-weight: 600;
}

.wcp-comments__date {
	color: var(--c-text-muted);
	font-size: 0.875rem;
}

.wcp-comments__content :last-child {
	margin-bottom: 0;
}

/* Task 10 fix: WordPress core's default comment_form() output (single.php
   renders it via comments_template() whenever comments_open()) had no
   theme styling at all -- browser-default text inputs and submit button
   measured 31px tall, under the 44px tap-target gate. Styled to match the
   .wcp-form__field / .btn conventions used by the custom contact form
   elsewhere in the theme, so this isn't a one-off look. The native
   checkbox itself (#wp-comment-cookies-consent, ~13x13px) is left at its
   native OS-rendered size -- resizing a native checkbox control away from
   its platform default is its own can of worms and isn't attempted here;
   its associated <label> is already a large, easy secondary tap target. */
#commentform {
	display: grid;
	gap: var(--space-4);
	max-width: 640px;
	margin-top: var(--space-4);
}

#commentform p {
	display: grid;
	gap: var(--space-1);
}

/* The consent checkbox's <input> and <label> are siblings inside one <p>
   (WordPress core markup), not stacked fields -- override the generic grid
   above so the box doesn't stretch to the paragraph's full width (a plain
   grid item with no explicit size stretches by default, blowing a normal
   ~13px checkbox out to hundreds of px wide) and sits inline before its
   label, as a checkbox+label pair normally reads. */
#commentform p.comment-form-cookies-consent {
	/* #commentform p above is (1,0,1) specificity; a bare class selector
	   here would lose to it and never apply -- match that specificity. */
	display: flex;
	align-items: center;
	gap: var(--space-2);
	flex-direction: row;
}

#commentform .comment-form-cookies-consent input[type="checkbox"] {
	width: auto;
	flex-shrink: 0;
	margin: 0;
}

#commentform label {
	font-weight: 600;
	font-size: 0.9375rem;
}

#commentform input[type="text"],
#commentform input[type="email"],
#commentform input[type="url"],
#commentform textarea {
	min-height: 48px;
	padding: var(--space-2) var(--space-3);
	background: var(--c-bg);
	color: var(--c-text);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-sm);
	width: 100%;
	font: inherit;
}

#commentform textarea {
	min-height: 128px;
	padding-block: var(--space-2);
	resize: vertical;
}

#commentform input[type="text"]:focus-visible,
#commentform input[type="email"]:focus-visible,
#commentform input[type="url"]:focus-visible,
#commentform textarea:focus-visible {
	border-color: var(--c-primary);
}

#commentform .form-submit {
	margin: 0;
}

#commentform #submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	min-height: 48px;
	padding: var(--space-2) var(--space-4);
	background: var(--btn-fill);
	color: var(--btn-ink);
	border: 2px solid var(--btn-fill);
	border-radius: var(--radius-sm);
	font-weight: 600;
	font-size: 0.9375rem;
	cursor: pointer;
}

/* ==========================================================================
   15. Archive grid + pagination
   ========================================================================== */

.wcp-archive {
	padding-block: var(--space-6) var(--space-8);
}

.wcp-archive__header {
	margin-bottom: var(--space-5);
}

.wcp-archive__desc {
	color: var(--c-text-muted);
}

.wcp-archive__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--space-5);
}

@media (min-width: 768px) {
	.wcp-archive__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 1024px) {
	.wcp-archive__grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

/* The real use of the 1280 tier named in the file banner: one more column
   once there is enough width to keep cards comfortable rather than cramped. */
@media (min-width: 1280px) {
	.wcp-archive__grid {
		grid-template-columns: repeat(4, 1fr);
	}
}

.wcp-archive__card {
	display: flex;
	flex-direction: column;
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	overflow: hidden;
	box-shadow: var(--shadow-1);
	transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.wcp-archive__card:hover {
	box-shadow: var(--shadow-2);
	transform: translateY(-2px);
}

.wcp-archive__card-media {
	display: block;
	aspect-ratio: 4 / 3;
	overflow: hidden;
}

.wcp-archive__card-media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.wcp-archive__card-body {
	padding: var(--space-4);
}

.wcp-archive__card-title {
	font-size: 1.1rem;
	margin-bottom: var(--space-2);
}

.wcp-archive__card-title a {
	color: var(--c-text);
	text-decoration: none;
	/* Task 10 follow-up fix: same padding/negative-margin hit-area
	   expansion used elsewhere in this file (footer/breadcrumb/tag links) --
	   at the mobile-390 viewport, short post titles wrap to a single
	   303x24px line, under the 44px tap-target gate. The card is already
	   >=44px wide, so only the block axis needs expansion; the card body's
	   24px padding above and the title's own 8px margin-bottom below
	   absorb the 13px reach on both edges (getBoundingClientRect includes
	   padding, not margin, so this satisfies the gate without changing the
	   visible card design). 11px measured 43.1px (still under the gate,
	   see t10fix-report.md) so 13px was used for a real safety margin. */
	display: inline-block;
	padding-block: 13px;
	margin-block: -13px;
}

.wcp-archive__card-title a:hover {
	color: var(--c-primary-hover);
}

[data-theme="dark"] .wcp-archive__card-title a:hover {
	color: var(--c-primary);
}

.wcp-archive__card-excerpt {
	color: var(--c-text-muted);
	margin: 0;
}

.wcp-archive__empty {
	color: var(--c-text-muted);
}

.navigation.pagination {
	margin-top: var(--space-6);
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	justify-content: center;
}

.navigation.pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding-inline: var(--space-2);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-sm);
	color: var(--c-text);
	text-decoration: none;
}

.navigation.pagination .page-numbers.current {
	background: var(--btn-fill);
	color: var(--btn-ink);
	border-color: var(--btn-fill);
}

.navigation.pagination a.page-numbers:hover {
	background: var(--c-surface-2);
}

/* ==========================================================================
   16. 404
   ========================================================================== */

.wcp-404 {
	padding-block: var(--space-8);
}

.wcp-404__inner {
	max-width: 640px;
	margin-inline: auto;
	text-align: center;
}

.wcp-404__eyebrow {
	font-weight: 700;
	letter-spacing: 0.08em;
	color: var(--c-primary-hover);
	margin-bottom: var(--space-2);
}

[data-theme="dark"] .wcp-404__eyebrow {
	color: var(--c-primary);
}

.wcp-404__text {
	color: var(--c-text-muted);
}

.wcp-404__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	justify-content: center;
	margin-bottom: var(--space-6);
}

.wcp-404__links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-4);
	justify-content: center;
	margin-bottom: var(--space-6);
}

.wcp-404__links a {
	font-weight: 600;
	text-decoration: none;
}

.wcp-404__links a:hover {
	text-decoration: underline;
}

/* ==========================================================================
   17. Search form
   ========================================================================== */

.wcp-search {
	display: flex;
	gap: var(--space-2);
	max-width: 420px;
	margin-inline: auto;
}

.wcp-search__field {
	flex: 1 1 auto;
	min-height: 48px;
	padding-inline: var(--space-3);
	background: var(--c-surface);
	color: var(--c-text);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-sm);
}

.wcp-search__field:focus-visible {
	border-color: var(--c-primary);
}

.wcp-search__submit {
	flex: 0 0 auto;
	width: 48px;
	height: 48px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: var(--btn-fill);
	color: var(--btn-ink);
	border: 0;
	border-radius: var(--radius-sm);
	cursor: pointer;
}

.wcp-search__submit:hover {
	background: var(--btn-fill-hover);
}

/* ==========================================================================
   18. Content vocabulary - core blocks
   ========================================================================== */

.wcp-content {
	padding-block: var(--space-3);
}

.wcp-content--front {
	padding-block: var(--space-7) var(--space-6);
}

.wcp-content > *:last-child {
	margin-bottom: 0;
}

.wcp-content ul,
.wcp-content ol {
	margin: 0 0 var(--space-4);
	padding-left: 1.25em;
}

.wcp-content li {
	margin-bottom: var(--space-2);
}

.wcp-content a {
	text-decoration: underline;
}

.wcp-content figure {
	margin: 0 0 var(--space-4);
}

.wcp-content img {
	max-width: 100%;
	height: auto;
	border-radius: var(--radius-sm);
}

.wcp-content figcaption {
	margin-top: var(--space-2);
	font-size: 0.875rem;
	color: var(--c-text-muted);
	text-align: center;
}

/* Core buttons block - same visual language as .btn, without depending on it. */
.wcp-content .wp-block-buttons {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	list-style: none;
	margin: 0 0 var(--space-4);
	padding: 0;
}

.wcp-content .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 48px;
	padding: var(--space-2) var(--space-4);
	background: var(--btn-fill);
	color: var(--btn-ink);
	border-radius: var(--radius-sm);
	font-weight: 600;
	text-decoration: none;
	transition: background-color 0.15s ease;
}

.wcp-content .wp-block-button__link:hover,
.wcp-content .wp-block-button__link:focus-visible {
	background: var(--btn-fill-hover);
	color: var(--btn-ink);
}

.wcp-content .is-style-outline .wp-block-button__link {
	background: transparent;
	color: var(--c-primary-hover);
	border: 2px solid var(--c-border);
}

[data-theme="dark"] .wcp-content .is-style-outline .wp-block-button__link {
	color: var(--c-primary);
}

/* Columns - stack on mobile, row from tablet up. */
.wcp-content .wp-block-columns {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-5);
	margin: 0 0 var(--space-5);
}

.wcp-content .wp-block-column {
	flex: 1 1 100%;
	min-width: 0;
}

@media (min-width: 768px) {
	.wcp-content .wp-block-column {
		flex: 1 1 0;
	}
}

/* Gallery */
.wcp-content .wp-block-gallery {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--space-3);
	list-style: none;
	margin: 0 0 var(--space-4);
	padding: 0;
}

@media (min-width: 768px) {
	.wcp-content .wp-block-gallery {
		grid-template-columns: repeat(3, 1fr);
	}
}

.wcp-content .wp-block-gallery figure {
	margin: 0;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: var(--radius-sm);
}

.wcp-content .wp-block-gallery img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

/* Embeds - force a 16:9 box for anything that didn't get inline dimensions. */
.wcp-content .wp-block-embed__wrapper {
	position: relative;
	aspect-ratio: 16 / 9;
	border-radius: var(--radius-sm);
	overflow: hidden;
	margin-bottom: var(--space-2);
}

.wcp-content .wp-block-embed__wrapper iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

/* Quote (standalone, outside .wcp-testimonials) */
.wcp-content .wp-block-quote {
	margin: 0 0 var(--space-4);
	padding-left: var(--space-4);
	border-left: 4px solid var(--c-primary-hover);
	color: var(--c-text);
	font-size: 1.125rem;
}

[data-theme="dark"] .wcp-content .wp-block-quote {
	border-left-color: var(--c-primary);
}

.wcp-content .wp-block-quote cite {
	display: block;
	margin-top: var(--space-2);
	font-size: 0.875rem;
	font-style: normal;
	font-weight: 600;
	color: var(--c-text-muted);
}

/* ==========================================================================
   19. Content vocabulary - custom components
   ========================================================================== */

/* .wcp-heading-text - emphasised non-heading text (a real <p>, styled bigger
   and bolder, deliberately not identical to an actual heading). */
.wcp-content .wcp-heading-text {
	font-size: clamp(1.125rem, 1.05rem + 0.4vw, 1.375rem);
	font-weight: 600;
	color: var(--c-primary-hover);
	margin-bottom: var(--space-3);
}

[data-theme="dark"] .wcp-content .wcp-heading-text {
	color: var(--c-primary);
}

/* .wcp-sectionhead - a section's heading + kicker as one centred unit, wearing
   the same accent bar the is-service / is-product / is-city page headers use
   (section 20), so a section break looks the same everywhere on the site. */
.wcp-content .wcp-sectionhead {
	max-width: 46rem;
	margin: 0 auto var(--space-6);
	text-align: center;
}

.wcp-content .wcp-sectionhead::before {
	content: "";
	display: block;
	width: 64px;
	height: 6px;
	margin: 0 auto var(--space-4);
	border-radius: 999px;
	background: var(--c-accent);
}

.wcp-content .wcp-sectionhead > *:last-child {
	margin-bottom: 0;
}

.wcp-content .wcp-sectionhead h2 {
	margin-bottom: var(--space-2);
}

/*
 * .wcp-cards - the three front-page service cards.
 *
 * Grid, not the flex columns rule above, for one reason: grid rows are equal
 * height by default, which is what makes the cards line up whatever the copy
 * length. Inside each card `margin-top: auto` on the buttons block pushes the
 * Learn More to the bottom edge, so all three sit on one line. The images are
 * forced to a single 4:3 box because the migrated sources are three different
 * shapes (1024x683, 1024x768 and a portrait crop).
 *
 * This overrides .wcp-content .wp-block-columns at equal specificity, so it
 * has to stay after it in the file - it is in section 19 and that is in 18.
 */
.wcp-content .wcp-cards {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--space-4);
	margin: 0 0 var(--space-7);
}

@media (min-width: 768px) {
	.wcp-content .wcp-cards {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--space-5);
	}
}

.wcp-content .wcp-cards > .wp-block-column {
	display: flex;
	flex-direction: column;
	min-width: 0;
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	overflow: hidden;
	box-shadow: var(--shadow-1);
	transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.wcp-content .wcp-cards > .wp-block-column:hover {
	transform: translateY(-4px);
	box-shadow: var(--shadow-2);
}

@media (prefers-reduced-motion: reduce) {
	.wcp-content .wcp-cards > .wp-block-column:hover {
		transform: none;
	}
}

.wcp-content .wcp-cards figure {
	margin: 0;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	background: var(--c-surface-2);
}

.wcp-content .wcp-cards figure img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

.wcp-content .wcp-cards h3 {
	margin: var(--space-4) var(--space-4) var(--space-2);
	font-size: 1.25rem;
}

.wcp-content .wcp-cards p {
	margin: 0 var(--space-4) var(--space-4);
	color: var(--c-text-muted);
	font-size: 0.9375rem;
}

.wcp-content .wcp-cards .wp-block-buttons {
	/* auto pins the action row to the bottom of an equal-height card. */
	margin: auto var(--space-4) var(--space-4);
}

/*
 * Front-page section rhythm. The migrated content is one flat stack of blocks
 * with no section wrappers, so a top-level h2 is the only signal that a new
 * section has started - it needs real air above it or the page reads as one
 * undifferentiated column. Scoped to DIRECT children of the container so an h2
 * inside a columns row (which must stay aligned with its sibling) is untouched.
 */
.wcp-content--front > .container > h2:not(:first-child),
.wcp-content--front > .container > .wp-block-group:not(:first-child) {
	margin-top: var(--space-8);
}

.wcp-content--front > .container > h2 + .wcp-heading-text {
	margin-bottom: var(--space-4);
}

/*
 * Front-page media rows. The migrated corpus pairs a photograph column with a
 * copy column, and two of the photographs are portrait (777x1024) - unconstrained
 * they ran to ~740px tall and left the copy stranded at the top of a very deep
 * empty column. Cap the picture, crop from the top third (the subject is always
 * in the upper half of these shots) and centre the pair.
 */
@media (min-width: 768px) {
	.wcp-content--front .wp-block-columns:has(> .wp-block-column > figure.wp-block-image:only-child) {
		align-items: center;
		gap: var(--space-6);
	}
}

.wcp-content--front .wp-block-column > figure.wp-block-image:only-child {
	margin-bottom: 0;
}

.wcp-content--front .wp-block-column > figure.wp-block-image:only-child img {
	width: 100%;
	max-height: 460px;
	object-fit: cover;
	object-position: 50% 32%;
	border-radius: var(--radius);
}

/*
 * Migrated "spec list + Learn More" rows further down the front page. Each is a
 * two-column block whose right column holds nothing but a button, so the action
 * floated level with the list's first line and left a tall empty gap under it.
 * Scoped to the front page: these are the only ones in the corpus laid out this
 * way, and a site-wide rule would restyle pages this task never looked at.
 */
.wcp-content--front .wp-block-columns:has(> .wp-block-column > .wp-block-buttons:only-child) {
	align-items: center;
	gap: var(--space-4);
	margin-bottom: 0;
	padding-block: var(--space-4);
	border-bottom: 1px solid var(--c-border);
}

.wcp-content--front .wp-block-columns:has(> .wp-block-column > .wp-block-buttons:only-child) :is(ul, ol, .wp-block-buttons) {
	margin-bottom: 0;
}

@media (min-width: 768px) {
	.wcp-content--front .wp-block-columns:has(> .wp-block-column > .wp-block-buttons:only-child) > .wp-block-column:last-child {
		flex: 0 0 auto;
	}

	.wcp-content--front .wp-block-columns:has(> .wp-block-column > .wp-block-buttons:only-child) .wp-block-buttons {
		justify-content: flex-end;
	}
}

/*
 * .c__areas-served-card - a raw wp:html block carried over from the old site.
 * It arrived with class names and no stylesheet, so all sixteen service areas
 * rendered as one tall column of bullets. Restyled here as a card of link
 * chips; the markup is untouched (it is the client's HTML block).
 */
.wcp-content .c__areas-served-card {
	padding: var(--space-6);
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-1);
}

.wcp-content .c__areas-served-card-header {
	margin-bottom: var(--space-5);
	text-align: center;
}

.wcp-content .c__areas-served-card-title {
	margin-bottom: var(--space-2);
}

.wcp-content .c__areas-served-card-subtitle {
	margin-bottom: 0;
	color: var(--c-text-muted);
}

.wcp-content .c__areas-served-card-list {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	gap: var(--space-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

.wcp-content .c__areas-served-card-list li {
	margin: 0;
}

.wcp-content .c__areas-served-card-link {
	display: flex;
	align-items: center;
	/* 44px: these are the densest tap targets on the page. */
	min-height: 44px;
	padding-inline: var(--space-3);
	background: var(--c-bg);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-sm);
	color: var(--c-text);
	font-weight: 500;
	font-size: 0.9375rem;
	text-decoration: none;
	transition: border-color 0.15s ease, color 0.15s ease;
}

.wcp-content .c__areas-served-card-link:hover,
.wcp-content .c__areas-served-card-link:focus-visible {
	border-color: var(--c-primary);
	color: var(--c-primary-hover);
	text-decoration: underline;
}

[data-theme="dark"] .wcp-content .c__areas-served-card-link:hover,
[data-theme="dark"] .wcp-content .c__areas-served-card-link:focus-visible {
	color: var(--c-primary);
}

/* .wcp-iconlist - checkmark bullets via a CSS mask, so the mark always
   matches the current theme's primary colour with no extra image asset. */
.wcp-content .wcp-iconlist {
	list-style: none;
	display: grid;
	gap: var(--space-3);
	padding-left: 0;
	margin-bottom: var(--space-5);
}

.wcp-content .wcp-iconlist li {
	position: relative;
	padding-left: calc(1.5em + var(--space-2));
	margin-bottom: 0;
}

/* Task 10 fix: a handful of iconlist rows (the NAP block on the home,
   contact, and location pages -- address/phone/email) contain a real link
   rather than plain feature text. Same padding/negative-margin hit-area
   trick; these are already wide enough, only the block axis is short. */
.wcp-content .wcp-iconlist li a {
	display: inline-block;
	padding-block: 11px;
	margin-block: -11px;
}

/* Task 10 fix: several migrated pages (home, contact, some location pages)
   carry a legacy "Phone: <a>...</a>" / "Email: <a>...</a>" paragraph as
   plain content, not a styled button. tel:/mailto: links are always a
   short atomic string (a number or address) that was never going to wrap
   mid-line, so forcing inline-block for the same hit-area trick used
   throughout this file carries none of the line-wrap risk a general
   "every inline content link" rule would. */
.wcp-content p a[href^="tel:"],
.wcp-content p a[href^="mailto:"] {
	display: inline-block;
	padding-block: 11px;
	margin-block: -11px;
}

.wcp-content .wcp-iconlist li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.15em;
	width: 1.2em;
	height: 1.2em;
	background-color: var(--c-primary-hover);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.55 17.6 4 12l1.4-1.4 4.15 4.15L18.6 5.7 20 7.1z'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.55 17.6 4 12l1.4-1.4 4.15 4.15L18.6 5.7 20 7.1z'/%3E%3C/svg%3E");
	mask-repeat: no-repeat;
	-webkit-mask-repeat: no-repeat;
	mask-size: contain;
	-webkit-mask-size: contain;
}

[data-theme="dark"] .wcp-content .wcp-iconlist li::before {
	background-color: var(--c-primary);
}

/* .wcp-iconbox / .wcp-imagebox - card-style groups. */
.wcp-content .wcp-iconbox,
.wcp-content .wcp-imagebox {
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	padding: var(--space-5);
	box-shadow: var(--shadow-1);
	transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.wcp-content .wcp-iconbox:hover,
.wcp-content .wcp-imagebox:hover {
	box-shadow: var(--shadow-2);
	transform: translateY(-2px);
}

.wcp-content .wcp-iconbox::before {
	content: "";
	display: block;
	width: 44px;
	height: 44px;
	margin-bottom: var(--space-3);
	background-color: var(--c-primary-hover);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.8s6.4 7 6.4 11a6.4 6.4 0 1 1-12.8 0c0-4 6.4-11 6.4-11z'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.8s6.4 7 6.4 11a6.4 6.4 0 1 1-12.8 0c0-4 6.4-11 6.4-11z'/%3E%3C/svg%3E");
	mask-repeat: no-repeat;
	-webkit-mask-repeat: no-repeat;
	mask-size: contain;
	-webkit-mask-size: contain;
	border-radius: var(--radius-sm);
}

[data-theme="dark"] .wcp-content .wcp-iconbox::before {
	background-color: var(--c-primary);
}

.wcp-content .wcp-iconbox h3,
.wcp-content .wcp-imagebox h3 {
	margin-bottom: var(--space-2);
}

.wcp-content .wcp-iconbox p:last-child,
.wcp-content .wcp-imagebox p:last-child {
	margin-bottom: 0;
	color: var(--c-text-muted);
}

.wcp-content .wcp-imagebox figure,
.wcp-content .wcp-imagebox > img {
	margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) var(--space-4);
	border-radius: var(--radius) var(--radius) 0 0;
	aspect-ratio: 4 / 3;
	overflow: hidden;
}

.wcp-content .wcp-imagebox img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

/* wp:details accordion */
.wcp-content .wp-block-details {
	border: 1px solid var(--c-border);
	border-radius: var(--radius-sm);
	padding: var(--space-3) var(--space-4);
	margin-bottom: var(--space-3);
	background: var(--c-surface);
}

.wcp-content .wp-block-details summary {
	cursor: pointer;
	list-style: none;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	font-weight: 600;
	min-height: 44px;
	padding-block: var(--space-1);
}

.wcp-content .wp-block-details summary::-webkit-details-marker {
	display: none;
}

.wcp-content .wp-block-details summary::after {
	content: "";
	flex-shrink: 0;
	width: 0.6em;
	height: 0.6em;
	border-right: 2px solid currentColor;
	border-bottom: 2px solid currentColor;
	transform: rotate(45deg);
	transition: transform 0.2s ease;
}

.wcp-content .wp-block-details[open] summary::after {
	transform: rotate(-135deg);
}

.wcp-content .wp-block-details > *:not(summary) {
	margin-top: var(--space-3);
}

.wcp-content .wp-block-details > *:not(summary):last-child {
	margin-bottom: 0;
}

@media (prefers-reduced-motion: no-preference) {
	.wcp-content .wp-block-details[open] > *:not(summary) {
		animation: wcp-details-in 0.2s ease;
	}
}

@keyframes wcp-details-in {
	from {
		opacity: 0;
		transform: translateY(-6px);
	}

	to {
		opacity: 1;
		transform: translateY(0);
	}
}

/* .wcp-map */
.wcp-content .wcp-map {
	width: 100%;
	aspect-ratio: 16 / 9;
	border: 0;
	border-radius: var(--radius);
	box-shadow: var(--shadow-1);
	margin-bottom: var(--space-4);
}

/* .wcp-testimonials */
.wcp-content .wcp-testimonials {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--space-4);
	margin-bottom: var(--space-5);
}

@media (min-width: 768px) {
	.wcp-content .wcp-testimonials {
		grid-template-columns: repeat(2, 1fr);
	}
}

.wcp-content .wcp-testimonials .wp-block-quote {
	margin: 0;
	padding: var(--space-5);
	border-left: 0;
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-1);
	position: relative;
	font-size: 1rem;
}

.wcp-content .wcp-testimonials .wp-block-quote::before {
	content: "\201C";
	position: absolute;
	top: var(--space-3);
	left: var(--space-4);
	font-size: 2.5rem;
	font-weight: 700;
	color: var(--c-primary-hover);
	opacity: 0.35;
	line-height: 1;
}

[data-theme="dark"] .wcp-content .wcp-testimonials .wp-block-quote::before {
	color: var(--c-primary);
}

.wcp-content .wcp-testimonials .wp-block-quote p {
	position: relative;
	z-index: 1;
	margin-bottom: 0;
}

.wcp-content .wcp-testimonials cite {
	display: block;
	margin-top: var(--space-3);
	font-style: normal;
	font-weight: 600;
	color: var(--c-text-muted);
}

/* .wcp-form-slot - the_content swap point (see inc/form.php). While empty
   (pre-Task-6, or if the placeholder is ever left unmatched) it keeps the
   layout stable with a dashed placeholder; once wcp_render_form() fills it,
   :empty no longer matches and the placeholder rules fall away on their
   own. */
.wcp-form-slot {
	display: block;
	margin-bottom: var(--space-4);
}

.wcp-form-slot:empty {
	min-height: 220px;
	background: var(--c-surface);
	border: 1px dashed var(--c-border);
	border-radius: var(--radius);
}

.wcp-form-slot:empty::before {
	content: "Contact form";
	display: flex;
	align-items: center;
	justify-content: center;
	height: 220px;
	color: var(--c-text-muted);
	font-weight: 600;
}

/* .wcp-form (Task 6) - the rendered contact/estimate form. Card treatment
   matches .wcp-iconbox (surface/border/radius/shadow) rather than inventing
   a new visual language; inputs reuse .wcp-search__field's proportions
   (48px min height, same border/radius) for the same reason. */
.wcp-form {
	display: grid;
	gap: var(--space-4);
	max-width: 640px;
	padding: var(--space-5);
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	box-shadow: var(--shadow-1);
}

.wcp-form__field {
	display: grid;
	gap: var(--space-1);
}

.wcp-form__field label {
	font-weight: 600;
	font-size: 0.9375rem;
}

.wcp-form__field input,
.wcp-form__field textarea {
	min-height: 48px;
	padding: var(--space-2) var(--space-3);
	background: var(--c-bg);
	color: var(--c-text);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-sm);
	width: 100%;
}

.wcp-form__field textarea {
	min-height: 128px;
	padding-block: var(--space-2);
	resize: vertical;
}

.wcp-form__field input:focus-visible,
.wcp-form__field textarea:focus-visible {
	border-color: var(--c-primary);
}

/* Classic honeypot - see the comment in inc/form.php for why display:none is
   the right call here. */
.wcp-form__hp {
	display: none;
}

.wcp-form__notice {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	padding: var(--space-3) var(--space-4);
	border-radius: var(--radius-sm);
	font-weight: 600;
	color: var(--c-text);
	max-width: 640px;
	margin-bottom: var(--space-4);
}

.wcp-form__notice .wcp-icon {
	width: 1.25em;
	height: 1.25em;
	flex-shrink: 0;
}

.wcp-form__notice--success {
	background: var(--c-surface-2);
	border: 1px solid var(--c-border);
	border-left: 4px solid var(--c-primary-hover);
}

.wcp-form__notice--success .wcp-icon {
	color: var(--c-primary-hover);
}

[data-theme="dark"] .wcp-form__notice--success .wcp-icon {
	color: var(--c-primary);
}

.wcp-form__notice--error {
	/* Locally-scoped danger ink - tokens.css has no error/danger token yet
	   (Task 3 only defined brand + surface colours), so this follows the
	   same local-custom-property pattern as --btn-fill above rather than
	   reaching into tokens.css for a one-off. Verified AA: 5.8:1 on light
	   --c-surface-2, 5.9:1 on dark --c-surface-2 - both clear the 4.5:1 text
	   minimum, well past the 3:1 a border/icon needs. */
	--wcp-form-danger: #B3261E;
	background: var(--c-surface-2);
	border: 1px solid var(--c-border);
	border-left: 4px solid var(--wcp-form-danger);
}

[data-theme="dark"] .wcp-form__notice--error {
	--wcp-form-danger: #FF8A80;
}

.wcp-form__notice--error .wcp-icon {
	color: var(--wcp-form-danger);
}

/* ==========================================================================
   20. Section variants (is-service / is-product / is-city)
   ========================================================================== */

/* Decorative accent bar - a fill, never text, so --c-accent stays clear of
   the light-mode text-contrast failure the Task 3 audit flagged. */
body.is-service .wcp-page__header::before,
body.is-product .wcp-page__header::before,
body.is-city .wcp-page__header::before {
	content: "";
	display: block;
	width: 64px;
	height: 6px;
	border-radius: 999px;
	background: var(--c-accent);
	margin-bottom: var(--space-3);
}

/* Product spec styling - a denser, two-up grid for water-treatment spec
   lists instead of the single-column default. */
@media (min-width: 640px) {
	body.is-product .wcp-content .wcp-iconlist {
		grid-template-columns: repeat(2, 1fr);
		column-gap: var(--space-5);
	}
}

/* Map full-width - service / product / city pages let the map bleed edge to
   edge instead of sitting inside the reading column. */
body.is-service .wcp-content .wcp-map,
body.is-product .wcp-content .wcp-map,
body.is-city .wcp-content .wcp-map {
	width: 100vw;
	max-width: 100vw;
	margin-inline: calc(50% - 50vw);
	border-radius: 0;
}

/* ==========================================================================
   21. Scroll reveal
   ========================================================================== */

/*
 * TASK 5 HOOK: main.js adds .will-reveal to each [data-reveal] element right
 * before it starts observing it, then adds .revealed once it intersects the
 * viewport. Scoping the hidden state to .will-reveal (rather than the bare
 * attribute) means every [data-reveal] element renders fully visible, with
 * no animation, until that script exists - this task ships with reveals
 * inert, not broken.
 */
[data-reveal].will-reveal {
	opacity: 0;
	transform: translateY(16px);
	transition: opacity 0.6s ease, transform 0.6s ease;
}

[data-reveal].will-reveal.revealed {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	[data-reveal].will-reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* ==========================================================================
   22. Print
   ========================================================================== */

@media print {
	.wcp-header,
	.wcp-footer,
	.wcp-nav-scrim,
	.wcp-cta-band,
	.wcp-skip,
	#wcp-hero-canvas {
		display: none !important;
	}

	.wcp-hero {
		background: none !important;
		color: var(--c-text) !important;
		padding-block: var(--space-4);
	}

	.wcp-hero__headline,
	.wcp-hero__sub {
		color: var(--c-text) !important;
	}

	a {
		color: var(--c-text) !important;
		text-decoration: underline !important;
	}

	body {
		background: #fff !important;
	}
}

/* Cloudflare Turnstile widget on the contact form. */
.wcp-form__turnstile {
	margin: var(--space-4) 0;
	min-height: 65px;
	display: flex;
	justify-content: center;
}

/*
 * Front page bands. Every other h2-delimited section sits on a surface card so
 * adjacent topics stop running together. Same surface + radius the CTA band
 * uses, so this reads as the existing design language rather than a new one.
 * Both surfaces are tokens, so dark mode follows automatically.
 */
.wcp-content--front .wcp-band {
	padding-block: var(--space-6);
	/*
	 * Every band carries the same inline padding, tinted or not. Only putting it
	 * on the tinted ones made the content jump 32px left and right from section
	 * to section, which read as the page being misaligned.
	 */
	padding-inline: var(--space-5);
}

.wcp-content--front .wcp-band:nth-of-type(even) {
	/*
	 * surface-2, not surface: --c-surface is #F7F9FC against a #FFFFFF page,
	 * a ~3% step that reads as nothing. surface-2 is the same value the CTA
	 * band uses and is actually visible. The inset shadow gives the panel a
	 * defined top and bottom edge so sections stop running together.
	 */
	background: var(--c-surface-2);
	border-block: 1px solid var(--c-border);
	border-radius: var(--radius);
	margin-block: var(--space-5);
}

@media (max-width: 640px) {
	.wcp-content--front .wcp-band:nth-of-type(even) {
		padding-inline: var(--space-4);
	}
}

/*
 * Callout bands: a heading, a sentence or two and a button, with no media.
 * Full-width and left-aligned they read as thin strips against the richer
 * sections around them, so they are centred and held to a comfortable
 * measure instead.
 */
.wcp-content--front .wcp-band--callout {
	text-align: center;
}

.wcp-content--front .wcp-band--callout > * {
	margin-inline: auto;
}

.wcp-content--front .wcp-band--callout p {
	max-width: 62ch;
}

.wcp-content--front .wcp-band--callout .wp-block-buttons {
	justify-content: center;
}

/*
 * Supporting imagery on the front page. The library mixes portrait and
 * landscape originals, so these are cropped to a common ratio rather than
 * letting a 1800x2400 re-pipe photo tower over a 1200x800 inspection shot.
 */
.wcp-content--front figure.wcp-service-media img,
.wcp-content--front .wcp-service-media .wp-block-image img {
	aspect-ratio: 4 / 3;
	object-fit: cover;
	width: 100%;
	/*
	 * Capped: at full column width these ran ~528px and dwarfed the four-item
	 * lists beside them, leaving a lot of dead space in the row.
	 */
	max-width: 320px;
	border-radius: var(--radius-sm);
}

.wcp-content--front .wcp-service-media .wp-block-image,
.wcp-content--front figure.wcp-service-media {
	margin-block-end: var(--space-3);
}

/*
 * The service rows are [list] | [image + button]. Give the media column the
 * smaller share and centre the two vertically, so a short list no longer sits
 * against a tall image with a gap underneath.
 */
.wcp-content--front .wp-block-columns:has(> .wcp-service-media) {
	align-items: center;
	gap: var(--space-5);
}

/* Gutenberg's own column rule sets flex-basis on .wp-block-columns > .wp-block-column,
   so this has to match that specificity to take effect. */
.wcp-content--front .wp-block-columns > .wp-block-column.wcp-service-media {
	flex-basis: 36%;
	flex-grow: 0;
}

@media (max-width: 781px) {
	.wcp-content--front .wp-block-columns > .wp-block-column.wcp-service-media {
		flex-basis: 100%;
	}

	.wcp-content--front figure.wcp-service-media img,
	.wcp-content--front .wcp-service-media .wp-block-image img {
		max-width: 100%;
	}
}

/* The 24/7 badge is a transparent PNG, so it is sized as an icon, not a photo. */
.wcp-content--front .wcp-band-icon img,
.wcp-content--front .wcp-emergency-badge img {
	width: 132px;
	height: auto;
	margin-inline: auto;
	border-radius: 0;
}

.wcp-content--front .wcp-band-icon,
.wcp-content--front .wcp-emergency-badge {
	margin-block-end: var(--space-3);
}

/* Team photo in the contact block. */
.wcp-content--front .wcp-contact-photo img {
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border-radius: var(--radius-sm);
	box-shadow: var(--shadow-1);
}

/* Inline icons on the contact details - a marker for each line, not decoration.
   inline-block matters: the base reset makes every svg display:block, which was
   knocking these onto their own line above the text they label. */
.wcp-content--front .wcp-contact-icon {
	display: inline-block;
	width: 1.1em;
	height: 1.1em;
	vertical-align: -0.18em;
	margin-inline-end: 0.5em;
	color: var(--c-primary);
	flex: none;
}

/* Real customer video testimonials, side by side on desktop. */
.wcp-content--front .wcp-testimonial {
	margin-block: var(--space-4);
}

.wcp-content--front .wcp-testimonial figcaption {
	font-size: 0.9rem;
	color: var(--c-text-muted);
	margin-block-start: var(--space-2);
	text-align: center;
}

@media (min-width: 782px) {
	.wcp-content--front .wcp-band .wcp-testimonial {
		display: inline-block;
		width: calc(50% - var(--space-3));
		vertical-align: top;
		/*
		 * Side by side, the pair's own block margins only unbalance the row -
		 * the first video hung 24px below the heading beside it. The column
		 * gap and the figcaption margins carry the spacing at this width;
		 * below it the stacked layout keeps the block margin above.
		 */
		margin-block: 0;
	}

	.wcp-content--front .wcp-band .wcp-testimonial + .wcp-testimonial {
		margin-inline-start: var(--space-4);
	}
}

/* The same card shadow the contact photo and iconboxes carry - the bare
   video rectangles were the only media on the page with no elevation. */
.wcp-content--front .wcp-testimonial .wp-block-embed__wrapper {
	box-shadow: var(--shadow-1);
}

/*
 * Heading rhythm on the front page. Gutenberg's flow layout zeroes the margins
 * on a block that is first or last in its container, which left several
 * headings sitting flush against the copy under them.
 */
.wcp-content--front .wcp-band h2 {
	margin-block-end: var(--space-3);
}

.wcp-content--front .wcp-band h3 {
	margin-block-start: var(--space-4);
	margin-block-end: var(--space-2);
}

.wcp-content--front .wcp-band .wp-block-column > h3:first-child {
	margin-block-start: 0;
}

.wcp-content--front .wcp-band p {
	margin-block-end: var(--space-3);
}

.wcp-content--front .wcp-band .wp-block-buttons {
	margin-block-start: var(--space-4);
}

/*
 * 2026-08-20 front-page polish pass.
 */

/* The rhythm rule above re-set the top margin the cards block uses to pin
   its action row (`margin: auto ...` in the .wcp-cards rules), so the three
   Learn More buttons floated at whatever height each card's copy left them.
   Re-assert the pin at higher specificity. */
.wcp-content--front .wcp-band .wcp-cards .wp-block-buttons {
	margin-block-start: auto;
}

/* A band's bottom edge belongs to its padding. The last block's own bottom
   margin stacked on top of it - 64px under the cards, 32px under a columns
   row, 24px under a buttons row - so every band ended a different distance
   from the next one, top-heavy against the uniform 48px above. */
.wcp-content--front .wcp-band > :last-child {
	margin-block-end: 0;
}

/* Short copy columns beside tall media (the testimonial videos, the Facebook
   timeline) sat top-aligned with a hole underneath. Centring matches the
   photo/text band treatment above. The contact row keeps its own rule below. */
.wcp-content--front .wcp-band > .wp-block-columns:has(.wcp-testimonial),
.wcp-content--front .wcp-band > .wp-block-columns:has(iframe[src*="facebook.com"]),
.wcp-content--front .wcp-band > .wp-block-columns:has(.wcp-form-slot) {
	align-items: center;
}

/* Section icon on the contact band: a solid primary disc above the kicker,
   sized to the iconbox marker. Decorative only - the svg is aria-hidden. */
.wcp-content--front .wcp-contact-badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	border-radius: 50%;
	background: var(--c-primary);
	box-shadow: var(--shadow-1);
	margin-block-end: var(--space-3);
}

.wcp-content--front .wcp-contact-badge .wcp-icon {
	width: 26px;
	height: 26px;
	color: #fff;
}

/* The 24/7 iconbox that closes the contact column. The band-level h3 rule
   would push its heading 24px down inside the card, and the box wants a
   clear break from the detail rows above it. */
.wcp-content--front .wcp-contact-247 {
	margin-block-start: var(--space-4);
}

.wcp-content--front .wcp-band .wcp-iconbox h3 {
	margin-block-start: 0;
}
