/*
 * 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 / 640 / 768 / 1024 / 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
 *   23. Front page bands
 *   24. Contact / estimate page (body.is-contact)
 *   25. Inner page sections (.wcp-sect)
 * ----------------------------------------------------------------------- */

/* ==========================================================================
   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.65;
	-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
   ========================================================================== */

/*
 * Two families: Archivo carries every heading and display moment, Public
 * Sans carries body copy and UI. Headings sit in --c-heading (a deep navy,
 * per-install overridable) rather than body ink, so the brand colour shows
 * up in the type itself and not only in buttons.
 */

h1,
h2,
h3,
h4,
h5,
h6 {
	margin: 0 0 var(--space-3);
	font-family: var(--font-display);
	font-weight: 700;
	line-height: 1.15;
	letter-spacing: var(--tracking-tight);
	color: var(--c-heading);
	text-wrap: balance;
}

h1 {
	font-size: clamp(2rem, 1.5rem + 2vw, 3rem);
	line-height: 1.08;
}

h2 {
	font-size: clamp(1.625rem, 1.3rem + 1.3vw, 2.375rem);
	line-height: 1.12;
}

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

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

h5,
h6 {
	font-family: var(--font-sans);
	font-size: 0.8125rem;
	font-weight: 700;
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
	color: var(--c-eyebrow);
}

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

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

/* Eyebrow / kicker - the small letter-spaced label that sits above a
   heading. Replaces the old accent-bar ornament everywhere. */
.wcp-eyebrow {
	display: block;
	margin: 0 0 var(--space-2);
	font-family: var(--font-sans);
	font-size: 0.8125rem;
	font-weight: 700;
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
	color: var(--c-eyebrow);
}

/* Lede - the one larger, quieter sentence under a page or section title. */
.wcp-lede {
	font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
	line-height: 1.6;
	color: var(--c-text-muted);
	max-width: 60ch;
}

/* ==========================================================================
   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: 1.5px solid transparent;
	border-radius: var(--radius-sm);
	font-family: var(--font-sans);
	font-weight: 600;
	font-size: 0.9375rem;
	letter-spacing: 0.005em;
	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, box-shadow 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);
	box-shadow: var(--shadow-1);
}

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

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

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

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

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

/*
 * On-ink variants - buttons that sit on the navy ground (hero, CTA card,
 * footer). A brand-primary fill would vanish into the ink on the SC install
 * (#14386C on #0A2240), so the primary action there is white with ink text,
 * and the ghost is white-on-transparent. Scoped by container, not by a
 * modifier class, so the templates need no per-surface markup.
 */
.wcp-onink .btn--primary,
.wcp-onink .btn--primary:hover,
.wcp-onink .btn--primary:focus-visible {
	background: var(--c-on-ink);
	border-color: var(--c-on-ink);
	color: var(--c-ink);
}

.wcp-onink .btn--primary:hover,
.wcp-onink .btn--primary:focus-visible {
	box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
}

.wcp-onink .btn--ghost {
	color: var(--c-on-ink);
	border-color: rgba(255, 255, 255, 0.42);
	background: transparent;
}

.wcp-onink .btn--ghost:hover,
.wcp-onink .btn--ghost:focus-visible {
	color: var(--c-on-ink);
	border-color: var(--c-on-ink);
	background: rgba(255, 255, 255, 0.10);
}

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

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

/* Text link with a trailing arrow - "Learn more", "Read article". */
.wcp-arrowlink {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	min-height: 44px;
	font-weight: 600;
	color: var(--c-primary-hover);
	text-decoration: none;
}

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

.wcp-arrowlink::after {
	content: "\2192";
	display: inline-block;
	transition: transform 0.18s ease;
}

.wcp-arrowlink:hover::after,
.wcp-arrowlink:focus-visible::after {
	transform: translateX(4px);
}

.wcp-arrowlink:hover,
.wcp-arrowlink:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* ==========================================================================
   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);
	transition: box-shadow 0.2s ease;
}

/*
 * main.js adds .is-scrolled to #wcp-header past a scroll threshold: the
 * utility strip folds away and the bar picks up a soft shadow so it reads as
 * floating over the page rather than being part of it.
 */
.wcp-header.is-scrolled {
	box-shadow: var(--shadow-1);
}

.wcp-header.is-scrolled .wcp-header__utility {
	max-height: 0;
	padding-block: 0;
	opacity: 0;
	overflow: hidden;
}

.wcp-header__utility {
	background: var(--c-ink);
	color: var(--c-on-ink);
	/* 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;
	letter-spacing: 0.01em;
	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-5);
	padding-block: 6px;
}

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

.wcp-utility__item {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	margin: 0;
	white-space: nowrap;
	color: var(--c-on-ink-muted);
}

.wcp-utility__link {
	color: var(--c-on-ink);
	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 is a real, reachable control. */
	padding-block: 11px;
	margin-block: -11px;
}

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

.wcp-utility__item .wcp-icon {
	width: 14px;
	height: 14px;
	opacity: 0.85;
}

.wcp-header__bar {
	padding-block: 10px;
}

@media (min-width: 768px) {
	.wcp-header__bar {
		padding-block: 12px;
	}
}

.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: 52px;
	max-width: 100%;
	width: auto;
}

@media (min-width: 768px) {
	.wcp-header__brand img {
		max-height: 60px;
	}
}

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

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

.wcp-wordmark__lead {
	font-family: var(--font-display);
	font-weight: 800;
	font-size: 1.125rem;
	letter-spacing: var(--tracking-tight);
}

.wcp-wordmark__sub {
	font-size: 0.7rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	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-3);
	}
}

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

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

.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;
	}
}

/*
 * The header phone is a bold text link, not a second bordered button - two
 * outlined pills side by side was the busiest part of the old bar. It keeps
 * the .btn box (48px tap target, icon slot) and drops the chrome. The same
 * wcp_phone_button() output is a full ghost button in the nav panel foot and
 * the CTA card, where the ghost chrome is wanted.
 */
.wcp-header__cta .wcp-phone {
	border-color: transparent;
	background: transparent;
	color: var(--c-heading);
	font-weight: 700;
	font-size: 1rem;
	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-header__cta .wcp-phone .wcp-icon {
	width: 1.2em;
	height: 1.2em;
	color: var(--c-primary-hover);
}

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

.wcp-header__cta .wcp-phone:hover,
.wcp-header__cta .wcp-phone:focus-visible {
	background: transparent;
	border-color: transparent;
	color: var(--c-primary-hover);
	text-decoration: underline;
	text-underline-offset: 0.25em;
	text-decoration-thickness: 2px;
}

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

.wcp-phone__number {
	display: none;
}

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

	.wcp-header__cta .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;
	}
}

/* Staging marker - printed by header.php only when WCP_STAGING is defined in
   wp-config.php, so a preview copy can never be mistaken for the live site. */
.wcp-staging {
	position: fixed;
	left: var(--space-3);
	bottom: var(--space-3);
	z-index: 300;
	padding: 6px 12px;
	background: var(--c-ink);
	color: var(--c-on-ink);
	border: 1px solid var(--c-on-ink-border);
	border-radius: 999px;
	font-size: 0.8125rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	box-shadow: var(--shadow-2);
	pointer-events: none;
}

