/*
 * Stili di base per header/footer/layout, coerenti con le custom
 * properties generate da theme.json (--wp--preset--*).
 */

/*
 * Tones derived from the theme.json palette, so they follow the Customizer's
 * color overrides (see itd_customizer_inline_css()) instead of staying
 * frozen at the default hex. Patterns and the starter-template builders
 * reference these via var(--itd-*) exactly like they reference the
 * palette presets. --itd-cream and --itd-border are not derived: they are
 * aliases of the `surface` and `line` palette slots (one source each).
 */
:root {
	/* Single source of truth: theme.json's settings.custom.primaryDark (the same
	 * "74% primary, 26% black" formula), emitted by WordPress as
	 * --wp--custom--primary-dark on the front end and inside the block editor
	 * iframe alike, and also used directly by theme.json's own button :hover
	 * background — so this tone never has to be kept in sync by hand in two
	 * places. */
	--itd-primary-dark: var( --wp--custom--primary-dark );
	--itd-accent-tint: color-mix( in srgb, var( --wp--preset--color--secondary, #c08a3e ) 20%, var( --wp--preset--color--base, #ffffff ) );
	--itd-accent-light: color-mix( in srgb, var( --wp--preset--color--secondary, #c08a3e ) 68%, #fff );
	--itd-cream: var( --wp--preset--color--surface, #f0e7da );
	--itd-border: var( --wp--preset--color--line, #e5e4df );
	--itd-on-dark-soft: color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 12%, transparent );
}

.site {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}

.site-content {
	flex: 1 0 auto;
}

/*
 * Same reasoning as the header (see below): the footer was still on the
 * theme.json legacy tokens (deep indigo, cyan links) left over from when
 * only Home had gone light-brand and header/footer were deliberately
 * left shared/dark. Every page is itd-brand now and the header is
 * fixed, so the footer was the last visibly mismatched piece. Uses the
 * itd-brand pine as a dark anchor section (same navy already used
 * for hero overlays/CTA-hover elsewhere) instead of switching to white,
 * so the page still ends on a grounded dark band rather than fading out.
 */
.site-footer {
	background-color: var( --wp--preset--color--primary, #1c3d2e );
	color: var( --wp--preset--color--base, #ffffff );
}

.site-footer__col a,
.site-footer__copy a {
	color: var( --itd-accent-light );
}

.site-footer__col a:hover,
.site-footer__copy a:hover {
	color: var( --wp--preset--color--base, #ffffff );
}

/*
 * The header uses the default palette (pine/brass/muted on white) through
 * the theme.json color presets, so it follows the Customizer's InTouchDesign
 * Colors overrides along with every pattern on the page.
 */
.site-header {
	background-color: var( --wp--preset--color--base, #ffffff );
	color: var( --wp--preset--color--primary, #1c3d2e );
	border-bottom: 1px solid color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 8%, transparent );
}

/*
 * An anchor's target lands below a sticky header, not under it: main.js sets
 * --itd-sticky-offset to the header's real height (0 when it is not sticky).
 */
html {
	scroll-padding-top: var( --itd-sticky-offset, 0px );
}

.site-header.is-sticky {
	position: sticky;
	top: 0;
	z-index: 100;
	box-shadow: 0 8px 24px -12px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 18%, transparent );
}

/*
 * All 3 non-default header layout variants below are gated to desktop
 * widths only. Every one of them overrides `.site-header__inner`'s
 * grid-template-columns or item `order` with a compound selector
 * (`.site-header--x .site-header__inner`) that's more specific than the
 * plain `.site-header__inner`/`.menu-toggle` rules the max-width:1024px
 * mobile query below uses — so without this guard, a chosen desktop
 * layout would keep winning past that breakpoint too (extra/misplaced
 * grid tracks, a logo pushed out of its usual top-left mobile spot),
 * instead of every layout collapsing into the one standard hamburger
 * header on small screens.
 */
@media ( min-width: 1025px ) {
	/*
	 * .site-header__inner below sets display:grid unconditionally, so a
	 * flex-only override here (flex-direction) had no effect — grid still
	 * won because this rule never touched `display`. Overriding the grid
	 * itself (single column, centered items) is what actually stacks logo
	 * above nav instead of leaving them side by side.
	 */
	.site-header--center .site-header__inner {
		grid-template-columns: 1fr;
		justify-items: center;
		text-align: center;
	}

	/*
	 * .site-header__cta has its own `justify-self:end` (needed to pin it to
	 * the right edge of the 3-column default layout) that survives into the
	 * single-column centered grid untouched, since the rule above only sets
	 * `justify-items` (the container's default for children), which an
	 * item's own `justify-self` always overrides. Without this, the button
	 * stayed pinned to the right edge instead of stacking centered like the
	 * logo and nav above it.
	 */
	.site-header--center .site-header__cta {
		justify-self: center;
	}

	/*
	 * Logo and menu clustered together on the left (auto/auto columns
	 * collapse to their content width instead of the default layout's
	 * symmetric 1fr/auto/1fr, which is what keeps the nav centered in the
	 * middle rather than hugging the logo), CTA pinned to the right edge
	 * via the trailing `1fr` track absorbing the rest of the row.
	 * `.site-header__cta` needs no extra rule here: its own
	 * `justify-self:end` already pins it to that track's right edge.
	 */
	.site-header--logo-menu-left .site-header__inner {
		grid-template-columns: auto auto 1fr;
	}

	/*
	 * Menu on the left, logo as the centered focal point, CTA on the right —
	 * same symmetric 1fr/auto/1fr grid as the default layout, with the logo
	 * and nav swapped via `order` so the logo lands in the middle (auto)
	 * track. `order` must be set on all three items, not just the two being
	 * swapped: an unset `order` defaults to 0, which would otherwise sort
	 * before both and put the CTA first.
	 *
	 * Two follow-up fixes over the naive version of this:
	 *
	 * 1. A grid item's automatic minimum width is its content's min-content
	 *    size (effectively "don't shrink below this"). Nav is now sitting in
	 *    a `1fr` track instead of its usual `auto` one, but a 6-item menu's
	 *    min-content is wide — wide enough that this minimum, not the `1fr`
	 *    share, was winning and pushing the nav/cta split off 50/50, which
	 *    dragged the "centered" logo track off-true-center with it (visibly
	 *    so — logo landed ~120px right of the header's actual midpoint at
	 *    common widths). `min-width:0` on the nav track lets it actually
	 *    shrink to its real `1fr` share.
	 * 2. That share can still be narrower than the menu needs on smaller
	 *    desktop widths (just above the 1024px hamburger breakpoint, or
	 *    with a long menu) — without anywhere to shrink to, the menu items would
	 *    visually overflow their now-narrower track and run straight into
	 *    the centered logo. `flex-wrap:wrap` on the menu itself means it
	 *    wraps onto a second line there instead of overlapping anything.
	 */
	.site-header--menu-left-logo-center .site-header__inner > .custom-logo-link,
	.site-header--menu-left-logo-center .site-header__inner > .site-title--default {
		order: 2;
	}

	.site-header--menu-left-logo-center .site-header__inner > .primary-menu-container {
		order: 1;
		min-width: 0;
		justify-content: flex-start;
	}

	.site-header--menu-left-logo-center .site-header__inner > .primary-menu-container .primary-menu {
		flex-wrap: wrap;
	}

	.site-header--menu-left-logo-center .site-header__inner > .site-header__cta {
		order: 3;
	}
}

/*
 * Everything inside .content-area that sits OUTSIDE .entry-content
 * (page/entry titles, archive headers, "no results", comments) had no
 * padding or max-width at all — flush at the viewport edge (x:0) while
 * the entry-content body below was properly constrained via the
 * `.entry-content > *` rule further down. A real bug, easy to miss
 * because a short left-aligned title doesn't visually scream "no
 * padding". NOT applied to `.content-area` itself or to `.entry-content`
 * — those must stay unconstrained so page/post content using
 * alignwide/alignfull blocks can still break out to wideSize/100vw
 * inside them.
 */
.page-header,
.entry-header,
.entry-footer,
.no-results,
.comments-area {
	max-width: var( --wp--style--global--content-size, 720px );
	margin-inline: auto;
	padding-inline: var( --wp--preset--spacing--30 );
}

.content-area > .navigation {
	max-width: var( --wp--style--global--content-size, 720px );
	margin-inline: auto;
	padding-inline: var( --wp--preset--spacing--30 );
	padding-block: 0 var( --wp--preset--spacing--70 );
}

/*
 * Block editor alignment support (align-wide) on the frontend: default
 * content sits at contentSize, .alignwide breaks out to wideSize,
 * .alignfull goes edge-to-edge.
 */

.entry-content > * {
	max-width: var( --wp--style--global--content-size, 720px );
	margin-inline: auto;
}

.entry-content > .alignwide {
	max-width: var( --wp--style--global--wide-size, 1300px );
}

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

.entry-content > .alignleft {
	float: left;
	margin-inline-end: var( --wp--preset--spacing--30 );
}

.entry-content > .alignright {
	float: right;
	margin-inline-start: var( --wp--preset--spacing--30 );
}

.entry-meta,
.entry-footer {
	display: flex;
	flex-wrap: wrap;
	gap: var( --wp--preset--spacing--20 );
}

.site-header__inner,
.site-footer__inner {
	max-width: var( --wp--style--global--wide-size, 1300px );
	margin-inline: auto;
	padding-inline: var( --wp--preset--spacing--30 );
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var( --wp--preset--spacing--30 );
}

.site-header__inner {
	padding-block: var( --wp--preset--spacing--30 );
	/*
	 * Grid instead of flex: with flex + a centered nav, the nav only
	 * centers in the space left between the logo and the CTA button —
	 * since those two are different widths, the nav visibly drifts off
	 * true center. A 1fr/auto/1fr grid keeps the two outer slots equal
	 * width, so the middle (nav) column always lands on the real
	 * horizontal center of the header regardless of logo/CTA width.
	 */
	display: grid;
	grid-template-columns: 1fr auto 1fr;
}

.site-header__inner > .menu-toggle {
	justify-self: end;
}

.site-footer__inner {
	border-top: 1px solid color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 12%, transparent );
	padding-block: var( --wp--preset--spacing--40 );
}

.site-footer__columns {
	max-width: var( --wp--style--global--wide-size, 1300px );
	margin-inline: auto;
	padding-inline: var( --wp--preset--spacing--30 );
	padding-block: var( --wp--preset--spacing--70 ) var( --wp--preset--spacing--50 );
	display: grid;
	grid-template-columns: 1fr;
	gap: var( --wp--preset--spacing--60 );
}

.site-footer__columns--2 {
	grid-template-columns: repeat( 2, 1fr );
}

.site-footer__columns--3 {
	grid-template-columns: repeat( 3, 1fr );
}

.site-footer__columns--4 {
	grid-template-columns: repeat( 4, 1fr );
}

.site-footer__heading {
	margin-block: 0 var( --wp--preset--spacing--30 );
}

.site-footer__col p {
	margin-block: 0 var( --wp--preset--spacing--20 );
}

.site-footer__social {
	display: flex;
	gap: var( --wp--preset--spacing--20 );
	list-style: none;
	margin: var( --wp--preset--spacing--30 ) 0 0;
	padding: 0;
}

.site-footer__social a {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border: 1px solid color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 25%, transparent );
	border-radius: 9999px;
	color: inherit;
	transition: border-color 0.15s ease, color 0.15s ease;
}

.site-footer__social a:hover {
	border-color: var( --itd-accent-light );
	color: var( --itd-accent-light );
}

.site-footer__hours {
	list-style: none;
	margin: 0;
	padding: 0;
}

.site-footer__hours li {
	display: flex;
	justify-content: space-between;
	gap: var( --wp--preset--spacing--30 );
	padding-block: var( --wp--preset--spacing--20 );
	border-bottom: 1px solid color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 12%, transparent );
}

.site-footer__hours li:last-child {
	border-bottom: 0;
}

@media ( max-width: 782px ) {
	.site-footer__columns,
	.site-footer__columns--2,
	.site-footer__columns--3,
	.site-footer__columns--4 {
		grid-template-columns: 1fr;
	}
}

.custom-logo-link img {
	display: block;
	/* The file's height, set by itd_custom_logo_height(): the box keeps its place while the logo loads. */
	height: var( --itd-logo-height, auto );
	width: auto;
	max-height: 60px;
	/* If a narrow header squeezes the width, the logo shrinks inside its box instead of stretching. */
	object-fit: contain;
}

.site-title--default {
	margin: 0;
}

/* Logo plus site title (Customizer → Site Identity), laid out like the default mark and title. */
.custom-logo-link--with-title {
	display: flex;
	align-items: center;
	gap: var( --wp--preset--spacing--20 );
	text-decoration: none;
	color: inherit;
}

.site-title--default a {
	display: flex;
	align-items: center;
	gap: var( --wp--preset--spacing--20 );
	text-decoration: none;
	color: inherit;
}

.site-title__mark {
	flex-shrink: 0;
}

.site-title__text {
	white-space: nowrap;
	font-family: var( --wp--preset--font-family--heading );
	font-weight: 600;
	font-size: 1.25rem;
	letter-spacing: -0.02em;
}

.primary-menu-container {
	flex: 1;
	display: flex;
	justify-content: center;
}

.primary-menu {
	display: flex;
	align-items: center;
	gap: var( --wp--preset--spacing--40 );
	list-style: none;
	margin: 0;
	padding: 0;
}

.primary-menu a {
	position: relative;
	text-decoration: none;
	/* A label breaks between items, never inside one ("About / Us"). */
	white-space: nowrap;
	font-size: 0.9375rem;
	font-weight: 500;
	color: var( --wp--preset--color--muted, #5a6259 );
	transition: color 0.15s ease;
}

.primary-menu a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 100%;
	bottom: -4px;
	height: 2px;
	background-color: var( --wp--preset--color--secondary, #c08a3e );
	border-radius: 1px;
	transition: right 0.2s ease;
}

.primary-menu a:hover {
	color: var( --wp--preset--color--primary, #1c3d2e );
}

.primary-menu a:hover::after {
	right: 0;
}

.primary-menu .current-menu-item > a,
.primary-menu .current_page_item > a {
	color: var( --wp--preset--color--primary, #1c3d2e );
	font-weight: 600;
}

.primary-menu .current-menu-item > a::after,
.primary-menu .current_page_item > a::after {
	right: 0;
}

/*
 * Sub-menus (a menu item with children, from Appearance > Menus or a starter
 * site). Without these rules WordPress's nested <ul class="sub-menu"> showed
 * as an always-open bulleted list that stretched the header. On desktop it is
 * a panel under its parent, opened by hover and by keyboard focus
 * (:focus-within), no script; on a phone it stays in the open menu as a
 * smaller, indented-by-size list (the mobile rules below).
 */
.primary-menu .sub-menu {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* The phone menu's sub-menu toggle (inc/setup.php, main.js): never on desktop. */
.primary-menu .sub-menu-toggle {
	display: none;
}

/*
 * The header switches to the phone menu at 1024px, not at WordPress's 782px:
 * between the two, a logo, six or seven items and the button do not fit on
 * one row, and tablets in portrait (820-834px) land right there. Above it, a
 * menu longer than the row wraps between items, never inside a label.
 */
@media ( min-width: 1025px ) {
	.primary-menu {
		flex-wrap: wrap;
		justify-content: center;
		row-gap: var( --wp--preset--spacing--20 );
	}

	.primary-menu li {
		position: relative;
	}

	.primary-menu .menu-item-has-children > a {
		padding-right: 0.875rem;
	}

	/* A small chevron after the parent's label, drawn with its text color. */
	.primary-menu .menu-item-has-children > a::before {
		content: "";
		position: absolute;
		right: 0;
		top: 50%;
		width: 0.3125rem;
		height: 0.3125rem;
		border-right: 1.5px solid currentColor;
		border-bottom: 1.5px solid currentColor;
		transform: translateY( -70% ) rotate( 45deg );
	}

	.primary-menu .sub-menu {
		position: absolute;
		top: 100%;
		left: calc( -1 * var( --wp--preset--spacing--30, 1rem ) );
		z-index: 110;
		min-width: 15rem;
		margin-top: 0.75rem;
		padding: 0.5rem 0;
		background-color: var( --wp--preset--color--base, #ffffff );
		border: 1px solid var( --itd-border );
		border-radius: 6px;
		box-shadow: 0 12px 32px -8px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 18%, transparent );
		opacity: 0;
		visibility: hidden;
		transform: translateY( 6px );
		transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
	}

	/* Keeps the pointer inside the item while it crosses the gap above the panel. */
	.primary-menu .sub-menu::before {
		content: "";
		position: absolute;
		left: 0;
		right: 0;
		bottom: 100%;
		height: 0.75rem;
	}

	.primary-menu li:hover > .sub-menu,
	.primary-menu li:focus-within > .sub-menu {
		opacity: 1;
		visibility: visible;
		transform: translateY( 0 );
		transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0s;
	}

	/* A third level, if a site builds one, opens beside its parent. */
	.primary-menu .sub-menu .sub-menu {
		top: -0.5rem;
		left: 100%;
		margin-top: 0;
	}

	.primary-menu .sub-menu a {
		display: block;
		padding: 0.5rem 1.25rem;
		white-space: nowrap;
	}

	.primary-menu .sub-menu a::after {
		display: none;
	}

	.primary-menu .sub-menu .menu-item-has-children > a {
		padding-right: 2rem;
	}

	.primary-menu .sub-menu .menu-item-has-children > a::before {
		right: 1rem;
		transform: translateY( -50% ) rotate( -45deg );
	}

	.primary-menu .sub-menu a:hover,
	.primary-menu .sub-menu a:focus-visible {
		background-color: var( --itd-cream );
		color: var( --wp--preset--color--primary, #1c3d2e );
	}
}

@media ( min-width: 1025px ) and ( prefers-reduced-motion: reduce ) {
	.primary-menu .sub-menu,
	.primary-menu li:hover > .sub-menu,
	.primary-menu li:focus-within > .sub-menu {
		transition: none;
		transform: none;
	}
}

.site-header__cta {
	flex-shrink: 0;
	white-space: nowrap;
	justify-self: end;
	display: inline-flex;
	align-items: center;
	text-decoration: none;
	font-size: 0.9375rem;
	font-weight: 500;
	color: var( --wp--preset--color--base, #ffffff );
	background-color: var( --wp--preset--color--secondary, #c08a3e );
	border-radius: 9999px;
	padding: var( --wp--preset--spacing--20 ) var( --wp--preset--spacing--40 );
	transition: background-color 0.15s ease;
}

.site-header__cta:hover {
	background-color: var( --wp--preset--color--primary, #1c3d2e );
	color: var( --wp--preset--color--base, #ffffff );
}

.footer-menu {
	display: flex;
	flex-wrap: wrap;
	gap: var( --wp--preset--spacing--30 );
	list-style: none;
	margin: 0;
	padding: 0;
}

.footer-menu a {
	text-decoration: none;
	color: color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 75%, transparent );
	transition: color 0.15s ease;
}

.footer-menu a:hover {
	color: var( --wp--preset--color--base, #ffffff );
}

.menu-toggle {
	display: none;
	background: none;
	border: 0;
	color: inherit;
	cursor: pointer;
}

a:focus-visible,
button:focus-visible,
.menu-toggle:focus-visible {
	outline: 2px solid var( --wp--preset--color--secondary, #c08a3e );
	outline-offset: 2px;
}

/*
 * Filled content buttons (core/button, any color — theme palette or a
 * pattern's own inline custom hex) had no hover feedback at all. A
 * color-agnostic brightness bump + lift works regardless of the
 * button's own background color, so it doesn't need per-palette rules.
 */
.wp-element-button {
	transition: filter 0.15s ease, transform 0.15s ease;
}

.wp-element-button:hover {
	filter: brightness( 1.1 );
	transform: translateY( -1px );
}

/*
 * Outline buttons (is-style-outline) only had a border/text color, no
 * fill on hover. color-mix() with currentColor keeps this working for
 * any border/text color a pattern sets, without hardcoding a palette.
 */
.wp-block-button.is-style-outline .wp-element-button:hover {
	background-color: color-mix( in srgb, currentColor 12%, transparent );
	filter: none;
	transform: none;
}

/*
 * "InTouchDesign brand" (InTouchDesign light palette) card language: flat
 * 1px borders with no shadow at all read as dated/boxy. A shared,
 * navy-tinted soft shadow (not the flat gray a generic box-shadow would
 * give) plus a hover lift gives every card in this palette real depth
 * without hardcoding box-shadow per pattern file — and without risking
 * Gutenberg block-validation (a hand-written box-shadow inside a
 * block's own JSON-declared inline style fails validation unless it's a
 * theme.json shadow preset; a plain CSS class sidesteps that entirely
 * since className always round-trips through save()).
 */
.itd-card-soft {
	box-shadow: 0 1px 2px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 4%, transparent ), 0 12px 32px -8px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 12%, transparent );
	transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.itd-card-soft:hover {
	box-shadow: 0 4px 8px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 6%, transparent ), 0 20px 40px -8px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 16%, transparent );
	transform: translateY( -2px );
}

/*
 * Icon badge: a bigger, softly-lifted circle instead of a flat tinted square.
 * `width: fit-content` + auto margins is load-bearing, not decorative: this
 * badge is a Group block (`layout:{"type":"constrained"}`) whose own box
 * otherwise defaults to plain block width (100% of its parent). Inside a
 * `.itd-card-equal` card that accidentally self-corrects — the
 * card's `display:flex` turns Gutenberg's own `margin-inline:auto!important`
 * (added to every constrained-layout child) into a shrink-and-center via the
 * flexbox auto-margin rule — but a badge used directly in a plain, no-card
 * section (e.g. core-values) has neither a flex ancestor nor a
 * `.is-layout-constrained` parent, so neither shrinking nor centering ever
 * kicks in and the badge stretches into a wide, stadium-shaped pill instead
 * of a small circle. Setting size/centering explicitly here makes the badge
 * correct on its own, in any context, instead of depending on an
 * accidental ancestor side-effect.
 */
.itd-icon-badge {
	width: fit-content;
	margin-inline: auto;
	box-shadow: 0 1px 2px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 4%, transparent ), 0 8px 20px -6px color-mix( in srgb, var( --wp--preset--color--secondary, #c08a3e ) 25%, transparent );
}

/*
 * Forces a wide/landscape crop on a photo regardless of the source
 * file's own orientation — a plain CSS class + object-fit, no dependency
 * on which image happens to be referenced.
 */
.itd-media-landscape img {
	aspect-ratio: 4 / 3;
	width: 100%;
	height: auto;
	object-fit: cover;
	display: block;
}

/*
 * Equal-height grid cards: `.wp-block-column` already stretches to match
 * its tallest row-sibling (core's default `align-items: normal` on
 * `.wp-block-columns` computes to stretch), but the card *inside* the
 * column doesn't automatically fill that stretched height on its own —
 * without this it stays exactly as tall as its own content, so a card
 * with a two-line description sits shorter than one with a three-line
 * description even though their columns are already the same height.
 */
.wp-block-column > .itd-card-equal {
	height: 100%;
	display: flex;
	flex-direction: column;
}

/*
 * Opt-in modifier, services-grid only: pins the card's last paragraph
 * (the "Learn More" link) to the same baseline across every card in the
 * row regardless of how much description text sits above it. NOT paired
 * with `.itd-card-equal` everywhere — a testimonial card's last
 * paragraph is the quote itself, and pushing that to the bottom would
 * leave an ugly gap above it instead of below.
 */
.itd-card-cta-bottom > p:last-child {
	margin-top: auto;
	padding-top: var( --wp--preset--spacing--20 );
}

@media ( prefers-reduced-motion: reduce ) {
	.itd-card-soft,
	.itd-card-soft:hover {
		transition: none;
		transform: none;
	}
}

/*
 * Scroll-reveal: fade + rise on first entry into the viewport, toggled by
 * an IntersectionObserver in main.js (unobserves after the first reveal,
 * so it never re-hides content on scroll-up — a one-way reveal, not a
 * repeating scrub). Never applied to above-the-fold content (hero,
 * contact strip): hiding the first thing a visitor sees behind a JS
 * dependency is a CLS/FOUC risk for no benefit.
 */
.itd-reveal {
	opacity: 0;
	transform: translateY( 16px );
	transition: opacity 0.5s ease, transform 0.5s ease;
}

.itd-reveal.is-visible {
	opacity: 1;
	transform: translateY( 0 );
}

/* Stagger cards within a row instead of popping in together. */
.wp-block-columns > .wp-block-column:nth-child( 2 ) .itd-reveal {
	transition-delay: 0.08s;
}

.wp-block-columns > .wp-block-column:nth-child( 3 ) .itd-reveal {
	transition-delay: 0.16s;
}

.wp-block-columns > .wp-block-column:nth-child( 4 ) .itd-reveal {
	transition-delay: 0.24s;
}

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

/*
 * Service icon "draw-in": each stroked shape carries `pathLength="1"` in its
 * markup, which normalizes stroke-dasharray/-dashoffset to 0-1 regardless of
 * the path's actual geometry — no per-icon length math needed. Starts fully
 * undrawn and animates to fully drawn together with the parent card's own
 * fade+rise (`.itd-reveal.is-visible`, toggled once by the same
 * IntersectionObserver in main.js), so no extra JS or observer is needed
 * here. A small hover pulse on the badge is independent of the reveal state.
 */
.itd-icon-animate path,
.itd-icon-animate circle,
.itd-icon-animate rect {
	stroke-dasharray: 1;
	stroke-dashoffset: 1;
	transition: stroke-dashoffset 0.9s ease 0.2s;
}

.itd-reveal.is-visible .itd-icon-animate path,
.itd-reveal.is-visible .itd-icon-animate circle,
.itd-reveal.is-visible .itd-icon-animate rect {
	stroke-dashoffset: 0;
}

.itd-icon-badge {
	transition: transform 0.2s ease;
}

.itd-card-soft:hover .itd-icon-badge {
	transform: scale( 1.08 ) rotate( -4deg );
}

@media ( prefers-reduced-motion: reduce ) {
	.itd-icon-animate path,
	.itd-icon-animate circle,
	.itd-icon-animate rect {
		stroke-dasharray: none;
		stroke-dashoffset: 0;
		transition: none;
	}

	.itd-icon-badge,
	.itd-card-soft:hover .itd-icon-badge {
		transition: none;
		transform: none;
	}
}

/*
 * Keyword divider marquee. The editable content is the ONE real
 * `.itd-marquee__list` (a normal wp:list — add/remove/edit
 * keywords like any list, no need to type the same word repeatedly to
 * "fill" the band). main.js measures it and clones it at runtime into a
 * `__track` of `__run`s wide enough to fill the screen and loop
 * seamlessly — see the JS comment for the exact technique. This file
 * only supplies: the full-bleed band itself (`.itd-marquee`,
 * the same width:100vw + negative-margin trick the theme already uses
 * for `.entry-content > .alignfull`, needed because it sits inside a
 * "constrained" pattern group), the visual style of the list-turned-row,
 * and the reduced-motion / no-JS fallback (the real list alone, static,
 * wrapped normally — still fully readable).
 */
.itd-marquee {
	overflow: hidden;
	width: 100vw;
	margin-inline: calc( 50% - 50vw );
}

.itd-marquee__list {
	display: flex;
	align-items: center;
	list-style: none;
	margin: 0;
	padding: 0;
	max-width: none;
	font-size: 1.5rem;
	font-weight: 600;
	text-transform: uppercase;
}

.itd-marquee__list li {
	display: flex;
	align-items: center;
	white-space: nowrap;
}

.itd-marquee__list li::after {
	content: "\2726";
	margin-inline: var( --wp--preset--spacing--40 );
}

/* Pre-JS/no-JS: one static, wrapping line — still fully readable. */
.itd-marquee:not( .itd-marquee--ready ) .itd-marquee__list {
	flex-wrap: wrap;
	row-gap: var( --wp--preset--spacing--20 );
}

.itd-marquee--ready .itd-marquee__list {
	flex-shrink: 0;
}

.itd-marquee__track {
	display: flex;
	width: max-content;
	max-width: none;
}

.itd-marquee--ready .itd-marquee__track {
	animation-name: itd-marquee-scroll;
	animation-timing-function: linear;
	animation-iteration-count: infinite;
	/* animation-duration is set inline by JS from the measured run width, so the scroll speed (px/s) stays constant regardless of how many keywords are in the list. */
}

.itd-marquee__run {
	display: flex;
	flex-shrink: 0;
}

.itd-marquee:hover .itd-marquee__track,
.itd-marquee:focus-within .itd-marquee__track {
	animation-play-state: paused;
}

@keyframes itd-marquee-scroll {
	from {
		transform: translateX( 0 );
	}
	to {
		transform: translateX( -50% );
	}
}

@media ( max-width: 600px ) {
	.itd-marquee__list {
		font-size: 1.125rem;
	}

	.itd-marquee__list li::after {
		margin-inline: var( --wp--preset--spacing--30 );
	}
}

/*
 * No separate prefers-reduced-motion rule needed here: main.js checks it
 * before ever building `__track`/`__run` or adding `--ready`, so a
 * reduced-motion visitor simply keeps the plain, static, wrapping
 * `__list` — the ":not(--ready)" rule above already covers that state.
 */

/*
 * Full-screen hero slider: progressive enhancement. Without JS every slide
 * renders in normal document flow, stacked full-height one after another
 * (a long but fully readable static page — never a blank or half-broken
 * hero). main.js adds `is-carousel` to the outer element as the very
 * first thing it does on init, which is what turns this into an actual
 * single-slide-at-a-time carousel; only then do the slides get stacked
 * into one grid cell and cross-faded via `is-active`. No autoplay: a
 * self-advancing carousel needs a visible pause control per WCAG 2.2.2,
 * and a visitor reads each slide at their own pace instead.
 *
 * Each slide is a full-bleed photo (`__media`) with the heading/text/CTAs
 * (`__content`) overlaid on top. The photo is decorative background at
 * that point — the meaningful alt text still lives on the underlying
 * wp:image for anyone reading with images/CSS off — so a dark scrim
 * (`::before`, pure CSS, no extra markup) sits between them to keep the
 * white overlay text readable regardless of what the photo looks like:
 * darkest on the left where the text column sits, fading out toward the
 * right so the photo still shows through.
 *
 * Autoplay advances every 6 seconds (main.js), pausing on hover
 * (`mouseenter`) and keyboard focus (`focusin`) — the WCAG 2.2.2 (Pause,
 * Stop, Hide) requirement that content moving on its own needs a way to
 * stop it, without being mouse-only. An optional `.itd-hero-slider__toggle`
 * button (below) adds an explicit pause/resume control for anyone who
 * wants one regardless of hover/focus state.
 */
.itd-hero-slider {
	position: relative;
}

.itd-hero-slider__track {
	position: relative;
}

.itd-hero-slider.is-carousel .itd-hero-slider__track {
	display: grid;
}

.itd-hero-slide {
	position: relative;
	height: calc( 100vh - var( --itd-header-h, 80px ) );
	height: calc( 100dvh - var( --itd-header-h, 80px ) );
	min-height: 480px;
	display: flex;
	align-items: center;
	overflow: hidden;
	background-color: var( --itd-primary-dark );
}

.itd-hero-slide::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: linear-gradient( 100deg, color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 82%, transparent ) 0%, color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 60%, transparent ) 38%, color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 25%, transparent ) 65%, color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 5%, transparent ) 100% );
	pointer-events: none;
}

.itd-hero-slide__media {
	position: absolute;
	inset: 0;
	z-index: 0;
	margin: 0;
}

.itd-hero-slide__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
	display: block;
}

.itd-hero-slide__content {
	position: relative;
	z-index: 2;
	max-width: 620px;
	padding-inline: clamp( 24px, 6vw, 96px );
}

/*
 * The prev/next arrows sit vertically centered at the slider's left/right
 * edges, so at desktop widths the text block has to start to the right of
 * the left arrow (edge offset + 48px button + a gap) instead of underneath
 * it, or the first letters of the subtitle end up hidden behind the button.
 * On phones there's no room beside the text at all, so the arrows drop to the
 * bottom corners next to the dots.
 */
@media ( min-width: 783px ) {
	.itd-hero-slide__content {
		padding-inline: calc( clamp( 12px, 3vw, 32px ) + 48px + 24px );
	}
}

/*
 * Entrance animation for each slide's heading/text/buttons: fade + rise,
 * staggered, replaying on every slide change (not just once on page
 * load). It works by keying the `animation` off `.is-active` on the
 * ANCESTOR slide rather than a one-shot JS-added class on the elements
 * themselves — `goTo()` in main.js toggles `.is-active` per slide on
 * every transition, so these selectors stop matching (animation removed)
 * then match again (animation restarts fresh) each time a slide becomes
 * active. Before `is-carousel` is added (JS hasn't run yet, or failed),
 * everything is plain static flow at full opacity — see the fallback
 * override below — so a broken script degrades to static content, never
 * hidden/invisible text.
 */
.itd-hero-slide__content > h1,
.itd-hero-slide__content > h2,
.itd-hero-slide__content > p,
.itd-hero-slide__content .wp-block-buttons > .wp-block-button {
	opacity: 0;
}

.itd-hero-slider:not( .is-carousel ) .itd-hero-slide__content > h1,
.itd-hero-slider:not( .is-carousel ) .itd-hero-slide__content > h2,
.itd-hero-slider:not( .is-carousel ) .itd-hero-slide__content > p,
.itd-hero-slider:not( .is-carousel ) .itd-hero-slide__content .wp-block-buttons > .wp-block-button {
	opacity: 1;
}

@keyframes itd-hero-reveal {
	from {
		opacity: 0;
		transform: translateY( 24px );
	}

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

.itd-hero-slide.is-active .itd-hero-slide__content > h1,
.itd-hero-slide.is-active .itd-hero-slide__content > h2 {
	animation: itd-hero-reveal 0.7s cubic-bezier( 0.16, 1, 0.3, 1 ) both;
}

.itd-hero-slide.is-active .itd-hero-slide__content > p {
	animation: itd-hero-reveal 0.7s cubic-bezier( 0.16, 1, 0.3, 1 ) both;
	animation-delay: 0.15s;
}

.itd-hero-slide.is-active .itd-hero-slide__content .wp-block-buttons > .wp-block-button {
	animation: itd-hero-reveal 0.7s cubic-bezier( 0.16, 1, 0.3, 1 ) both;
	animation-delay: 0.3s;
}

.itd-hero-slide.is-active .itd-hero-slide__content .wp-block-buttons > .wp-block-button:nth-child( 2 ) {
	animation-delay: 0.4s;
}

/*
 * A cross-fade: the next slide fades in on top while the current one stays
 * visible underneath until it is covered, then drops out (the delayed
 * opacity/visibility below). Hiding the outgoing slide at once, as before,
 * flashed the background between two photos.
 */
.itd-hero-slider.is-carousel .itd-hero-slide {
	grid-area: 1 / 1;
	z-index: 0;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0s linear var( --itd-hero-fade, 0.6s ), visibility 0s linear var( --itd-hero-fade, 0.6s );
	pointer-events: none;
}

.itd-hero-slider.is-carousel .itd-hero-slide.is-active {
	z-index: 1;
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transition: opacity var( --itd-hero-fade, 0.6s ) ease-in-out, visibility 0s;
}

/*
 * main.js is deferred, so the page is usually painted before it adds
 * `is-carousel`: the slides were drawn stacked, the arrows sat halfway down
 * that tall column, off screen, and the whole hero jumped into place a moment
 * later (layout shift). When the browser runs scripts it already stacks the
 * slides in one cell and shows the first, exactly as the carousel will; with
 * scripting off every slide still reads one after another, as above.
 */
@media ( scripting: enabled ) {
	.itd-hero-slider:not( .itd-hero-slider--media ):not( .is-carousel ) .itd-hero-slider__track {
		display: grid;
	}

	.itd-hero-slider:not( .itd-hero-slider--media ):not( .is-carousel ) .itd-hero-slide {
		grid-area: 1 / 1;
	}

	.itd-hero-slider:not( .itd-hero-slider--media ):not( .is-carousel ) .itd-hero-slide:not( :first-child ) {
		visibility: hidden;
	}
}

.itd-hero-slider__arrow {
	position: absolute;
	top: 50%;
	z-index: 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	border-radius: 9999px;
	border: 0;
	background-color: color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 92%, transparent );
	color: var( --wp--preset--color--primary, #1c3d2e );
	cursor: pointer;
	transform: translateY( -50% );
	box-shadow: 0 4px 16px color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 25%, transparent );
	transition: background-color 0.15s ease, transform 0.15s ease;
}

.itd-hero-slider__arrow--prev {
	left: clamp( 12px, 3vw, 32px );
}

.itd-hero-slider__arrow--next {
	right: clamp( 12px, 3vw, 32px );
}

.itd-hero-slider__arrow:hover {
	background-color: var( --wp--preset--color--base, #ffffff );
	transform: translateY( -50% ) scale( 1.08 );
}

@media ( max-width: 782px ) {
	.itd-hero-slider__arrow {
		top: auto;
		bottom: 12px;
		transform: none;
	}

	.itd-hero-slider__arrow:hover {
		transform: scale( 1.08 );
	}
}

.itd-hero-slider__dots {
	position: absolute;
	bottom: clamp( 16px, 4vh, 40px );
	left: 50%;
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 10px;
	transform: translateX( -50% );
}

.itd-hero-slider__dot {
	width: 10px;
	height: 10px;
	padding: 0;
	border: 0;
	border-radius: 9999px;
	background-color: color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 50%, transparent );
	cursor: pointer;
	transition: background-color 0.15s ease, transform 0.15s ease;
}

.itd-hero-slider__dot.is-active {
	background-color: var( --wp--preset--color--base, #ffffff );
	transform: scale( 1.3 );
}

.itd-hero-slider__arrow:focus-visible,
.itd-hero-slider__dot:focus-visible {
	outline: 2px solid var( --wp--preset--color--base, #ffffff );
	outline-offset: 2px;
}

@media ( max-width: 782px ) {
	.itd-hero-slide__content {
		max-width: none;
		/* Clears the 40px arrow + its edge offset on each side so long
		   lines never run under a button (readability > full-bleed text
		   on narrow screens). */
		padding-inline: 60px;
	}

	.itd-hero-slider__arrow {
		width: 40px;
		height: 40px;
	}
}

@media ( prefers-reduced-motion: reduce ) {
	.itd-hero-slider.is-carousel .itd-hero-slide,
	.itd-hero-slider.is-carousel .itd-hero-slide.is-active {
		transition: none;
	}

	.itd-hero-slide.is-active .itd-hero-slide__content > h1,
	.itd-hero-slide.is-active .itd-hero-slide__content > h2,
	.itd-hero-slide.is-active .itd-hero-slide__content > p,
	.itd-hero-slide.is-active .itd-hero-slide__content .wp-block-buttons > .wp-block-button {
		animation: none;
		opacity: 1;
		transform: none;
	}
}

/*
 * Image-only hero slider modifier (`--media`): three photos cross-fading
 * inside a fixed-ratio box while the heading/text stay in normal flow
 * elsewhere on the page — unlike the full-screen slider above, there's no
 * `__content` overlay and no dark scrim, so each slide is just the
 * `wp:image` figure itself (`.itd-hero-slide`). Without JS, or under
 * `prefers-reduced-motion`, only the first slide shows: the same
 * progressive-enhancement contract as the full slider, just expressed with
 * `display: none` on the extra figures instead of stacking full-height
 * blocks (there's no meaningful "read each slide at your own pace" fallback
 * for a small decorative image well). The organic mask shape (border-radius
 * or similar) is applied by whoever uses this modifier (e.g. a demo's own
 * `pro/style.css`), not here.
 */
.itd-hero-slider--media {
	position: relative;
	aspect-ratio: 7 / 6;
	height: auto;
	min-height: 0;
}

.itd-hero-slider--media {
	--itd-hero-fade: 1.2s;
}

.itd-hero-slider--media .itd-hero-slide {
	position: absolute;
	inset: 0;
	height: 100%;
	min-height: 0;
	margin: 0;
	opacity: 0;
}

.itd-hero-slider--media .itd-hero-slide img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.itd-hero-slider--media:not( .is-carousel ) .itd-hero-slide:first-child,
.itd-hero-slider--media.is-carousel .itd-hero-slide.is-active {
	opacity: 1;
}

.itd-hero-slider--media:not( .is-carousel ) .itd-hero-slide:not( :first-child ) {
	display: none;
}

/*
 * The reduced-motion rule above (`.itd-hero-slider.is-carousel .itd-hero-slide
 * { transition: none; }`) already matches these slides too — a `--media`
 * slider still carries the plain `.itd-hero-slider` class — so no separate
 * override is needed here to kill the cross-fade transition.
 */

/*
 * Optional pause/resume control (main.js): works on both the full-screen
 * slider and the `--media` modifier. Positioned bottom-right so it never
 * collides with the full slider's centered dots or its arrows (which only
 * move to the bottom corners on narrow screens, clear of this corner).
 * There's nothing to pause under `prefers-reduced-motion` (autoplay never
 * starts), so the control hides itself instead of sitting there inert.
 */
.itd-hero-slider__toggle {
	position: absolute;
	right: clamp( 12px, 3vw, 32px );
	bottom: clamp( 16px, 4vh, 40px );
	z-index: 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 0;
	border-radius: 9999px;
	background-color: color-mix( in srgb, var( --wp--preset--color--base, #ffffff ) 92%, transparent );
	color: var( --wp--preset--color--primary, #1c3d2e );
	cursor: pointer;
	transition: background-color 0.15s ease;
}

.itd-hero-slider__toggle:hover {
	background-color: var( --wp--preset--color--base, #ffffff );
}

.itd-hero-slider__toggle:focus-visible {
	outline: 2px solid var( --wp--preset--color--base, #ffffff );
	outline-offset: 2px;
}

/* Pause icon (two bars): shown while playing — clicking it pauses. The second
   bar is a shadow 7px to the right; the margin makes the box as wide as what is
   drawn, so the button centres both bars like it centres the play triangle. */
.itd-hero-slider__toggle[aria-pressed="false"]::before {
	content: "";
	width: 3px;
	height: 14px;
	margin-inline-end: 7px;
	background-color: currentColor;
	box-shadow: 7px 0 0 currentColor;
}

/* Play icon (triangle): shown while paused — clicking it resumes. */
.itd-hero-slider__toggle[aria-pressed="true"]::before {
	content: "";
	width: 0;
	height: 0;
	margin-inline-start: 2px;
	border-style: solid;
	border-width: 7px 0 7px 12px;
	border-color: transparent transparent transparent currentColor;
}

@media ( prefers-reduced-motion: reduce ) {
	.itd-hero-slider__toggle {
		display: none;
	}
}

/*
 * Static inner-page hero: a single full-bleed photo with a dark scrim and
 * centered white text — the "default brand" equivalent of the Home hero
 * slider, but for pages that need one photo and a short intro instead of
 * a multi-slide carousel. `content-page.php` checks for this class name
 * and skips the generic auto page-title when it's present, exactly like
 * the front page already skips it because its own hero introduces the
 * page — otherwise a plain black-on-white "About Us" heading would sit
 * above this hero, duplicating what the hero itself already says.
 */
.itd-page-hero {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 460px;
	overflow: hidden;
	background-color: var( --wp--preset--color--primary, #1c3d2e );
}

.itd-page-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: linear-gradient( 180deg, color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 72%, transparent ) 0%, color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 58%, transparent ) 100% );
	pointer-events: none;
}

.itd-page-hero__media {
	position: absolute;
	inset: 0;
	z-index: 0;
	margin: 0;
}

.itd-page-hero__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
	display: block;
}

.itd-page-hero__content {
	position: relative;
	z-index: 2;
	max-width: 640px;
	padding-inline: 24px;
	text-align: center;
}

@media ( max-width: 782px ) {
	.itd-page-hero {
		min-height: 340px;
	}
}

/*
 * InTouchDesign contact strip: at desktop width the icon+text group and the
 * button sit on opposite ends of the row (justify-content: space-between).
 * Once it wraps to a single narrow column, space-between leaves each row
 * pinned to the row's own start edge instead of centered — looks flush
 * against the left side. Center both rows once stacked.
 */
@media ( max-width: 782px ) {
	.itd-contact-strip.itd-contact-strip {
		justify-content: center;
		text-align: center;
	}

	.itd-contact-strip .wp-block-buttons {
		justify-content: center;
	}
}

/* Generic inline links inside page content: underline on hover. */
.entry-content a:not( .wp-element-button ):not( .itd-arrow-link ):hover {
	text-decoration: underline;
}

/*
 * Arrow-suffixed text links (e.g. "Learn More →" cards): an underline
 * would run under the arrow glyph too, so this gets its own hover
 * feedback instead — a small nudge on the arrow side.
 */
.itd-arrow-link {
	text-decoration: none;
	display: inline-block;
	transition: transform 0.15s ease;
}

.itd-arrow-link:hover {
	transform: translateX( 3px );
}

@media ( max-width: 1024px ) {
	.menu-toggle {
		display: block;
	}

	.site-header__inner {
		grid-template-columns: 1fr auto;
	}

	.primary-menu-container {
		grid-column: 1 / -1;
	}

	/*
	 * Mobile dropdown: was a hard `display:none` -> `flex` cut (display
	 * can't be transitioned, so nothing actually animated). Kept in flow
	 * at all times instead, collapsed via max-height/opacity/transform so
	 * the open/close can transition smoothly, with `visibility` delayed
	 * on close (and instant on open) so closed-but-technically-in-DOM
	 * links can't be tabbed into while invisible.
	 */
	.primary-menu {
		display: flex;
		flex-direction: column;
		width: 100%;
		max-height: 0;
		overflow: hidden;
		opacity: 0;
		visibility: hidden;
		transform: translateY( -8px );
		transition: max-height 0.35s cubic-bezier( 0.16, 1, 0.3, 1 ),
			opacity 0.25s ease,
			transform 0.3s cubic-bezier( 0.16, 1, 0.3, 1 ),
			visibility 0s linear 0.35s;
	}

	.primary-menu.is-open {
		max-height: 480px;
		opacity: 1;
		visibility: visible;
		transform: translateY( 0 );
		transition: max-height 0.35s cubic-bezier( 0.16, 1, 0.3, 1 ),
			opacity 0.25s ease,
			transform 0.3s cubic-bezier( 0.16, 1, 0.3, 1 ),
			visibility 0s linear 0s;
	}

	/* Each link fades/slides in with a small stagger once the menu is open. */
	.primary-menu li {
		opacity: 0;
		transform: translateY( -6px );
		transition: opacity 0.25s ease, transform 0.25s ease;
	}

	.primary-menu.is-open li {
		opacity: 1;
		transform: translateY( 0 );
	}

	.primary-menu.is-open li:nth-child( 1 ) {
		transition-delay: 0.05s;
	}

	.primary-menu.is-open li:nth-child( 2 ) {
		transition-delay: 0.1s;
	}

	.primary-menu.is-open li:nth-child( 3 ) {
		transition-delay: 0.15s;
	}

	.primary-menu.is-open li:nth-child( 4 ) {
		transition-delay: 0.2s;
	}

	.primary-menu.is-open li:nth-child( 5 ) {
		transition-delay: 0.25s;
	}

	.primary-menu.is-open li:nth-child( 6 ) {
		transition-delay: 0.3s;
	}

	.primary-menu.is-open li:nth-child( n + 7 ) {
		transition-delay: 0.35s;
	}

	/*
	 * A menu with sub-menus can be taller than the 480px above: let the open
	 * menu grow to most of the screen, and scroll inside it past that.
	 */
	.primary-menu.is-open:has( .sub-menu ) {
		max-height: 80vh;
		overflow-y: auto;
	}

	/* The parent is as wide as its longest child: center its own label too. */
	.primary-menu .menu-item-has-children {
		display: flex;
		flex-direction: column;
		align-items: center;
	}

	/* With the script, the label and its toggle share a row and the
	   sub-menu waits closed below them until the toggle is pressed. */
	.primary-menu .menu-item-has-children:has( > .sub-menu-toggle:not( [hidden] ) ) {
		flex-direction: row;
		flex-wrap: wrap;
		justify-content: center;
	}

	.primary-menu .sub-menu-toggle:not( [hidden] ) {
		display: inline-grid;
		place-items: center;
		width: 2.75rem;
		height: 2.75rem;
		margin: -0.75rem -0.75rem -0.75rem 0;
		padding: 0;
		border: 0;
		background: none;
		color: inherit;
		cursor: pointer;
	}

	.primary-menu .sub-menu-toggle::before {
		content: "";
		width: 0.4375rem;
		height: 0.4375rem;
		border-right: 1.5px solid currentColor;
		border-bottom: 1.5px solid currentColor;
		transform: translateY( -25% ) rotate( 45deg );
		transition: transform 0.2s ease;
	}

	.primary-menu .is-sub-open > .sub-menu-toggle::before {
		transform: translateY( 25% ) rotate( -135deg );
	}

	.primary-menu .sub-menu-toggle:focus-visible {
		outline: 2px solid currentColor;
		outline-offset: -4px;
	}

	.primary-menu .sub-menu-toggle:not( [hidden] ) ~ .sub-menu {
		flex-basis: 100%;
	}

	.primary-menu .menu-item-has-children:not( .is-sub-open ) > .sub-menu-toggle:not( [hidden] ) ~ .sub-menu {
		display: none;
	}

	.primary-menu .sub-menu {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: var( --wp--preset--spacing--20, 0.5rem );
		margin-top: var( --wp--preset--spacing--20, 0.5rem );
	}

	.primary-menu .sub-menu a {
		font-size: 0.875rem;
	}

	.site-header__cta {
		display: none;
	}
}

@media ( max-width: 1024px ) and ( prefers-reduced-motion: reduce ) {
	.primary-menu,
	.primary-menu.is-open,
	.primary-menu li,
	.primary-menu.is-open li {
		transition: none;
		transform: none;
	}
}

/*
 * Contact Form 7 (default brand). CF7 ships no visual styling of its
 * own beyond bare browser-default form chrome, and its labels have no
 * explicit color — they were inheriting this site's global text color
 * (white, meant for the dark legacy palette) while sitting in the
 * InTouchDesign template's white-background sections, rendering
 * completely invisible. Every rule below is scoped to `.wpcf7-form` and
 * hardcodes the itd-brand pine/brass/muted tokens directly (the
 * same hex values the InTouchDesign patterns already use inline) since
 * a CF7 form only ever appears on that light-palette template.
 */
.wpcf7-form p {
	margin: 0 0 var( --wp--preset--spacing--30 );
}

.wpcf7-form label {
	display: block;
	color: var( --wp--preset--color--primary, #1c3d2e );
	font-weight: 600;
	font-size: 0.9375rem;
	margin-bottom: var( --wp--preset--spacing--10 );
}

.wpcf7-form .wpcf7-form-control-wrap {
	display: block;
}

.wpcf7-form input.wpcf7-form-control,
.wpcf7-form textarea.wpcf7-form-control {
	display: block;
	width: 100%;
	box-sizing: border-box;
	font-family: inherit;
	font-size: 1rem;
	color: var( --wp--preset--color--primary, #1c3d2e );
	background-color: var( --wp--preset--color--base, #ffffff );
	border: 1px solid var( --itd-border );
	border-radius: 12px;
	padding: 12px 16px;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.wpcf7-form textarea.wpcf7-form-control {
	min-height: 140px;
	resize: vertical;
}

.wpcf7-form input.wpcf7-form-control:focus,
.wpcf7-form textarea.wpcf7-form-control:focus {
	outline: none;
	border-color: var( --wp--preset--color--secondary, #c08a3e );
	box-shadow: 0 0 0 3px color-mix( in srgb, var( --wp--preset--color--secondary, #c08a3e ) 15%, transparent );
}

.wpcf7-form input.wpcf7-form-control.wpcf7-not-valid {
	border-color: #c0392b;
}

.wpcf7-form .wpcf7-not-valid-tip {
	display: block;
	color: #c0392b;
	font-size: 0.8125rem;
	margin-top: var( --wp--preset--spacing--10 );
}

.wpcf7-form input.wpcf7-submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: auto;
	color: var( --wp--preset--color--base, #ffffff );
	background-color: var( --wp--preset--color--secondary, #c08a3e );
	border: 0;
	border-radius: 9999px;
	padding: var( --wp--preset--spacing--20 ) var( --wp--preset--spacing--50 );
	font-family: inherit;
	font-size: 1rem;
	font-weight: 600;
	cursor: pointer;
	transition: filter 0.15s ease, transform 0.15s ease;
}

.wpcf7-form input.wpcf7-submit:hover {
	filter: brightness( 1.1 );
	transform: translateY( -1px );
}

.wpcf7-form input.wpcf7-submit:focus-visible {
	outline: 2px solid var( --wp--preset--color--secondary, #c08a3e );
	outline-offset: 2px;
}

.wpcf7-spinner {
	margin-left: var( --wp--preset--spacing--20 );
}

.wpcf7-form .wpcf7-response-output {
	margin: var( --wp--preset--spacing--30 ) 0 0;
	padding: 14px 18px;
	border-radius: 12px;
	border: 1px solid var( --itd-border );
	color: var( --wp--preset--color--primary, #1c3d2e );
	font-size: 0.9375rem;
}

.wpcf7-form.sent .wpcf7-response-output {
	border-color: #bfe3cc;
	background-color: #eefbf2;
	color: #1f7a4d;
}

.wpcf7-form.failed .wpcf7-response-output,
.wpcf7-form.aborted .wpcf7-response-output,
.wpcf7-form.spam .wpcf7-response-output {
	border-color: #f3c6c0;
	background-color: #fdf0ee;
	color: #c0392b;
}

@media ( prefers-reduced-motion: reduce ) {
	.wpcf7-form input.wpcf7-submit {
		transition: none;
		transform: none;
	}
}

/*
 * Blog listing (card grid) and single article, itd-brand.
 * `.content-area` (index/archive/search/single/page) had no color of its
 * own, so it fell back to the theme.json body default — dark legacy
 * background with white text — same "still-legacy" gap as the header/
 * footer had. Every other template already covers the full viewport with
 * its own explicitly-colored patterns, which is why this never showed
 * up anywhere except here, on the one set of templates that render raw
 * `the_content()`/`the_excerpt()` with no pattern wrapper.
 */
/*
 * On `.site-content` (the flexed <main>), not just the shrink-wrapped
 * `.content-area` inside it: `.site-content{flex:1 0 auto}` stretches
 * <main> to push the footer down, so on any short page (Sample Page,
 * Privacy Policy) `.content-area` alone left a visible gap of bare body
 * (dark legacy) between it and the footer, and another sliver between
 * the header and `.content-area`'s own top margin.
 */
.site-content {
	background-color: var( --wp--preset--color--base, #ffffff );
	color: var( --wp--preset--color--contrast, #252b26 );
}

.page-header,
.archive-description {
	text-align: center;
	max-width: var( --wp--style--global--content-size, 720px );
}

.page-header {
	padding-block: var( --wp--preset--spacing--60 ) var( --wp--preset--spacing--40 );
}

.page-title {
	color: var( --wp--preset--color--primary, #1c3d2e );
	font-size: clamp( 1.75rem, 1.75rem + 1vw, 2.5rem );
}

.archive-description {
	color: var( --wp--preset--color--muted, #5a6259 );
}

/* Card grid: blog index, plus category/tag/date archives and search results. */
.itd-blog-grid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: var( --wp--preset--spacing--50 );
	max-width: var( --wp--style--global--wide-size, 1300px );
	margin-inline: auto;
	padding-inline: var( --wp--preset--spacing--30 );
	padding-block: var( --wp--preset--spacing--50 ) var( --wp--preset--spacing--70 );
}

@media ( max-width: 1024px ) {
	.itd-blog-grid {
		grid-template-columns: repeat( 2, 1fr );
	}
}

@media ( max-width: 700px ) {
	.itd-blog-grid {
		grid-template-columns: 1fr;
	}
}

.itd-blog-card {
	display: flex;
	flex-direction: column;
	border-radius: 20px;
	overflow: hidden;
	background-color: var( --wp--preset--color--base, #ffffff );
}

.itd-blog-card__thumbnail {
	display: block;
	height: 220px;
	overflow: hidden;
	background-color: var( --itd-border );
}

.itd-blog-card__thumbnail img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.itd-blog-card__body {
	display: flex;
	flex-direction: column;
	flex: 1;
	gap: var( --wp--preset--spacing--10 );
	padding: var( --wp--preset--spacing--30 );
}

.itd-blog-card .entry-meta {
	color: var( --wp--preset--color--secondary, #c08a3e );
	font-size: 0.8125rem;
}

.itd-blog-card .entry-title {
	margin: 0;
	font-size: 1.125rem;
}

.itd-blog-card .entry-title a {
	color: var( --wp--preset--color--primary, #1c3d2e );
	text-decoration: none;
}

.itd-blog-card .entry-title a:hover {
	color: var( --wp--preset--color--secondary, #c08a3e );
}

.itd-blog-card .entry-summary {
	flex: 1;
	color: var( --wp--preset--color--muted, #5a6259 );
	font-size: 0.9375rem;
}

.itd-blog-card .entry-summary p {
	margin: 0;
}

.itd-blog-card__readmore {
	width: fit-content;
	margin-top: auto;
	color: var( --wp--preset--color--secondary, #c08a3e );
	font-weight: 600;
	font-size: 0.875rem;
	text-decoration: none;
	transition: transform 0.15s ease;
}

.itd-blog-card__readmore:hover {
	transform: translateX( 3px );
}

/* A post's categories as labels: above a blog card's title, and in the
   opening of an article with its date and author under the title. */
.itd-post-cats {
	display: flex;
	flex-wrap: wrap;
	gap: var( --wp--preset--spacing--20 );
}

.itd-post-cats a {
	color: var( --wp--preset--color--secondary, #c08a3e );
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	text-decoration: none;
}

.itd-post-cats a:hover {
	text-decoration: underline;
}

.itd-article .itd-post-cats {
	margin-bottom: var( --wp--preset--spacing--20 );
}

.itd-article .itd-page-hero .itd-post-cats,
.itd-article .itd-page-hero .entry-meta {
	justify-content: center;
}

.itd-article .itd-page-hero .itd-post-cats a,
.itd-article .itd-page-hero .entry-meta,
.itd-article .itd-page-hero .entry-meta a {
	color: var( --wp--preset--color--base, #ffffff );
}

.itd-article .itd-page-hero .entry-meta,
.itd-article > .entry-header .entry-meta {
	margin-top: var( --wp--preset--spacing--20 );
}

/* Single article: photo-hero header (reuses .itd-page-hero) + readable body. */
.itd-article .itd-page-hero {
	min-height: 380px;
}

.itd-article .itd-page-hero .entry-title {
	max-width: 720px;
	color: var( --wp--preset--color--base, #ffffff );
	font-size: clamp( 1.75rem, 1.75rem + ( ( 1vw - 0.2rem ) * 2 ), 2.75rem );
}

.itd-article > .entry-header .entry-title {
	color: var( --wp--preset--color--primary, #1c3d2e );
	font-size: clamp( 1.75rem, 1.75rem + 1vw, 2.5rem );
}

.itd-article__body {
	padding-block: var( --wp--preset--spacing--50 ) var( --wp--preset--spacing--70 );
}

.itd-article .entry-meta {
	margin: 0;
	color: var( --wp--preset--color--muted, #5a6259 );
	font-size: 0.875rem;
}

.itd-article .entry-meta .posted-on::after {
	content: "\2022";
	margin-inline: var( --wp--preset--spacing--20 );
}

.itd-article .entry-meta a {
	color: var( --wp--preset--color--muted, #5a6259 );
}

.itd-article .entry-meta a:hover {
	color: var( --wp--preset--color--secondary, #c08a3e );
}

.itd-article .entry-footer {
	flex-direction: column;
	align-items: flex-start;
	gap: var( --wp--preset--spacing--10 );
	margin-top: var( --wp--preset--spacing--50 );
	padding-top: var( --wp--preset--spacing--30 );
	border-top: 1px solid color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 10%, transparent );
	color: var( --wp--preset--color--muted, #5a6259 );
	font-size: 0.875rem;
}

.itd-article .entry-footer a {
	color: var( --wp--preset--color--secondary, #c08a3e );
}

/* Search form (404 page, no-results): bare WP core markup, unstyled. */
.search-form {
	display: flex;
	flex-wrap: wrap;
	gap: var( --wp--preset--spacing--20 );
	max-width: 420px;
	margin-top: var( --wp--preset--spacing--30 );
}

.search-form label {
	flex: 1;
	min-width: 200px;
}

.search-form .search-field {
	width: 100%;
	box-sizing: border-box;
	font-family: inherit;
	font-size: 1rem;
	color: var( --wp--preset--color--primary, #1c3d2e );
	background-color: var( --wp--preset--color--base, #ffffff );
	border: 1px solid var( --itd-border );
	border-radius: 12px;
	padding: 12px 16px;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.search-form .search-field:focus {
	outline: none;
	border-color: var( --wp--preset--color--secondary, #c08a3e );
	box-shadow: 0 0 0 3px color-mix( in srgb, var( --wp--preset--color--secondary, #c08a3e ) 15%, transparent );
}

.search-form .search-submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	color: var( --wp--preset--color--base, #ffffff );
	background-color: var( --wp--preset--color--secondary, #c08a3e );
	border: 0;
	border-radius: 9999px;
	padding: var( --wp--preset--spacing--20 ) var( --wp--preset--spacing--40 );
	font-family: inherit;
	font-size: 1rem;
	font-weight: 600;
	cursor: pointer;
	transition: filter 0.15s ease, transform 0.15s ease;
}

.search-form .search-submit:hover {
	filter: brightness( 1.1 );
	transform: translateY( -1px );
}

/* Comments: bare WP core markup had no styling at all anywhere in the theme. */
.comments-area {
	padding-block: var( --wp--preset--spacing--50 ) var( --wp--preset--spacing--70 );
}

.comments-title {
	color: var( --wp--preset--color--primary, #1c3d2e );
	font-size: 1.375rem;
}

.comment-list {
	list-style: none;
	margin: var( --wp--preset--spacing--40 ) 0 0;
	padding: 0;
}

.comment-list .children {
	list-style: none;
	margin: 0;
	padding-left: var( --wp--preset--spacing--50 );
}

.comment-body {
	padding-block: var( --wp--preset--spacing--30 );
	border-bottom: 1px solid color-mix( in srgb, var( --wp--preset--color--primary, #1c3d2e ) 10%, transparent );
}

.comment-author {
	display: flex;
	align-items: center;
	gap: var( --wp--preset--spacing--20 );
}

.comment-author .avatar {
	border-radius: 9999px;
}

.comment-author .fn {
	font-style: normal;
	font-weight: 600;
	color: var( --wp--preset--color--primary, #1c3d2e );
}

.comment-metadata {
	margin-bottom: var( --wp--preset--spacing--10 );
}

.comment-metadata a {
	color: var( --wp--preset--color--muted, #5a6259 );
	font-size: 0.8125rem;
	text-decoration: none;
}

.comment-content p {
	color: var( --wp--preset--color--muted, #5a6259 );
	margin-block: var( --wp--preset--spacing--10 ) 0;
}

.comment-reply-link {
	color: var( --wp--preset--color--secondary, #c08a3e );
	font-size: 0.8125rem;
	font-weight: 600;
	text-decoration: none;
}

.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form input[type="url"],
.comment-form textarea {
	display: block;
	width: 100%;
	box-sizing: border-box;
	font-family: inherit;
	font-size: 1rem;
	color: var( --wp--preset--color--primary, #1c3d2e );
	background-color: var( --wp--preset--color--base, #ffffff );
	border: 1px solid var( --itd-border );
	border-radius: 12px;
	padding: 12px 16px;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.comment-form textarea {
	min-height: 140px;
	resize: vertical;
}

.comment-form input[type="text"]:focus,
.comment-form input[type="email"]:focus,
.comment-form input[type="url"]:focus,
.comment-form textarea:focus {
	outline: none;
	border-color: var( --wp--preset--color--secondary, #c08a3e );
	box-shadow: 0 0 0 3px color-mix( in srgb, var( --wp--preset--color--secondary, #c08a3e ) 15%, transparent );
}

.comment-form-comment,
.comment-form-author,
.comment-form-email,
.comment-form-url {
	margin-bottom: var( --wp--preset--spacing--20 );
}

.comment-form .form-submit input[type="submit"] {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: var( --wp--preset--color--base, #ffffff );
	background-color: var( --wp--preset--color--secondary, #c08a3e );
	border: 0;
	border-radius: 9999px;
	padding: var( --wp--preset--spacing--20 ) var( --wp--preset--spacing--50 );
	font-family: inherit;
	font-size: 1rem;
	font-weight: 600;
	cursor: pointer;
	transition: filter 0.15s ease, transform 0.15s ease;
}

.comment-form .form-submit input[type="submit"]:hover {
	filter: brightness( 1.1 );
	transform: translateY( -1px );
}

/*
 * Pagination (blog index/archive/search): `.navigation.pagination` only had
 * max-width/padding (see the `.content-area > .navigation` rule above) — the
 * `.page-numbers` links/spans themselves had zero styling, so they rendered
 * as bare inline text with no gap between them ("1234" running together).
 */
.pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var( --wp--preset--spacing--20 );
}

.page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.5em;
	height: 2.5em;
	padding-inline: var( --wp--preset--spacing--20 );
	border-radius: 9999px;
	color: var( --wp--preset--color--primary, #1c3d2e );
	background-color: var( --wp--preset--color--base, #ffffff );
	border: 1px solid var( --itd-border );
	font-size: 0.9375rem;
	font-weight: 600;
	text-decoration: none;
	transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}

a.page-numbers:hover {
	border-color: var( --wp--preset--color--secondary, #c08a3e );
	color: var( --wp--preset--color--secondary, #c08a3e );
	transform: translateY( -1px );
}

.page-numbers.current {
	background-color: var( --wp--preset--color--secondary, #c08a3e );
	border-color: var( --wp--preset--color--secondary, #c08a3e );
	color: var( --wp--preset--color--base, #ffffff );
}

.page-numbers.dots {
	border-color: transparent;
	background-color: transparent;
	color: var( --wp--preset--color--muted, #5a6259 );
}

/*
 * Core-generated classes every theme is expected to style: sticky posts,
 * post-author comments, classic-editor alignment/captions, gallery captions
 * and the paginated-post links from wp_link_pages().
 */
.sticky .entry-title::before {
	content: "\2605\00a0";
	color: var( --wp--preset--color--secondary, #c08a3e );
}

.bypostauthor > .comment-body {
	border-inline-start: 3px solid var( --wp--preset--color--secondary, #c08a3e );
	padding-inline-start: var( --wp--preset--spacing--30 );
}

.aligncenter {
	display: block;
	margin-inline: auto;
}

.wp-caption {
	max-width: 100%;
	margin-block-end: var( --wp--preset--spacing--30 );
}

.wp-caption img {
	display: block;
	max-width: 100%;
	height: auto;
}

.wp-caption-text,
.gallery-caption {
	margin-block-start: var( --wp--preset--spacing--20 );
	font-size: var( --wp--preset--font-size--small );
	color: var( --wp--preset--color--muted, #5a6259 );
}

.page-links {
	display: flex;
	flex-wrap: wrap;
	gap: var( --wp--preset--spacing--20 );
	align-items: center;
	margin-block: var( --wp--preset--spacing--40 );
}

.page-links > a,
.page-links > .post-page-numbers {
	padding: var( --wp--preset--spacing--20 ) var( --wp--preset--spacing--30 );
	border-radius: 9999px;
	text-decoration: none;
	border: 1px solid var( --itd-border );
}