/* ==========================================================================
   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: 600;
	font-size: 1.0625rem;
	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;
}

/* Non-clickable group headings inside a dropdown (SC install's Water
   Treatment menu: "City Water Treatment" / "Well Water Treatment" /
   "Reverse Osmosis"). Items carry .wcp-menu-group from the menu editor. */
.wcp-menu .wcp-menu-group > a {
	pointer-events: none;
	cursor: default;
	min-height: 32px;
	font-size: 0.78em;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--c-text-muted);
	opacity: 0.85;
}

.wcp-menu .sub-menu .wcp-menu-group:not(:first-child) > a {
	margin-top: var(--space-2);
	border-top: 1px solid var(--c-border);
	border-radius: 0;
}

.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 {
		position: relative;
		min-height: 44px;
		padding: var(--space-2) 10px;
		border-radius: var(--radius-sm);
		font-size: 0.9375rem;
		font-weight: 600;
	}

	/* Animated underline instead of a hover pill; it stays on for the
	   current page and its section. */
	.wcp-menu > .menu-item > a::before {
		content: "";
		position: absolute;
		left: 10px;
		right: 10px;
		bottom: 4px;
		height: 2px;
		background: var(--c-primary);
		transform: scaleX(0);
		transform-origin: left;
		transition: transform 0.2s ease;
	}

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

	.wcp-menu > .menu-item > a:hover::before,
	.wcp-menu > .menu-item > a:focus-visible::before,
	.wcp-menu > .current-menu-item > a::before,
	.wcp-menu > .current-menu-ancestor > a::before,
	.wcp-menu > .current_page_parent > a::before {
		transform: scaleX(1);
	}

	/*
	 * 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: 250px;
		margin: 0;
		padding: var(--space-2);
		background: var(--c-bg);
		border: 1px solid var(--c-border);
		border-radius: var(--radius);
		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-3);
		border-radius: var(--radius-sm);
		color: var(--c-text);
		font-size: 0.9375rem;
	}

	.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
   ========================================================================== */

/*
 * The footer is the deepest ground on the page - navy ink, light type - so
 * every page closes with weight instead of fading out into grey. When the
 * CTA card precedes it (footer.php adds --after-cta) the top padding grows
 * to make room for the card, which overlaps this edge by --cta-overlap.
 */
.wcp-footer {
	--cta-overlap: 72px;
	position: relative;
	background: var(--c-ink);
	color: var(--c-on-ink-muted);
	margin-top: var(--space-8);
}

.wcp-footer--after-cta {
	margin-top: 0;
}

.wcp-footer a {
	color: var(--c-on-ink);
}

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

.wcp-footer--after-cta .wcp-footer__grid {
	padding-top: calc(var(--space-7) + var(--cta-overlap));
}

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

	.wcp-footer--after-cta .wcp-footer__grid {
		padding-top: calc(var(--space-8) + var(--cta-overlap));
	}
}

@media (min-width: 1024px) {
	.wcp-footer__grid {
		grid-template-columns: 1.5fr 1fr 1fr 1.2fr;
		gap: var(--space-7);
	}
}

.wcp-footer__logo {
	display: inline-block;
	margin-bottom: var(--space-4);
}

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

.wcp-footer__about {
	color: var(--c-on-ink-muted);
	max-width: 36ch;
	line-height: 1.65;
}

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

.wcp-footer__badge .wcp-icon {
	width: 20px;
	height: 20px;
	color: var(--c-accent);
}

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

.wcp-footer__social a {
	font-weight: 600;
	text-decoration: none;
	/* 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__social a:hover {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.wcp-footer__heading {
	font-family: var(--font-sans);
	font-size: 0.8125rem;
	font-weight: 700;
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
	color: var(--c-on-ink);
	margin-bottom: var(--space-4);
}

.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-on-ink-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 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 16px column
	   gap (--space-3), so it never overlaps the next column. */
	display: inline-block;
	padding: 10.5px 7px;
	margin: -10.5px -7px;
	transition: color 0.15s ease;
}

.wcp-footer__list a:hover {
	color: var(--c-on-ink);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.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-on-ink-muted);
}

.wcp-footer__nap-item a {
	color: var(--c-on-ink);
	text-decoration: none;
	/* 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 does not shift the
	   icon vertical position (the link layout-box height is unchanged by
	   the canceling negative margin). */
	display: inline-block;
	padding-block: 10px;
	margin-block: -10px;
}

.wcp-footer__nap-item a:hover {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.wcp-footer__nap-item .wcp-icon {
	flex-shrink: 0;
	width: 18px;
	height: 18px;
	margin-top: 0.15em;
	color: var(--c-accent);
}

/* Footer CTA: the on-ink primary (white) via the shared .wcp-onink scope on
   the <footer> element itself - see footer.php. */

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

.wcp-footer__legal p {
	margin: 0;
}

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

/* A quiet trail on the page ground - no bar, no border. It belongs to the
   page header below it rather than to the site chrome above. */
.wcp-breadcrumbs {
	background: transparent;
}

.wcp-breadcrumbs__list {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-1);
	padding-block: var(--space-4) 0;
	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 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;
	text-underline-offset: 0.2em;
}

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

.wcp-breadcrumbs__item + .wcp-breadcrumbs__item::before {
	content: "/";
	margin-inline: var(--space-1) var(--space-2);
	opacity: 0.45;
}

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

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

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

/*
 * Composition: copy left, the company photograph right, on a solid navy ink
 * ground with a soft brand-coloured glow behind the copy. The trust strip
 * (section 12) continues the same ground directly beneath, separated by a
 * hairline, so hero + credentials read as one confident block with a
 * straight bottom edge. Layering is three deep - canvas (0), glow (1),
 * content (2).
 *
 * The water-caustic canvas (assets/js/hero-canvas.js) still mounts here; it
 * is dimmed and screen-blended so it reads as light moving through the navy,
 * not as a pattern on top of it.
 */

.wcp-hero {
	position: relative;
	isolation: isolate;
	overflow: clip;
	background: var(--c-ink);
	color: var(--c-on-ink);
	padding-block: var(--space-7) var(--space-7);
}

.wcp-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background:
		radial-gradient(80% 90% at 8% 0%, color-mix(in srgb, var(--c-primary) 34%, transparent), transparent 62%),
		radial-gradient(60% 70% at 100% 100%, color-mix(in srgb, var(--c-ink-2) 80%, transparent), transparent 60%);
}

.wcp-hero__canvas {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	opacity: 0.55;
	mix-blend-mode: screen;
}

.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__eyebrow {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	margin: 0 0 var(--space-4);
	font-size: 0.8125rem;
	font-weight: 700;
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
	color: var(--c-on-ink-muted);
}

.wcp-hero__eyebrow::before {
	content: "";
	width: 28px;
	height: 2px;
	background: var(--c-accent);
	flex: none;
}

.wcp-hero__headline {
	color: var(--c-on-ink);
	font-size: clamp(2.25rem, 1.5rem + 3.4vw, 3.875rem);
	font-weight: 800;
	line-height: 1.04;
	letter-spacing: -0.025em;
	text-wrap: balance;
	margin-bottom: var(--space-4);
}

.wcp-hero__sub {
	font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
	line-height: 1.6;
	color: var(--c-on-ink-muted);
	max-width: 52ch;
	margin-bottom: var(--space-5);
}

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

/* --- hero media: the real company photograph --- */

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

.wcp-hero__frame {
	position: relative;
	margin: 0;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	border-radius: var(--radius-lg);
	border: 1px solid var(--c-on-ink-border);
	box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}

.wcp-hero__frame::after {
	/* A breath of the ink dropped into the lower edge, so the photograph
	   belongs to the ground instead of sitting on top of it. */
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(180deg, rgba(10, 34, 64, 0) 60%, rgba(10, 34, 64, 0.35));
	pointer-events: none;
}

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

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

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

	.wcp-hero__media {
		max-width: none;
		justify-self: end;
	}

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

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

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

/*
 * The four credentials as the closing row of the hero block: same ink
 * ground, a hairline above, light type. One short band (a single row from
 * 1024px up), icons 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-ink);
	color: var(--c-on-ink);
	border-top: 1px solid var(--c-on-ink-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;
	color: var(--c-on-ink);
}

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

/* 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-on-ink-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);
		justify-content: center;
	}
}

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

/*
 * The closing call to action is a brand-primary card that overlaps the top
 * edge of the ink footer by --cta-overlap (the footer grows its top padding
 * by the same amount - section 9). Card on ink, not band on white: the last
 * thing on every page is the phone number and the contact button, framed.
 */

.wcp-cta-band {
	--cta-overlap: 72px;
	position: relative;
	z-index: 2;
	padding-block: var(--space-6) 0;
	margin-bottom: calc(var(--cta-overlap) * -1);
}

@media (min-width: 768px) {
	.wcp-cta-band {
		padding-top: var(--space-7);
	}
}

.wcp-cta-band__inner {
	background: linear-gradient(135deg, var(--c-primary-hover), var(--c-primary));
	color: var(--c-on-ink);
	border: 1px solid var(--c-on-ink-border);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-2);
	padding: var(--space-6) var(--space-5);
	display: flex;
	flex-direction: column;
	gap: var(--space-5);
	text-align: center;
	align-items: center;
}

[data-theme="dark"] .wcp-cta-band__inner {
	background: linear-gradient(135deg, var(--c-ink-2), var(--c-surface-2));
}

.wcp-cta-band__copy h2 {
	color: var(--c-on-ink);
	margin-bottom: var(--space-2);
	font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.25rem);
}

.wcp-cta-band__copy p {
	color: var(--c-on-ink-muted);
	margin-bottom: 0;
	max-width: 56ch;
	font-size: 1.0625rem;
}

.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-4) var(--space-7);
}

@media (min-width: 768px) {
	.wcp-page__inner {
		padding-block: var(--space-5) var(--space-8);
	}
}

.wcp-page__header {
	margin-bottom: var(--space-5);
	max-width: 52rem;
}

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

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

/* The section eyebrow page.php prints above a service / product / city page
   title ("Plumbing Services", "Water Treatment", "Service Area"). On the
   many migrated pages whose h1 lives inside post_content, this is the only
   thing in the header and it sits directly above that h1. */
.wcp-page__eyebrow {
	margin-bottom: var(--space-2);
}

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

.wcp-content .wcp-page__eyebrow + h1 {
	margin-top: 0;
}

/* --- single post: an editorial measure, not the full 1200px container --- */

.wcp-single .wcp-page__inner {
	max-width: calc(var(--measure) + 2 * var(--space-4));
}

.wcp-single .wcp-page__header {
	max-width: none;
	margin-bottom: 0;
}

.wcp-single .wcp-page__title {
	font-size: clamp(2rem, 1.4rem + 2.4vw, 3.125rem);
	line-height: 1.06;
}

.wcp-single__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2) var(--space-3);
	margin: var(--space-4) 0 0;
	color: var(--c-text-muted);
	font-size: 0.9375rem;
}

.wcp-single__meta > * {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	margin: 0;
}

.wcp-single__meta > * + *::before {
	content: "\00B7";
	margin-right: var(--space-2);
	opacity: 0.6;
}

.wcp-single__meta .wcp-icon {
	width: 16px;
	height: 16px;
	opacity: 0.8;
}

.wcp-single__meta strong {
	font-weight: 600;
	color: var(--c-text);
}

.wcp-single__thumb {
	margin: var(--space-5) 0 var(--space-6);
	border-radius: var(--radius-lg);
	overflow: hidden;
	aspect-ratio: 16 / 9;
	background: var(--c-surface-2);
	box-shadow: var(--shadow-1);
}

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

.wcp-single .entry-content {
	font-size: 1.0625rem;
	line-height: 1.75;
}

@media (min-width: 768px) {
	.wcp-single .entry-content {
		font-size: 1.125rem;
	}
}

.wcp-single .entry-content > h2 {
	margin-top: var(--space-6);
	font-size: clamp(1.5rem, 1.25rem + 1vw, 1.875rem);
}

.wcp-single .entry-content > h3 {
	margin-top: var(--space-5);
}

.wcp-single .entry-content > h1:first-child,
.wcp-single .entry-content > h2:first-child {
	margin-top: 0;
}

.wcp-single .entry-content p,
.wcp-single .entry-content ul,
.wcp-single .entry-content ol {
	margin-bottom: var(--space-4);
}

.wcp-single .entry-content a {
	color: var(--c-primary-hover);
	text-decoration-thickness: 1.5px;
	text-underline-offset: 0.18em;
}

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

.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;
}

/* Inline call to action under the article body: a quiet card, brand rule on
   the left, phone and contact side by side. */
.wcp-single__cta {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
	margin-top: var(--space-7);
	padding: var(--space-5);
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-left: 4px solid var(--c-primary-hover);
	border-radius: var(--radius);
}

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

.wcp-single__cta h2 {
	font-size: 1.375rem;
	margin-bottom: var(--space-1);
}

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

.wcp-single__cta-actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	flex-shrink: 0;
}

@media (min-width: 768px) {
	.wcp-single__cta {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
	}
}

/* Related posts under a single post - full container width again. */
.wcp-related {
	margin-top: var(--space-7);
	padding-top: var(--space-7);
	border-top: 1px solid var(--c-border);
}

.wcp-related__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--space-3) var(--space-5);
	margin-bottom: var(--space-5);
}

.wcp-related__head h2 {
	margin: 0;
}

.wcp-related__head .wcp-eyebrow {
	margin-bottom: var(--space-1);
}


/* 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-4) var(--space-7);
}

@media (min-width: 768px) {
	.wcp-archive {
		padding-block: var(--space-5) var(--space-8);
	}
}

.wcp-archive__header {
	margin-bottom: var(--space-6);
	max-width: 52rem;
}

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

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

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

/*
 * Post card - shared by the blog index, every archive and the related-posts
 * row under a single post (template-parts/post-card.php). Borderless: the
 * photograph is the card, the title is set in the display face, and a small
 * uppercase meta line (date, reading time) sits between them.
 */
.wcp-postgrid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--space-6) var(--space-5);
}

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

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

.wcp-postcard {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.wcp-postcard__media {
	display: block;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: var(--radius);
	background: var(--c-surface-2);
	margin-bottom: var(--space-3);
}

.wcp-postcard__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.35s ease;
}

.wcp-postcard:hover .wcp-postcard__media img {
	transform: scale(1.03);
}

@media (prefers-reduced-motion: reduce) {
	.wcp-postcard:hover .wcp-postcard__media img {
		transform: none;
	}
}

.wcp-postcard__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
	margin: 0 0 var(--space-2);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--c-text-muted);
}

.wcp-postcard__meta > * + *::before {
	content: "\00B7";
	margin-right: var(--space-2);
	opacity: 0.6;
}

.wcp-postcard__title {
	font-size: 1.1875rem;
	line-height: 1.25;
	margin-bottom: var(--space-2);
}

.wcp-postcard__title a {
	color: var(--c-heading);
	text-decoration: none;
	/* Task 10 follow-up fix: same padding/negative-margin hit-area
	   expansion used elsewhere in this file -- at the mobile-390 viewport,
	   short post titles wrap to a single ~24px line, under the 44px
	   tap-target gate. The card is already >=44px wide, so only the block
	   axis needs expansion; 13px measured a real safety margin over the
	   gate (11px measured 43.1px). */
	display: inline-block;
	padding-block: 13px;
	margin-block: -13px;
}

.wcp-postcard__title a:hover {
	color: var(--c-primary-hover);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

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

.wcp-postcard__excerpt {
	color: var(--c-text-muted);
	margin: 0;
	font-size: 0.9375rem;
	line-height: 1.6;
}

/* Featured - the newest post, on page one of the blog index only: photo and
   copy side by side across the full grid width, a rule beneath it. */
.wcp-postcard--featured {
	grid-column: 1 / -1;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-5);
	align-items: center;
	padding-bottom: var(--space-6);
	border-bottom: 1px solid var(--c-border);
}

@media (min-width: 900px) {
	.wcp-postcard--featured {
		grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
		gap: var(--space-7);
	}
}

.wcp-postcard--featured .wcp-postcard__media {
	margin-bottom: 0;
	aspect-ratio: 16 / 10;
	border-radius: var(--radius-lg);
}

.wcp-postcard--featured .wcp-postcard__title {
	font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.125rem);
	margin-bottom: var(--space-3);
}

.wcp-postcard--featured .wcp-postcard__excerpt {
	font-size: 1.0625rem;
	margin-bottom: var(--space-4);
}

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

.navigation.pagination {
	margin-top: var(--space-7);
	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-3);
	border: 1px solid var(--c-border-strong);
	border-radius: var(--radius-sm);
	color: var(--c-text);
	font-weight: 600;
	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);
	border-color: var(--c-primary-hover);
	color: var(--c-primary-hover);
}

/* ==========================================================================
   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 {
	/* The bands (section 23) carry the front page rhythm. */
	padding-block: 0;
}

.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);
}

.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;
	}
}

/*
 * Page lead row (.wcp-lead on a columns block) - the client-approved intro
 * format on the SC service, product and city pages: copy in one column, one
 * photo in the other. Job-site photos are mostly portrait phone shots, and at
 * full content width a 1200x1600 original ran ~1500px tall - two screens of
 * scrolling before the first sentence. The photo keeps its own aspect ratio
 * (no crop - the subject is often at the bottom of the frame) but is capped
 * at 500px, the height the approved staging build used, and hugs the outer
 * edge of its column so the row reads text | photo (or photo | text).
 */
/* Core's columns stylesheet pins align-items: normal !important on the row, so
   vertical centring has to be declared on the columns themselves. */
.wcp-content .wcp-lead > .wp-block-column {
	align-self: center;
}

.wcp-content .wcp-lead > .wp-block-column > figure.wp-block-image {
	display: flex;
	margin: 0;
}

.wcp-content .wcp-lead > .wp-block-column:first-child > figure.wp-block-image {
	justify-content: flex-start;
}

.wcp-content .wcp-lead > .wp-block-column:last-child > figure.wp-block-image {
	justify-content: flex-end;
}

.wcp-content .wcp-lead figure.wp-block-image img {
	width: auto;
	max-width: 100%;
	height: auto;
	max-height: 500px;
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-1);
}

/* Stacked (core stacks columns at 781px): the photo drops under the copy,
   centred, and never taller than about half the screen so the next section
   is always within reach. The !important matches core's own columns rule -
   it has to beat the inline flex-basis the column width attribute writes. */
@media (max-width: 781px) {
	.wcp-content .wcp-lead > .wp-block-column {
		flex-basis: 100% !important;
	}

	/* Both edge rules above carry a pseudo-class, so the stacked rule has to
	   match them or it loses on specificity and the photo stays flush right. */
	.wcp-content .wcp-lead > .wp-block-column:first-child > figure.wp-block-image,
	.wcp-content .wcp-lead > .wp-block-column:last-child > figure.wp-block-image {
		justify-content: center;
	}

	.wcp-content .wcp-lead figure.wp-block-image img {
		max-height: min(400px, 50vh);
	}
}

/* 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.0625rem, 1rem + 0.35vw, 1.25rem);
	font-weight: 600;
	line-height: 1.45;
	color: var(--c-heading);
	margin-bottom: var(--space-3);
}

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

/* Under a section heading the emphasised line is a lede, not a second
   heading. */
.wcp-content .wcp-sectionhead .wcp-heading-text {
	font-weight: 500;
	color: var(--c-text-muted);
}

.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);
	}

	/* Four-card rows (SC home mirrors its approved example's 4-up layout):
	   2x2 on tablets, 4-across from 1280px. */
	.wcp-content .wcp-cards--4 {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 1280px) {
	.wcp-content .wcp-cards--4 {
		grid-template-columns: repeat(4, 1fr);
	}
}

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

.wcp-content .wcp-cards > .wp-block-column:hover {
	transform: translateY(-3px);
	border-color: var(--c-border-strong);
	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.1875rem;
}

.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);
}

/* Inside a card the "Learn More" button becomes a text link with a trailing
   arrow - four filled buttons in a row was the loudest thing on the page. */
.wcp-content .wcp-cards .wp-block-button__link {
	background: transparent;
	color: var(--c-primary-hover);
	padding: 0;
	min-height: 44px;
	border-radius: 0;
	gap: var(--space-2);
}

.wcp-content .wcp-cards .wp-block-button__link::after {
	content: "\2192";
	transition: transform 0.18s ease;
}

.wcp-content .wcp-cards .wp-block-button__link:hover,
.wcp-content .wcp-cards .wp-block-button__link:focus-visible {
	background: transparent;
	color: var(--c-primary-hover);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.wcp-content .wcp-cards .wp-block-button__link:hover::after,
.wcp-content .wcp-cards .wp-block-button__link:focus-visible::after {
	transform: translateX(4px);
}

[data-theme="dark"] .wcp-content .wcp-cards .wp-block-button__link,
[data-theme="dark"] .wcp-content .wcp-cards .wp-block-button__link:hover,
[data-theme="dark"] .wcp-content .wcp-cards .wp-block-button__link:focus-visible {
	color: var(--c-primary);
}

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

.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. Flat at rest, a hairline
   and a lift on hover; the iconbox mark is a tinted square with the drop
   glyph inside it (::before is the tile, ::after the masked glyph). */
.wcp-content .wcp-iconbox,
.wcp-content .wcp-imagebox {
	position: relative;
	background: var(--c-bg);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	padding: var(--space-5);
	transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

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

.wcp-content .wcp-iconbox::before {
	content: "";
	display: block;
	width: 48px;
	height: 48px;
	margin-bottom: var(--space-3);
	background: var(--c-surface-2);
	border-radius: var(--radius);
}

.wcp-content .wcp-iconbox::after {
	content: "";
	position: absolute;
	top: calc(var(--space-5) + 12px);
	left: calc(var(--space-5) + 12px);
	width: 24px;
	height: 24px;
	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;
	pointer-events: none;
}

[data-theme="dark"] .wcp-content .wcp-iconbox::after {
	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);
	padding: var(--space-3) var(--space-4);
	margin-bottom: var(--space-2);
	background: var(--c-bg);
}

.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-6) var(--space-5) var(--space-5);
	border-left: 0;
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-lg);
	position: relative;
	font-size: 1.0625rem;
	line-height: 1.65;
}

.wcp-content .wcp-testimonials .wp-block-quote::before {
	content: "\201C";
	position: absolute;
	top: var(--space-3);
	left: var(--space-4);
	font-family: var(--font-display);
	font-size: 4rem;
	font-weight: 800;
	color: var(--c-primary-hover);
	opacity: 0.16;
	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-bg);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-lg);
	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-strong);
	border-radius: var(--radius-sm);
	width: 100%;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.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);
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-primary) 24%, transparent);
}

/* 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)
   ========================================================================== */

/* The section mark is now the eyebrow page.php prints above the title (see
   .wcp-page__eyebrow in section 14) - the old accent bar ornament is gone.
   What remains here is layout that genuinely differs per section. */

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

/* ==========================================================================
   23. Front page bands
   ========================================================================== */

/*
 * wcp_band_front_sections() (inc/setup.php) wraps each h2-delimited run of
 * the Home page into <section class="wcp-band">. Even bands sit on a
 * full-bleed tinted ground with a hairline top and bottom; odd bands sit on
 * the page white. The band IS the section - no card-within-a-card, no
 * radius, no shadow - so the page reads as a sequence of rooms rather than
 * a stack of panels. Vertical rhythm is carried entirely by the bands, which
 * is why .wcp-content--front itself has no block padding (section 18).
 */
.wcp-content--front .wcp-band {
	padding-block: var(--space-7);
}

@media (min-width: 768px) {
	.wcp-content--front .wcp-band {
		padding-block: var(--space-8);
	}
}

.wcp-content--front .wcp-band:nth-of-type(even) {
	background: var(--c-surface);
	border-block: 1px solid var(--c-border);
	/* Full bleed: break out of .container, then pad back in to its content
	   edge so the copy stays aligned with the bands around it. 100vw includes
	   the scrollbar, same as core .alignfull - acceptable. */
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	padding-inline: max(var(--space-3), calc(50vw - var(--container) / 2 + var(--space-3)));
}

@media (min-width: 768px) {
	.wcp-content--front .wcp-band:nth-of-type(even) {
		padding-inline: max(var(--space-4), calc(50vw - var(--container) / 2 + 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);
}

.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);
	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 carries - 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);
}

/* 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
   Learn More links 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 padding 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: var(--radius);
	background: var(--c-primary-hover);
	margin-block-end: var(--space-3);
}

[data-theme="dark"] .wcp-content--front .wcp-contact-badge {
	background: var(--c-primary);
}

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

[data-theme="dark"] .wcp-content--front .wcp-contact-badge .wcp-icon {
	color: var(--c-bg);
}

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

/* ==========================================================================
   24. Contact / estimate page (body.is-contact)
   ========================================================================== */

/*
 * The estimate page is the site's conversion page, so it gets a treatment of
 * its own without touching its client-approved content. Everything keys off
 * the block order the page already has (copy | form row, 24/7 row, service
 * area card, testimonials row): the opening row becomes a full-bleed ink band
 * - the front-page photograph fading in behind it - with the form as a raised
 * white card that hangs below the band edge; the 24/7 and testimonial rows
 * become proper two-column sections; the service-area card sits on a tinted
 * band. wcp_body_classes() adds .is-contact; page.php passes the photograph
 * in as --wcp-page-photo.
 */

/* Breadcrumb strip continues the ink of the band below it. */
.is-contact .wcp-breadcrumbs {
	background: var(--c-ink);
}

.is-contact .wcp-breadcrumbs__list {
	color: var(--c-on-ink-muted);
	padding-block: var(--space-4) var(--space-2);
}

.is-contact .wcp-breadcrumbs__item a {
	color: var(--c-on-ink-muted);
}

.is-contact .wcp-breadcrumbs__item a:hover {
	color: var(--c-on-ink);
}

.is-contact .wcp-breadcrumbs__item[aria-current],
.is-contact .wcp-breadcrumbs__item span[aria-current] {
	color: var(--c-on-ink);
}

.is-contact .wcp-page__inner {
	padding-top: 0;
	padding-bottom: var(--space-7);
}

.is-contact .wcp-content {
	padding-block: 0;
}

.is-contact .wcp-content > .wp-block-columns {
	margin-bottom: 0;
}

.is-contact .wcp-content > * + * {
	margin-top: var(--space-8);
}

.is-contact .wcp-footer {
	margin-top: var(--space-7);
}

/* --- 1. lead band: copy | form card --- */

.is-contact .wcp-content > .wp-block-columns:first-child {
	position: relative;
	isolation: isolate;
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	padding-block: var(--space-6) var(--space-8);
	padding-inline: max(var(--space-3), calc(50vw - var(--container) / 2 + var(--space-3)));
	background: var(--c-ink);
	color: var(--c-on-ink);
	gap: var(--space-6);
	align-items: flex-start;
}

@media (min-width: 768px) {
	.is-contact .wcp-content > .wp-block-columns:first-child {
		padding-block: var(--space-7) var(--space-8);
		padding-inline: max(var(--space-4), calc(50vw - var(--container) / 2 + var(--space-4)));
		gap: var(--space-7);
	}
}

/* The front-page photograph fading in from the right, under a brand glow.
   Both pseudo-elements sit below the content inside the band's own stacking
   context (isolation: isolate above). */
.is-contact .wcp-content > .wp-block-columns:first-child::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--wcp-page-photo, none) center / cover no-repeat;
	opacity: 0.26;
	-webkit-mask-image: linear-gradient(90deg, transparent 20%, #000 80%);
	mask-image: linear-gradient(90deg, transparent 20%, #000 80%);
	pointer-events: none;
}

.is-contact .wcp-content > .wp-block-columns:first-child::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: radial-gradient(70% 90% at 0% 0%, color-mix(in srgb, var(--c-primary) 36%, transparent), transparent 62%);
	pointer-events: none;
}

.is-contact .wcp-content > .wp-block-columns:first-child > .wp-block-column:first-child {
	padding-top: var(--space-4);
}

/* "Contact Us" kicker -> eyebrow on ink, with the hero's short accent rule. */
.is-contact .wcp-content > .wp-block-columns:first-child .wcp-heading-text {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	margin-bottom: var(--space-4);
	font-size: 0.8125rem;
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
	color: var(--c-on-ink-muted);
}

.is-contact .wcp-content > .wp-block-columns:first-child .wcp-heading-text::before {
	content: "";
	width: 28px;
	height: 2px;
	background: var(--c-accent);
	flex: none;
}

.is-contact .wcp-content > .wp-block-columns:first-child h1 {
	color: var(--c-on-ink);
	font-size: clamp(2.25rem, 1.5rem + 3vw, 3.5rem);
	font-weight: 800;
	line-height: 1.04;
	letter-spacing: -0.025em;
	margin-bottom: var(--space-4);
}

.is-contact .wcp-content > .wp-block-columns:first-child p {
	color: var(--c-on-ink-muted);
	font-size: 1.0625rem;
	line-height: 1.6;
	max-width: 46ch;
}

.is-contact .wcp-content > .wp-block-columns:first-child .wcp-iconlist {
	margin-bottom: var(--space-5);
}

.is-contact .wcp-content > .wp-block-columns:first-child .wcp-iconlist li {
	color: var(--c-on-ink);
	font-weight: 600;
}

.is-contact .wcp-content > .wp-block-columns:first-child .wcp-iconlist li::before {
	background-color: var(--c-accent);
}

/* "Phone: <a>" / "Email: <a>" -> small label over a big white number. The
   label text is a bare text node, so the paragraph carries the label style
   and the link resets it. */
.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="tel:"]),
.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="mailto:"]) {
	max-width: none;
	margin-bottom: var(--space-4);
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
	color: var(--c-on-ink-muted);
}

.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="tel:"]) a,
.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="mailto:"]) a {
	display: block;
	margin: 2px 0 0;
	padding: 0;
	text-transform: none;
	letter-spacing: normal;
	color: var(--c-on-ink);
	text-decoration: none;
}

.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="tel:"]) a {
	font-family: var(--font-display);
	font-size: clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem);
	font-weight: 800;
	letter-spacing: -0.02em;
	line-height: 1.1;
}

.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="mailto:"]) a {
	font-size: 1.0625rem;
	font-weight: 600;
	overflow-wrap: anywhere;
}

.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="tel:"]) a:hover,
.is-contact .wcp-content > .wp-block-columns:first-child p:has(> a[href^="mailto:"]) a:hover {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* Form card: white, raised, two-up fields, and it hangs below the band edge
   by --space-6 (the negative margin shrinks the band; the next section's
   top margin below makes room for the overhang). */
.is-contact .wcp-content > .wp-block-columns:first-child > .wp-block-column:last-child {
	margin-bottom: calc(-1 * (var(--space-8) + var(--space-6)));
}

.is-contact .wcp-form-slot {
	margin-bottom: 0;
}

.is-contact .wcp-form {
	max-width: none;
	padding: var(--space-5);
	background: var(--c-bg);
	color: var(--c-text);
	border: 0;
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-2);
}

@media (min-width: 640px) {
	.is-contact .wcp-form {
		padding: var(--space-6);
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.is-contact .wcp-form__hp,
	.is-contact .wcp-form__field:has(textarea),
	.is-contact .wcp-form__turnstile,
	.is-contact .wcp-form > .btn {
		grid-column: 1 / -1;
	}
}

.is-contact .wcp-form__field label {
	color: var(--c-text);
}

.is-contact .wcp-form > .btn {
	min-height: 54px;
	font-size: 1rem;
	margin-top: var(--space-2);
}

.is-contact .wcp-form__notice {
	max-width: none;
}

.is-contact .wcp-content > .wp-block-columns:first-child + * {
	margin-top: calc(var(--space-6) + var(--space-7));
}

/* --- 2. 24/7 row and 4. testimonials row: heading column | body column --- */

.is-contact .wcp-content > .wp-block-columns:nth-of-type(2),
.is-contact .wcp-content > .wp-block-columns:last-of-type {
	gap: var(--space-6);
	align-items: flex-start;
}

@media (min-width: 782px) {
	.is-contact .wcp-content > .wp-block-columns:nth-of-type(2) > .wp-block-column:first-child,
	.is-contact .wcp-content > .wp-block-columns:last-of-type > .wp-block-column:first-child {
		flex: 0 0 36%;
	}

	.is-contact .wcp-content > .wp-block-columns:nth-of-type(2),
	.is-contact .wcp-content > .wp-block-columns:last-of-type {
		gap: var(--space-8);
	}
}

.is-contact .wcp-content > .wp-block-columns:nth-of-type(2) h2,
.is-contact .wcp-content > .wp-block-columns:last-of-type h2 {
	font-size: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);
	margin-bottom: var(--space-3);
}

.is-contact .wcp-content > .wp-block-columns:nth-of-type(2) h2::before,
.is-contact .wcp-content > .wp-block-columns:last-of-type h2::before {
	content: "";
	display: block;
	width: 36px;
	height: 3px;
	margin-bottom: var(--space-3);
	background: var(--c-accent);
}

.is-contact .wcp-content > .wp-block-columns:nth-of-type(2) p,
.is-contact .wcp-content > .wp-block-columns:last-of-type > .wp-block-column:first-child p {
	font-size: 1.0625rem;
	line-height: 1.65;
	color: var(--c-text-muted);
}

.is-contact .wcp-content > .wp-block-columns:nth-of-type(2) .wp-block-buttons,
.is-contact .wcp-content > .wp-block-columns:last-of-type .wp-block-buttons {
	margin-top: var(--space-4);
}

.is-contact .wcp-content > .wp-block-columns:nth-of-type(2) .wp-block-button__link {
	min-height: 54px;
	padding-inline: var(--space-5);
	font-size: 1.0625rem;
}

/* Testimonials as cards - the same treatment .wcp-testimonials gets. */
.is-contact .wcp-content > .wp-block-columns:last-of-type .wp-block-quote {
	position: relative;
	margin: 0 0 var(--space-4);
	padding: var(--space-6) var(--space-5) var(--space-5);
	background: var(--c-surface);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-lg);
	font-size: 1.0625rem;
	line-height: 1.65;
	color: var(--c-text);
}

.is-contact .wcp-content > .wp-block-columns:last-of-type .wp-block-quote::before {
	content: "\201C";
	position: absolute;
	top: var(--space-3);
	left: var(--space-4);
	font-family: var(--font-display);
	font-size: 4rem;
	font-weight: 800;
	line-height: 1;
	color: var(--c-primary-hover);
	opacity: 0.16;
}

[data-theme="dark"] .is-contact .wcp-content > .wp-block-columns:last-of-type .wp-block-quote::before {
	color: var(--c-primary);
}

.is-contact .wcp-content > .wp-block-columns:last-of-type .wp-block-quote p {
	position: relative;
	margin-bottom: 0;
	color: var(--c-text);
}

.is-contact .wcp-content > .wp-block-columns:last-of-type .wp-block-quote cite {
	display: block;
	margin-top: var(--space-3);
	font-size: 0.9375rem;
	font-style: normal;
	font-weight: 700;
	color: var(--c-heading);
}

.is-contact .wcp-content > .wp-block-columns:last-of-type .wp-block-quote cite::before {
	content: "\2014\00a0";
	opacity: 0.5;
}

/* --- 3. service-area card on a tinted full-bleed band --- */

.is-contact .wcp-content > .c__areas-served-card__wrapper {
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	padding-block: var(--space-7);
	padding-inline: max(var(--space-3), calc(50vw - var(--container) / 2 + var(--space-3)));
	background: var(--c-surface);
	border-block: 1px solid var(--c-border);
}

@media (min-width: 768px) {
	.is-contact .wcp-content > .c__areas-served-card__wrapper {
		padding-block: var(--space-8);
		padding-inline: max(var(--space-4), calc(50vw - var(--container) / 2 + var(--space-4)));
	}
}

.is-contact .wcp-content .c__areas-served-card {
	padding: 0;
	background: transparent;
	border: 0;
	border-radius: 0;
}

.is-contact .wcp-content .c__areas-served-card-link {
	background: var(--c-bg);
}

/* Stacked (phone): the copy sits at the top of the band and the form card at
   the bottom, so the photograph fades in from the top down and lives behind
   the card, not behind the headline and phone number. */
@media (max-width: 767px) {
	.is-contact .wcp-content > .wp-block-columns:first-child::before {
		opacity: 0.22;
		-webkit-mask-image: linear-gradient(180deg, transparent 32%, #000 78%);
		mask-image: linear-gradient(180deg, transparent 32%, #000 78%);
	}
}

/* ==========================================================================
   25. Inner page sections (.wcp-sect, from wcp_band_page_sections)
   ========================================================================== */

/*
 * Service, product, city and plain pages arrive as one flat stack of headings
 * and paragraphs. wcp_band_page_sections() (inc/setup.php) groups every
 * h2-led run into <section class="wcp-sect">; a run that starts with a bare
 * <h2> is split into .wcp-sect__head + .wcp-sect__body. Here each section is
 * a full-bleed band (even ones tinted, with a faint blueprint dot grid), the
 * heading pins on the left with a section number, and the copy sits in a
 * reading column on the right. Sub-runs of three or more h3 + paragraph
 * pairs (the hub service lists) arrive as .wcp-tiles and render as a card
 * grid. The intro row before the first h2 (.wcp-sect-lead, usually the
 * .wcp-lead copy | photo columns) is left in the container.
 */

.wcp-page .wcp-content {
	counter-reset: wcp-sect;
}

/* The sections carry the bottom rhythm; cancel the shell's padding below
   them so the CTA card follows at band distance, not band + shell. */
.wcp-page .wcp-content:has(> .wcp-sect) {
	margin-bottom: calc(-1 * var(--space-7));
}

@media (min-width: 768px) {
	.wcp-page .wcp-content:has(> .wcp-sect) {
		margin-bottom: calc(-1 * var(--space-8));
	}
}

/* --- intro block --- */

.wcp-content .wcp-sect-lead {
	padding-block: var(--space-2) var(--space-6);
}

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

/* Pages without a photo row (the hubs) open with h1 + one paragraph: set
   that paragraph as a lede. */
.wcp-content .wcp-sect-lead > h1 + p {
	font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
	line-height: 1.6;
	color: var(--c-text-muted);
	max-width: 60ch;
}

/* Offset brand panel behind the lead photograph - a hard shadow, so it
   needs no extra element and follows the image wherever it sits. */
.wcp-content .wcp-lead figure.wp-block-image img {
	box-shadow: 16px 16px 0 0 color-mix(in srgb, var(--c-primary) 14%, transparent), var(--shadow-1);
}

@media (max-width: 781px) {
	.wcp-content .wcp-lead figure.wp-block-image img {
		box-shadow: 12px 12px 0 0 color-mix(in srgb, var(--c-primary) 14%, transparent), var(--shadow-1);
	}
}

/* --- bands --- */

.wcp-page .wcp-content > .wcp-sect {
	counter-increment: wcp-sect;
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	margin-block: 0;
	padding-block: var(--space-7);
	padding-inline: max(var(--space-3), calc(50vw - var(--container) / 2 + var(--space-3)));
}

@media (min-width: 768px) {
	.wcp-page .wcp-content > .wcp-sect {
		padding-block: var(--space-8);
		padding-inline: max(var(--space-4), calc(50vw - var(--container) / 2 + var(--space-4)));
	}
}

.wcp-page .wcp-content > .wcp-sect:nth-of-type(even) {
	background-color: var(--c-surface);
	background-image: radial-gradient(color-mix(in srgb, var(--c-heading) 11%, transparent) 1px, transparent 1.5px);
	background-size: 22px 22px;
	border-block: 1px solid var(--c-border);
}

/* --- split sections: pinned heading | reading column --- */

.wcp-content .wcp-sect--split {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-5);
	align-items: start;
}

@media (min-width: 900px) {
	.wcp-content .wcp-sect--split {
		grid-template-columns: minmax(0, 0.36fr) minmax(0, 0.64fr);
		gap: var(--space-6) var(--space-8);
	}

	.wcp-content .wcp-sect__head {
		position: sticky;
		top: 96px;
	}
}

.wcp-content .wcp-sect__head h2 {
	margin-bottom: 0;
	font-size: clamp(1.75rem, 1.35rem + 1.7vw, 2.5rem);
	line-height: 1.1;
}

/* Section number - the run's position on the page, set small in the display
   face over a short accent rule. */
.wcp-content .wcp-sect__head::before,
.wcp-content .wcp-sect--block > .wp-block-columns > .wp-block-column:first-child > h2:first-of-type::before {
	content: counter(wcp-sect, decimal-leading-zero);
	display: block;
	width: 40px;
	margin-bottom: var(--space-3);
	padding-bottom: var(--space-2);
	border-bottom: 2px solid var(--c-accent);
	font-family: var(--font-display);
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	line-height: 1;
	color: var(--c-eyebrow);
}

.wcp-content .wcp-sect--headonly {
	grid-template-columns: minmax(0, 1fr);
}

/* --- block sections (columns rows that already carry their own heading) --- */

.wcp-content .wcp-sect--block > .wp-block-columns {
	margin-bottom: 0;
	gap: var(--space-5);
}

.wcp-content .wcp-sect--block > * + * {
	margin-top: var(--space-6);
}

@media (min-width: 900px) {
	.wcp-content .wcp-sect--block > .wp-block-columns {
		gap: var(--space-8);
	}

	.wcp-content .wcp-sect--block > .wp-block-columns > .wp-block-column:first-child {
		flex: 0 0 34%;
	}
}

.wcp-content .wcp-sect--block > .wp-block-columns > .wp-block-column:first-child > h2 {
	font-size: clamp(1.75rem, 1.35rem + 1.7vw, 2.5rem);
	line-height: 1.1;
}

/* --- body typography --- */

.wcp-content .wcp-sect__body > p,
.wcp-content .wcp-sect__body > ul:not(.wcp-iconlist),
.wcp-content .wcp-sect__body > ol,
.wcp-content .wcp-sect--block .wp-block-column > p {
	max-width: 66ch;
}

.wcp-content .wcp-sect__body p,
.wcp-content .wcp-sect--block .wp-block-column > p {
	font-size: 1.0625rem;
	line-height: 1.7;
}

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

.wcp-content .wcp-sect__body > h3,
.wcp-content .wcp-sect--block .wp-block-column > h3 {
	margin: var(--space-6) 0 var(--space-3);
	padding-left: var(--space-3);
	border-left: 3px solid var(--c-accent);
	font-size: 1.3125rem;
	line-height: 1.3;
}

.wcp-content .wcp-sect__body > h3:first-child,
.wcp-content .wcp-sect--block .wp-block-column > h3:first-child {
	margin-top: 0;
}

.wcp-content .wcp-sect ul:not(.wcp-iconlist) li::marker,
.wcp-content .wcp-sect ol li::marker {
	color: var(--c-primary-hover);
	font-weight: 700;
}

[data-theme="dark"] .wcp-content .wcp-sect ul:not(.wcp-iconlist) li::marker,
[data-theme="dark"] .wcp-content .wcp-sect ol li::marker {
	color: var(--c-primary);
}

/* Check lists become tile rows (product specs, service feature lists). */
.wcp-content .wcp-sect .wcp-iconlist {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-2);
	max-width: none;
}

@media (min-width: 640px) {
	.wcp-content .wcp-sect .wcp-iconlist {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: var(--space-2);
	}
}

.wcp-content .wcp-sect .wcp-iconlist li {
	padding: 12px 16px 12px 46px;
	background: var(--c-bg);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	font-weight: 500;
}

.wcp-content .wcp-sect .wcp-iconlist li::before {
	left: 15px;
	top: 14px;
	width: 20px;
	height: 20px;
}

/* Quotes inside a section (city pages) - card, not a rule. */
.wcp-content .wcp-sect__body > .wp-block-quote,
.wcp-content .wcp-sect--block .wp-block-column > .wp-block-quote {
	position: relative;
	margin: 0 0 var(--space-4);
	padding: var(--space-6) var(--space-5) var(--space-5);
	background: var(--c-bg);
	border: 1px solid var(--c-border);
	border-radius: var(--radius-lg);
	font-size: 1.0625rem;
	line-height: 1.65;
	color: var(--c-text);
}

.wcp-content .wcp-sect__body > .wp-block-quote::before,
.wcp-content .wcp-sect--block .wp-block-column > .wp-block-quote::before {
	content: "\201C";
	position: absolute;
	top: var(--space-3);
	left: var(--space-4);
	font-family: var(--font-display);
	font-size: 4rem;
	font-weight: 800;
	line-height: 1;
	color: var(--c-primary-hover);
	opacity: 0.16;
}

.wcp-content .wcp-sect__body > .wp-block-quote p,
.wcp-content .wcp-sect--block .wp-block-column > .wp-block-quote p {
	position: relative;
	margin-bottom: 0;
}

.wcp-content .wcp-sect__body > .wp-block-quote cite,
.wcp-content .wcp-sect--block .wp-block-column > .wp-block-quote cite {
	display: block;
	margin-top: var(--space-3);
	font-size: 0.9375rem;
	font-style: normal;
	font-weight: 700;
	color: var(--c-heading);
}

.wcp-content .wcp-sect__body > .wp-block-quote cite::before,
.wcp-content .wcp-sect--block .wp-block-column > .wp-block-quote cite::before {
	content: "\2014\00a0";
	opacity: 0.5;
}

/* --- tiles: h3 + paragraph pairs as a card grid --- */

.wcp-content .wcp-tiles {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-4);
	margin-top: var(--space-4);
}

@media (min-width: 640px) {
	.wcp-content .wcp-tiles {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

.wcp-content .wcp-tile {
	padding: var(--space-5);
	background: var(--c-bg);
	border: 1px solid var(--c-border);
	border-radius: var(--radius);
	transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.wcp-content .wcp-tile:hover {
	transform: translateY(-2px);
	border-color: var(--c-border-strong);
	box-shadow: var(--shadow-1);
}

@media (prefers-reduced-motion: reduce) {
	.wcp-content .wcp-tile:hover {
		transform: none;
	}
}

.wcp-content .wcp-tile > h3 {
	margin: 0 0 var(--space-2);
	padding-left: 0;
	border-left: 0;
	font-size: 1.125rem;
	line-height: 1.3;
}

.wcp-content .wcp-tile > h3 a {
	color: var(--c-heading);
	text-decoration: none;
}

.wcp-content .wcp-tile > h3 a::after {
	content: "\00a0\2192";
	color: var(--c-primary-hover);
	display: inline-block;
	transition: transform 0.18s ease;
}

.wcp-content .wcp-tile > h3 a:hover {
	color: var(--c-primary-hover);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.wcp-content .wcp-tile > h3 a:hover::after {
	transform: translateX(3px);
}

.wcp-content .wcp-tile p {
	margin: 0;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--c-text-muted);
	max-width: none;
}

.wcp-content .wcp-tile > * + * {
	margin-top: var(--space-2);
}

/* Buttons rows inside sections breathe a little more. */
.wcp-content .wcp-sect .wp-block-buttons {
	margin-top: var(--space-5);
}

/* Block sections whose heading column opens with a kicker paragraph (the
   city pages' "Contact Us" above "Request an Estimate"): the section number
   goes above the kicker, not between kicker and heading, and the kicker is
   set as an eyebrow. */
.wcp-content .wcp-sect--block > .wp-block-columns > .wp-block-column:first-child > .wcp-heading-text:first-child {
	margin-bottom: var(--space-2);
	font-size: 0.8125rem;
	font-weight: 700;
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
	color: var(--c-eyebrow);
}

.wcp-content .wcp-sect--block > .wp-block-columns > .wp-block-column:first-child > .wcp-heading-text:first-child::before {
	content: counter(wcp-sect, decimal-leading-zero);
	display: block;
	width: 40px;
	margin-bottom: var(--space-3);
	padding-bottom: var(--space-2);
	border-bottom: 2px solid var(--c-accent);
	font-family: var(--font-display);
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	line-height: 1;
	color: var(--c-eyebrow);
}

.wcp-content .wcp-sect--block > .wp-block-columns > .wp-block-column:first-child > .wcp-heading-text:first-child + h2::before {
	content: none;
}

/* A heading column that is only a heading (city pages) should not pin
   short-list rows into tall bands: tighten the vertical padding when the
   section is short. */
.wcp-page .wcp-content > .wcp-sect--block:has(> .wp-block-columns > .wp-block-column:last-child > h3:last-child) {
	padding-block: var(--space-6);
}

.wcp-content .wcp-sect--block .wp-block-column > h3 + h3 {
	margin-top: var(--space-3);
}
