/**
 * ZTAT component styles.
 *
 * Design tokens live in theme.json and arrive as --wp--preset--* custom
 * properties. This file only styles things theme.json cannot express.
 *
 * TWO DELIBERATE LCP DECISIONS, do not "fix" these without measuring:
 *
 *   1. The hero <h1> is NEVER opacity-animated. Chrome records LCP when the
 *      element first paints with non-zero opacity, so fading in the largest
 *      text on the page directly delays LCP by the animation duration.
 *      The eyebrow, lede and buttons animate instead, which reads as motion
 *      without costing the metric.
 *
 *   2. .ztat-reveal has NO hidden state in CSS. Elements are visible by
 *      default and motion.js only hides the ones currently below the fold
 *      before animating them in. That means a JS failure, a slow network or
 *      a blocked script leaves a complete, readable page, and there is no
 *      flash-of-visible-then-hidden content on load.
 */

/* ------------------------------------------------------------- easing */

/*
 * These MUST live here, not in theme.json's `styles.css`.
 *
 * theme.json emitted them as bare declarations with no selector, so the
 * browser saw `}--ztat-ease: cubic-bezier(...)` and discarded the lot. The
 * properties were therefore never defined, and every rule referencing them
 * was invalid at computed-value time: an unresolved var() invalidates the
 * whole declaration. That silently killed the logo draw animation, the hero
 * entrance, the scroll-reveal easing and every hover transition in the
 * theme, all of which failed open and simply looked instant.
 *
 * Defining them at :root here is unambiguous and under our control.
 */
:root {
	--ztat-ease: cubic-bezier(0.22, 1, 0.36, 1);
	--ztat-ease-out: cubic-bezier(0.16, 1, 0.3, 1);

	/*
	 * BRAND GRADIENT, AND THE RULE THAT GOVERNS IT.
	 *
	 * The palette is warm copper on a warm near-black. It runs in TWO TIERS,
	 * because a copper light enough to be interesting is never dark enough to
	 * carry text on a light background. Measured against base #faf7f4 and
	 * ink #14100d (WCAG 2.1, sRGB):
	 *
	 *   copper-lift #c4703a on ink ..... 5.16:1   fine
	 *   copper-lift #c4703a on base .... 3.44:1   graphic only, FAILS text
	 *   amber #e8944f on ink ........... 7.91:1   fine
	 *   amber #e8944f on base .......... 2.24:1   fails even the 3:1 floor
	 *   white text on #c4703a .......... 3.67:1   FAILS — never a button
	 *
	 * So --ztat-gradient is for dark bands and decoration only. Anything
	 * carrying information on a light background uses solid accent #a55726
	 * (4.93:1) instead.
	 *
	 * --ztat-gradient-btn is the light-surface tier and both its stops are
	 * verified against white text: #a55726 is 5.26:1 and #7d3f19 is 8.09:1,
	 * so the sweep never dips below AA anywhere along its length.
	 *
	 * Do not put white text on --ztat-gradient.
	 *
	 * Teal is retired. #1bc7c7 measured 1.96:1 on the warm base — worse than
	 * it was on white — and it fights copper. The slug is gone from
	 * theme.json; to bring it back, re-add it there and repoint the footer
	 * logo hover below.
	 */
	--ztat-gradient: linear-gradient(120deg, #c4703a 0%, #e8944f 55%, #f5b06b 100%);
	--ztat-gradient-btn: linear-gradient(120deg, #a55726 0%, #7d3f19 100%);

	/*
	 * Gradient used as TEXT on the dark bands. Starts at amber rather than
	 * copper-lift because #c4703a measures 5.16:1 on #14100d — it clears AA,
	 * but the leftmost characters would be the hardest to read of the whole
	 * run. Starting at amber puts the floor at 7.91:1 and the far end at
	 * 10.19:1.
	 */
	--ztat-gradient-text: linear-gradient(120deg, #e8944f 0%, #f5b06b 100%);

	/*
	 * SPACING SCALE — redeclared here because theme.json's does not ship.
	 *
	 * Same class of failure as the easing variables above, and worth reading
	 * that comment first.
	 *
	 * theme.json declares spacingSizes 10-70. WordPress resolves them
	 * correctly under the `theme` origin — but core's `default` origin carries
	 * its own generated slugs 20-80, and default WINS the merge on every
	 * colliding slug. Verified with WP_Theme_JSON_Resolver on production: the
	 * theme origin resolves 60 = clamp(4.5rem, 8vw, 7rem) while the emitted
	 * CSS variable was 2.25rem. Slug 10 is the only one that does not collide,
	 * and it was the only declared value ever reaching the page.
	 *
	 * Net effect before this block: every section on the site rendered at
	 * roughly a third of its designed padding.
	 *
	 * `spacingScale: { steps: 0 }` in theme.json does not fix it — that only
	 * stops THIS theme adding a generated scale of its own. Nor can the slugs
	 * simply be renamed without touching 133 usages.
	 *
	 * main.css loads after the global stylesheet, so a plain :root redeclare
	 * wins on source order at equal specificity. Keep these in sync with
	 * theme.json, which remains the record of intent.
	 */
	--wp--preset--spacing--20: 1rem;
	--wp--preset--spacing--30: 1.5rem;
	--wp--preset--spacing--40: 2.5rem;
	--wp--preset--spacing--50: clamp(3rem, 5vw, 4.5rem);
	--wp--preset--spacing--60: clamp(4.5rem, 8vw, 7rem);
	--wp--preset--spacing--70: clamp(6rem, 11vw, 10rem);

	/* Radius scale. Square corners are the exception, not the default. */
	--ztat-r-sm: 8px;
	--ztat-r-md: 14px;
	--ztat-r-lg: 20px;
	--ztat-r-pill: 999px;
}

/* ------------------------------------------------------- section seams */

/*
 * Core puts `margin-block-start: 1.5rem` on every top-level block, via
 * `:root :where(.wp-site-blocks) > *` and `:where(.is-layout-*) > *`. Between
 * two sections of the SAME colour that gap is a 24px stripe of the page
 * background cutting straight through them.
 *
 * Measured before this rule, at x=6:
 *   /about/   dark ends 1704, WHITE 1705-1728, dark resumes 1729
 *   /41fork/  dark ends  719, WHITE  720- 743, dark resumes  744
 *   home      surface ends 2795, WHITE 2796-2819, surface resumes 2820
 *
 * Both bands either side of those stripes are the identical colour. The gap
 * was never a design choice, and it is the hardest edge on the site.
 *
 * Sections carry their own padding (spacing 60/70), so removing the margin
 * closes the stripe without letting content collide.
 *
 * Specificity: core's selectors are (0,1,0) because the `:where()` contributes
 * nothing. These are (0,2,0) and win without !important. `:is()` takes the
 * specificity of its most specific argument, so the section list stays (0,1,0)
 * and `.ztat-main` supplies the second class — which also makes it work on
 * page.html / page-wide.html, where sections are nested inside post-content
 * rather than being direct children of main.
 */
/*
 * Target the template-part WRAPPER, not `.ztat-footer`.
 *
 * WordPress wraps every template part in its own element, so the tree is
 *   .wp-site-blocks > footer.wp-block-template-part > footer.ztat-footer
 * and the 24px margin sits on the OUTER one. A first attempt at
 * `.wp-site-blocks > .ztat-footer` matched nothing at all and shipped without
 * changing anything — the inner element already computes margin-block-start: 0.
 */
.wp-site-blocks > footer.wp-block-template-part { margin-block-start: 0; }

.ztat-main :is(
	.ztat-hero, .ztat-proof, .ztat-flow-section, .ztat-services,
	.ztat-process, .ztat-voices, .ztat-founder, .ztat-faq, .ztat-packages
) { margin-block-start: 0; }

/*
 * .ztat-cta-band is deliberately NOT in that list. It carries an inline
 * margin-top of spacing|70, and that runway is where the fade ramp into the
 * dark band lives.
 */

/* --------------------------------------------------------- the page field */

/*
 * ONE gradient for the whole page, instead of per-section fills.
 *
 * Chaining gradients section-to-section would mean every section has to know
 * what colour its neighbours end on, and any reorder or conditional section
 * (a pattern that returns early when it has nothing to show) breaks the chain
 * and reintroduces a visible edge. A single field on the wrapper cannot have
 * a seam, because there is only one paint.
 *
 * <main class="ztat-main"> exists in all 13 templates, so this is the one
 * reliable hook. .has-global-padding only insets content — the element itself
 * is full viewport width, so the field spans edge to edge.
 *
 * `z-index: 0` IS LOAD-BEARING, do not drop it as redundant. Without it
 * `.ztat-main` forms no stacking context, `::before { z-index: -1 }` escapes to
 * the root one, and paints BEHIND body's opaque background colour. The field
 * then renders perfectly and is completely invisible, which looks exactly like
 * the gradient failing to load.
 *
 * Do NOT add overflow/transform/filter/will-change/contain here. Each makes
 * .ztat-main a containing block for fixed descendants and adds a compositing
 * layer the size of a 5000px+ page, and `overflow` would silently break the
 * sticky positioning theme.json enables.
 */
.ztat-main {
	position: relative;
	z-index: 0;
}

.ztat-main::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	/*
	 * Stops stay inside base..surface. That is only a ~4% luminance step, and
	 * several components (step numbers, quote cards, logo tiles) rely on
	 * reading against it. Going darker than surface anywhere would swallow
	 * them. Long stop distances are the point: at 5000px+ no transition is
	 * ever perceptible as an edge.
	 */
	background: linear-gradient(
		180deg,
		#faf7f4 0%,
		#f6f1ea 18%,
		#faf7f4 36%,
		#f4efe7 58%,
		#faf7f4 78%,
		#f6f1ea 100%
	);
}

/*
 * THE CURRENT — the one decorative element on the page.
 *
 * The site's whole argument is that data should flow between systems instead
 * of being retyped. A single line running the length of the page, crossing
 * every section boundary without stopping, is that argument as a graphic. It
 * is also the only ornament here; everything else stays quiet.
 *
 * TILED, not one stretched SVG. Page aspect ratios across this site swing 37x
 * (/calendar/ desktop 0.63, homepage mobile 23.2). Under
 * preserveAspectRatio="none" a single full-height SVG renders a 45-degree
 * stroke at 75 degrees on the homepage, and its horizontal segments paint
 * 3.79x thicker than its vertical ones — unmistakable as a rendering fault.
 * `background-size: 100% <fixed>px` pins the vertical scale so the tile is
 * identical on every page and only the horizontal meander narrows on mobile,
 * which is the behaviour we want anyway.
 *
 * The path starts and ends at x=50 with a matching vertical tangent, so the
 * repeat is mathematically continuous — one unbroken line, not a visible
 * pattern. At a 900px viewport against a 1600px tile you never see two
 * periods at once.
 *
 * TWO SILENT-FAILURE TRAPS, both of which render "no line at all" with no
 * console error:
 *   1. `#` MUST be written `%23`. An unescaped `#` truncates the data URI and
 *      the whole declaration is dropped.
 *   2. `xmlns` is MANDATORY in a data URI, even though it is optional inline.
 * Also: var() and currentColor do not resolve inside a data URI, so the
 * stroke colour is baked. #d8c3ac is copper at low saturation — it reads
 * against every stop of the field without competing with any content.
 */
.ztat-main::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none"><path d="M50 0 C 50 12, 18 20, 18 34 C 18 48, 82 52, 82 66 C 82 80, 50 88, 50 100" fill="none" stroke="%23d8c3ac" stroke-width="1.1" vector-effect="non-scaling-stroke"/></svg>');
	background-repeat: repeat-y;
	background-position: 50% 0;
	background-size: 100% 1600px;
	opacity: 0.55;
}

/*
 * page-no-chrome opts out. /calendar/ is a bare Cal.com embed on a flat
 * background; a decorative field behind an iframe is noise.
 */
.ztat-main--bare { z-index: auto; }
.ztat-main--bare::before,
.ztat-main--bare::after { display: none; }

/*
 * The dark band is the one place a hard edge survives, because it genuinely
 * has to be dark. Fade into it across the runway its own inline
 * margin-top: spacing|70 already provides — that space is empty page field,
 * so there is nothing to overlap.
 *
 * rgba(20,16,13,0), NOT `transparent`. `transparent` computes to
 * rgba(0,0,0,0) and interpolates through grey, producing a visible haze band
 * across the ramp that reads as a rendering artifact rather than a fade.
 *
 * The bottom edge needs nothing: the band and the footer resolve to the same
 * ink, and the 24px stripe that used to split them is gone.
 */
.ztat-cta-band { position: relative; }

.ztat-cta-band::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 100%;
	/*
	 * An explicit length, NOT var(--wp--preset--spacing--70).
	 *
	 * That token does not resolve to what theme.json declares. The theme asks
	 * for clamp(6rem, 11vw, 10rem); WordPress ships 3.38rem, because a
	 * theme.json with no `spacingScale` key still gets core's generated scale
	 * and that wins over `spacingSizes`. A 54px ramp reads as a grey smudge,
	 * not a fade. (The same bug shrinks every section's padding site-wide —
	 * see the note in theme.json.)
	 *
	 * Sized to the runway above the band, which is spacing|70 — about 158px at
	 * a 1440px viewport now that the spacing scale actually ships.
	 *
	 * This was 90-150px while that gap was still the broken 54px. A 260px
	 * ramp against a 54px gap was measured darkening the last two FAQ rows to
	 * rgb(167,163,158): still 7:1 against the ink, so not an accessibility
	 * failure, but the copy read as sinking into a shadow. Keep the ramp at or
	 * under the real gap and that cannot happen.
	 */
	height: clamp(110px, 11vw, 158px);
	pointer-events: none;
	/*
	 * Weighted very late. A linear fade puts mid-grey in the middle of the
	 * ramp, which is a band in its own right. Holding near-zero for the first
	 * half keeps the darkening below the preceding section's last line.
	 */
	background: linear-gradient(
		to bottom,
		rgba(20, 16, 13, 0) 0%,
		rgba(20, 16, 13, 0.03) 46%,
		rgba(20, 16, 13, 0.22) 72%,
		rgba(20, 16, 13, 0.68) 89%,
		#14100d 100%
	);
}

@media print {
	.ztat-main::after { display: none !important; }
}

/*
 * `body { background: #fff }` in the print block does not suppress a
 * pseudo-element on a child. Without this, ticking "Background graphics"
 * prints a full-page gradient on every sheet.
 */
@media print {
	.ztat-main::before { display: none !important; }
}

/* ---------------------------------------------------------------- base */

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

html {
	-webkit-text-size-adjust: 100%;
	overflow-x: clip; /* belt and braces: no element may widen the document */
}

body {
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	overflow-x: clip;
}

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

:where(a):focus-visible,
:where(button):focus-visible,
:where(summary):focus-visible,
:where(input):focus-visible,
:where(textarea):focus-visible,
:where(select):focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
	border-radius: 3px;
}

/* -------------------------------------------------------- accessibility */

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

/*
 * Skip link (WCAG 2.4.1 Bypass Blocks).
 *
 * WordPress block themes already inject their own skip link via
 * wp_enqueue_block_template_skip_link(), using `.skip-link.screen-reader-text`.
 * This theme previously added a SECOND one in the header template part, so
 * every page shipped two "Skip to content" links and Tab landed on core's
 * while the custom one sat unused. The duplicate is gone; core's is the one
 * that ships, and these rules just give it the theme's styling when focused.
 */
.skip-link.screen-reader-text {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--base);
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.875rem;
	font-weight: 600;
	text-decoration: none;
	border-radius: 0 0 8px 0;
}

.skip-link.screen-reader-text:focus {
	clip-path: none;
	clip: auto;
	width: auto;
	height: auto;
	padding: 0.75rem 1.25rem;
	top: 0;
	left: 0;
	z-index: 9999;
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

/* ------------------------------------------------- dark-band inheritance */

/*
 * theme.json sets elements.heading.color to `ink` (near-black), which WP
 * emits as a bare `h1,h2,...` rule. That beats the inherited white text of a
 * dark section, so every heading inside the dark bands rendered near-black on
 * near-black and was effectively invisible. These rules hand the headings
 * back to the section's own text colour.
 */
.ztat-cta-band :is(h1, h2, h3, h4, h5, h6),
.ztat-footer   :is(h1, h2, h3, h4, h5, h6) {
	color: inherit;
}

/* Muted copy needs the same treatment inside dark bands. */
.ztat-cta-band .has-ink-muted-color {
	color: rgba(255, 255, 255, 0.72) !important;
}

/* ------------------------------------------------------------ utilities */

.ztat-eyebrow {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--ink-subtle);
	margin-bottom: 0.75rem;
}

.ztat-label {
	display: block;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--ink-subtle);
	margin-bottom: 0.4rem;
}

.has-base-color .ztat-eyebrow,
.ztat-cta-band .ztat-eyebrow { color: rgba(255, 255, 255, 0.55); }

/* --------------------------------------------------------------- header */

/*
 * THE BLUR LIVES ON ::before, NOT ON THE HEADER. Do not move it back.
 *
 * `backdrop-filter` makes an element a containing block for `position: fixed`
 * descendants. WordPress positions the mobile navigation overlay `fixed` to
 * cover the viewport; with the filter on .ztat-header the overlay was trapped
 * inside the header's ~60px box, so opening the menu produced a thin white
 * strip with one visible link and the page showing through underneath.
 *
 * Painting the blur on an absolutely-positioned pseudo-element keeps the
 * frosted effect while leaving the header itself an ordinary containing
 * block. (`position: sticky` alone does not trap fixed children.)
 */
.ztat-header {
	position: sticky;
	top: 0;
	z-index: 100;
	border-bottom: 1px solid transparent;
	transition: border-color 0.25s var(--ztat-ease);
}
.ztat-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background: rgba(250, 247, 244, 0.82);
	backdrop-filter: saturate(180%) blur(12px);
	-webkit-backdrop-filter: saturate(180%) blur(12px);
	transition: background 0.25s var(--ztat-ease);
}
.ztat-header.is-stuck { border-bottom-color: var(--wp--preset--color--border); }
.ztat-header.is-stuck::before { background: rgba(250, 247, 244, 0.94); }

.ztat-header__bar { padding-block: 0.85rem; gap: 1.5rem; }
.ztat-header__brand { gap: 0.6rem; }
.ztat-header__brand .wp-block-site-title a { text-decoration: none; color: var(--wp--preset--color--ink); }

/*
 * RESTORED. An earlier edit replaced everything between the "logo mark" and
 * "hero" section markers, and .ztat-header__nav / .ztat-nav / the mobile CTA
 * media query happened to sit between them. They were silently deleted, which
 * is why the header CTA stayed visible at 375px despite a rule saying it
 * should not.
 */
.ztat-header__nav { gap: 1.75rem; }

/*
 * Nav hover: a gradient underline that wipes in from the left, and out to the
 * right on leave rather than snapping back.
 *
 * Deliberately CSS, not GSAP. Hover has to work whether or not the animation
 * bundle ever loads, and a scaleX on a pseudo-element is GPU-composited and
 * free. GSAP is reserved for scroll-scrubbed work CSS cannot express.
 */
.ztat-nav a {
	position: relative;
	color: var(--wp--preset--color--ink-muted);
	text-decoration: none;
	transition: color 0.18s var(--ztat-ease);
}
.ztat-nav a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -5px;
	height: 2px;
	border-radius: var(--ztat-r-pill);
	background-image: var(--ztat-gradient-btn);
	transform: scaleX(0);
	transform-origin: right center;
	transition: transform 0.32s var(--ztat-ease);
}
.ztat-nav a:hover { color: var(--wp--preset--color--ink); text-decoration: none; }
.ztat-nav a:hover::after { transform: scaleX(1); transform-origin: left center; }
.ztat-nav .current-menu-item a { color: var(--wp--preset--color--ink); }

@media (prefers-reduced-motion: reduce) {
	.ztat-nav a::after { transition: none; }
}

@media (max-width: 860px) {
	.ztat-header__cta { display: none; }
}

/* Mobile overlay: core's default link size is far too small full-screen. */
.wp-block-navigation__responsive-container.is-menu-open { padding-top: 5rem; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container { gap: 0.4rem; }
.wp-block-navigation__responsive-container.is-menu-open a {
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.75rem;
	font-weight: 600;
	letter-spacing: -0.02em;
	color: var(--wp--preset--color--ink);
}
.wp-block-navigation__responsive-container.is-menu-open a::after { display: none; }

/* ------------------------------------------------------------ logo mark */

/*
 * ZTAT lockup: raked capitals with a gradient arrow that sweeps under the
 * word, cuts through the A, and rides behind the final T.
 *
 * The cut is an SVG mask, not a background-coloured shape, so the logo is
 * correct on any backdrop. An earlier version used a knockout halo filled
 * with the page colour; it had to be told what was behind it and smeared on
 * anything that was not white or #0b1220.
 *
 * Only the A is cut. Cutting the final T's crossbar as well looked
 * deliberate at 120px and made the word read as "ZTAI" at header size.
 *
 * The animation draws the arrow left to right, then lands the head. It uses
 * pathLength="100" on the path so the dash length is normalised and no
 * JavaScript measurement is needed. The mask path animates identically, so
 * the cut opens as the arrow arrives rather than sitting there empty.
 *
 * Resting state is the FINISHED logo: the animation only ever runs from a
 * start state toward it. With animations suppressed, CSS still loading, or
 * JS off, the complete mark renders.
 */
.ztat-logo-link {
	display: inline-flex;
	align-items: center;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
	border-radius: 4px;
}
.ztat-logo-link:hover { color: var(--wp--preset--color--accent); text-decoration: none; }

.ztat-logo {
	display: block;
	height: 30px;
	width: auto;
	transition: color 0.2s var(--ztat-ease);
}

@media (min-width: 700px) {
	.ztat-logo { height: 34px; }
}

@media (prefers-reduced-motion: no-preference) {
	.ztat-logo__arrow {
		stroke-dasharray: 100;
		stroke-dashoffset: 100;
		animation: ztat-logo-draw 0.85s var(--ztat-ease-out) 0.08s forwards;
	}
	.ztat-logo__head {
		opacity: 0;
		animation: ztat-logo-head 0.3s var(--ztat-ease-out) 0.78s forwards;
	}
}

@keyframes ztat-logo-draw {
	to { stroke-dashoffset: 0; }
}

@keyframes ztat-logo-head {
	from { opacity: 0; transform: translate3d(-3px, 3px, 0); }
	to   { opacity: 1; transform: none; }
}

/* ----------------------------------------------------------------- hero */

.ztat-hero { position: relative; overflow: hidden; z-index: 0; }

/*
 * The hero wash, moved off the block attribute so the hero has no opaque
 * background and therefore no hard bottom edge against the page field.
 *
 * It is RADIAL and keyed to the hero's own box, so the page-wide vertical
 * field cannot express it — it had to move rather than be deleted.
 *
 * The far stop is `rgba(250,247,244,0)`, NOT `transparent`. `transparent`
 * computes to rgba(0,0,0,0) and interpolates through grey, producing a dirty
 * haze band across the middle of the hero that reads as a rendering fault.
 */
.ztat-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background: radial-gradient(120% 100% at 15% 0%, #f7ede2 0%, rgba(250, 247, 244, 0) 58%);
}

@media print {
	.ztat-hero::before { display: none !important; }
}

.ztat-hero__inner { max-width: 940px; }

/* NOTE: no opacity animation here on purpose. See file header, item 1. */
.ztat-hero__title {
	max-width: 17ch;
	margin-block: 0.5rem 1.25rem;
	text-wrap: balance;
}

@media (min-width: 900px) {
	.ztat-hero__title { max-width: 20ch; }
}

.ztat-hero__lede { max-width: 62ch; }
.ztat-hero__actions { gap: 0.75rem; }
.ztat-hero__note { max-width: 50ch; }

/* Everything except the h1 gets a gentle entrance. Pure CSS, runs on load,
   no JS dependency, and none of it is the LCP element. */
@media (prefers-reduced-motion: no-preference) {
	.ztat-hero__eyebrow,
	.ztat-hero__lede,
	.ztat-hero__actions,
	.ztat-hero__note {
		animation: ztat-rise 0.7s var(--ztat-ease-out) backwards;
	}
	.ztat-hero__eyebrow { animation-delay: 0.02s; }
	.ztat-hero__lede    { animation-delay: 0.12s; }
	.ztat-hero__actions { animation-delay: 0.20s; }
	.ztat-hero__note    { animation-delay: 0.28s; }
}

@keyframes ztat-rise {
	from { opacity: 0; transform: translate3d(0, 14px, 0); }
	to   { opacity: 1; transform: none; }
}

/* ----------------------------------------------------------- logo wall */

.ztat-logo-wall {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: clamp(1.75rem, 4vw, 3.25rem);
}

/*
 * The radius goes on the tile, never on the <img>. Client logos are mixed
 * aspect ratios; rounding the image itself clips the corners off wide marks.
 */
.ztat-logo-wall__item {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0.85rem 1.15rem;
	min-width: 116px;
	border-radius: var(--ztat-r-md);
	background: rgba(20, 16, 13, 0.045);
	border: 1px solid var(--wp--preset--color--border);
	transition: border-color 0.25s var(--ztat-ease), transform 0.25s var(--ztat-ease), box-shadow 0.25s var(--ztat-ease);
}
.ztat-logo-wall__item:hover {
	border-color: var(--wp--preset--color--ink-subtle);
	transform: translateY(-2px);
	box-shadow: var(--wp--preset--shadow--md);
}

.ztat-logo-wall__img {
	height: clamp(26px, 3.4vw, 38px);
	width: auto;
	opacity: 0.5;
	filter: grayscale(100%);
	transition: opacity 0.25s var(--ztat-ease), filter 0.25s var(--ztat-ease);
}
.ztat-logo-wall__item:hover .ztat-logo-wall__img { opacity: 1; filter: none; }

.ztat-logo-wall__text {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 600;
	font-size: 1rem;
	color: var(--wp--preset--color--ink-subtle);
	letter-spacing: -0.01em;
}

/* -------------------------------------------------------- flow diagram */

/*
 * The diagram needs ~640px to stay legible, so below that it scrolls inside
 * its own container rather than widening the page. `overflow: clip` (not
 * `visible`) on the SVG matters: the packets animate along paths that can
 * stray a pixel or two outside the viewBox, and a visible overflow there was
 * pushing the document to 383px at a 375px viewport.
 */
.ztat-flow {
	margin: 0;
	max-width: 100%;
	overflow-x: auto;
	overflow-y: hidden;
	overscroll-behavior-x: contain;
	-webkit-overflow-scrolling: touch;
}
.ztat-flow__svg { width: 100%; height: auto; display: block; overflow: clip; }

.ztat-flow__node rect {
	fill: var(--wp--preset--color--base);
	stroke: var(--wp--preset--color--border);
	stroke-width: 1.5;
}

.ztat-flow__node text,
.ztat-flow__hub text {
	font-family: var(--wp--preset--font-family--body);
	font-size: 14px;
	font-weight: 600;
	fill: var(--wp--preset--color--ink);
}

.ztat-flow__sub {
	font-family: var(--wp--preset--font-family--mono) !important;
	font-size: 10px !important;
	font-weight: 400 !important;
	fill: var(--wp--preset--color--ink-subtle) !important;
	letter-spacing: 0.06em;
}

.ztat-flow__hub rect {
	fill: var(--wp--preset--color--ink);
	stroke: var(--wp--preset--color--ink);
}
.ztat-flow__hub-title {
	font-family: var(--wp--preset--font-family--display) !important;
	font-size: 22px !important;
	font-weight: 700 !important;
	fill: #fff !important;
	letter-spacing: -0.02em;
}
.ztat-flow__hub-sub {
	font-family: var(--wp--preset--font-family--mono) !important;
	font-size: 10px !important;
	font-weight: 400 !important;
	fill: rgba(255, 255, 255, 0.6) !important;
	letter-spacing: 0.06em;
}

.ztat-flow__caption {
	margin-top: 1.5rem;
	text-align: center;
	font-size: var(--wp--preset--font-size--xs);
	color: var(--wp--preset--color--ink-subtle);
}

/* Traveling packets. offset-path only, zero JS. Hidden entirely when the
   browser can't do it, so no stray dot parked at the origin. */
.ztat-flow__packet { fill: var(--wp--preset--color--accent); opacity: 0; }

@supports (offset-path: path("M 0 0 L 1 1")) {
	@media (prefers-reduced-motion: no-preference) {
		.ztat-flow__packet {
			opacity: 1;
			offset-rotate: 0deg;
			animation: ztat-packet 3.2s linear infinite;
		}
		.ztat-flow__packet--1 { offset-path: path("M232,72 C320,72 330,200 400,200");   animation-delay: 0s; }
		.ztat-flow__packet--2 { offset-path: path("M232,200 C310,200 330,200 400,200"); animation-delay: 0.5s; }
		.ztat-flow__packet--3 { offset-path: path("M232,328 C320,328 330,200 400,200"); animation-delay: 1s; }
		.ztat-flow__packet--4 { offset-path: path("M600,200 C670,200 680,72 768,72");   animation-delay: 1.6s; }
		.ztat-flow__packet--5 { offset-path: path("M600,200 C670,200 690,200 768,200"); animation-delay: 2.1s; }
		.ztat-flow__packet--6 { offset-path: path("M600,200 C670,200 680,328 768,328"); animation-delay: 2.6s; }
	}
}

@keyframes ztat-packet {
	0%       { offset-distance: 0%;   opacity: 0; }
	12%      { opacity: 1; }
	88%      { opacity: 1; }
	100%     { offset-distance: 100%; opacity: 0; }
}

@media (max-width: 700px) {
	.ztat-flow__svg { min-width: 640px; }
}

/* -------------------------------------------------------- services grid */

.ztat-svc-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
	gap: 1px;
	background: var(--wp--preset--color--border);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 14px;
	overflow: hidden;
}

.ztat-svc {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	padding: clamp(1.5rem, 3vw, 2.25rem);
	background: var(--wp--preset--color--base);
	text-decoration: none;
	color: inherit;
	transition: background 0.22s var(--ztat-ease);
}
.ztat-svc:hover { background: rgba(20, 16, 13, 0.045); text-decoration: none; }

.ztat-svc__num {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--accent);
}

.ztat-svc__title {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: 1.15;
	margin: 0;
}

.ztat-svc__desc {
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--sm);
	margin: 0;
	flex: 1;
}

.ztat-svc__tags {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	color: var(--wp--preset--color--ink-subtle);
	letter-spacing: 0.02em;
}

.ztat-svc__go {
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--wp--preset--color--accent);
	transition: transform 0.22s var(--ztat-ease);
}
.ztat-svc:hover .ztat-svc__go { transform: translateX(3px); }

/* ------------------------------------------------------------- metrics */

.ztat-metric { display: flex; flex-direction: column; gap: 0.15rem; }

.ztat-metric__value {
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.75rem, 3.5vw, 2.5rem);
	font-weight: 700;
	letter-spacing: -0.03em;
	line-height: 1;
	font-variant-numeric: tabular-nums;
	margin: 0;
}

.ztat-metric--lg .ztat-metric__value { font-size: clamp(2.25rem, 5vw, 3.5rem); }

.ztat-metric__label {
	font-size: var(--wp--preset--font-size--xs);
	color: var(--wp--preset--color--ink-subtle);
	margin: 0;
	line-height: 1.35;
}

/* -------------------------------------------------------- work grid */

.ztat-work-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
	gap: 1.25rem;
}

.ztat-work-card {
	position: relative;
	display: flex;
	flex-direction: column;
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 14px;
	overflow: hidden;
	transition: border-color 0.22s var(--ztat-ease), box-shadow 0.22s var(--ztat-ease), transform 0.22s var(--ztat-ease);
}
.ztat-work-card:hover {
	border-color: var(--wp--preset--color--ink-subtle);
	box-shadow: var(--wp--preset--shadow--lg);
	transform: translateY(-3px);
}

.ztat-work-card__link { position: absolute; inset: 0; z-index: 1; }

.ztat-work-card__media {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 132px;
	padding: 1.5rem;
	background: rgba(20, 16, 13, 0.045);
	border-bottom: 1px solid var(--wp--preset--color--border);
}

.ztat-work-card__logo { max-height: 56px; width: auto; object-fit: contain; }

.ztat-work-card__fallback {
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.25rem;
	font-weight: 700;
	color: var(--wp--preset--color--ink-muted);
	letter-spacing: -0.02em;
	line-height: 1.2;
	text-align: center;
	text-wrap: balance;
	padding: 0 0.5rem;
}

.ztat-work-card__body { padding: 1.25rem 1.5rem; display: flex; flex-direction: column; gap: 0.5rem; flex: 1; }
.ztat-work-card__title { font-size: var(--wp--preset--font-size--lg); font-weight: 600; margin: 0; letter-spacing: -0.015em; }
.ztat-work-card__desc { font-size: var(--wp--preset--font-size--sm); color: var(--wp--preset--color--ink-muted); margin: 0; }
.ztat-work-card__stack {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	color: var(--wp--preset--color--ink-subtle);
	margin: 0;
}

/* Only present on the projects that carry measured, consented numbers. */
.ztat-work-card__metrics {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem;
	margin-top: 0.5rem;
}

/*
 * The shared .ztat-metric__value is clamp(1.75rem, 3.5vw, 2.5rem) — up to 40px,
 * tuned for the full-width case-study card that no longer exists. At that size
 * a metric outweighs the card's own title. Scoped down here rather than
 * changing the shared rule, which the dark CTA metrics still use at full size.
 */
.ztat-work-card__metrics .ztat-metric__value {
	font-size: clamp(1.125rem, 1.6vw, 1.375rem);
}

.ztat-work-card__foot {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 1rem;
	padding: 0.85rem 1.5rem;
	border-top: 1px solid var(--wp--preset--color--border);
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	color: var(--wp--preset--color--ink-subtle);
}
.ztat-work-card__external { position: relative; z-index: 2; color: var(--wp--preset--color--accent); text-decoration: none; }
.ztat-work-card__external:hover { text-decoration: underline; }

/* Single project strip */
.ztat-project-strip {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
	gap: 1.5rem;
	padding: clamp(1.25rem, 3vw, 1.75rem);
	background: rgba(20, 16, 13, 0.045);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 14px;
}
.ztat-project-strip p { margin: 0; font-size: var(--wp--preset--font-size--sm); font-weight: 500; }

/* -------------------------------------------------------- packages */

.ztat-pkg-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr));
	gap: 1.25rem;
}

.ztat-pkg {
	display: flex;
	flex-direction: column;
	padding: clamp(1.5rem, 3vw, 2.25rem);
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 16px;
	transition: border-color 0.22s var(--ztat-ease), box-shadow 0.22s var(--ztat-ease);
}
.ztat-pkg:hover { border-color: var(--wp--preset--color--ink-subtle); box-shadow: var(--wp--preset--shadow--md); }

.ztat-pkg--featured {
	border-color: var(--wp--preset--color--accent);
	border-width: 2px;
	box-shadow: var(--wp--preset--shadow--lg);
}

.ztat-pkg__index {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--ink-subtle);
	margin: 0 0 0.5rem;
}

.ztat-pkg__flag {
	display: inline-block;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.625rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--base);
	background: var(--wp--preset--color--accent);
	padding: 0.25rem 0.6rem;
	border-radius: 999px;
	margin: 0 0 0.6rem;
}

.ztat-pkg__name {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--2xl);
	font-weight: 700;
	letter-spacing: -0.025em;
	line-height: 1.1;
	margin: 0 0 0.6rem;
}

.ztat-pkg__price { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; margin: 0 0 0.9rem; }
.ztat-pkg__amount {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	color: var(--wp--preset--color--accent);
	letter-spacing: -0.02em;
}
.ztat-pkg__unit {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--ink-subtle);
}

.ztat-pkg__pitch {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--ink-muted);
	margin: 0 0 1.25rem;
	padding-bottom: 1.25rem;
	border-bottom: 1px solid var(--wp--preset--color--border);
}

.ztat-pkg__body { flex: 1; }
.ztat-pkg__body .ztat-label { margin-top: 1.1rem; }
.ztat-pkg__body .ztat-label:first-child { margin-top: 0; }

.ztat-pkg__list { margin: 0; padding-left: 1.1rem; }
.ztat-pkg__list li {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--ink-muted);
	margin-bottom: 0.4rem;
	line-height: 1.5;
}
.ztat-pkg__list li::marker { color: var(--wp--preset--color--accent); }

.ztat-pkg__excl { font-size: var(--wp--preset--font-size--sm); color: var(--wp--preset--color--ink-muted); margin: 0; }

.ztat-pkg__foot { margin-top: 1.75rem; padding-top: 1.25rem; border-top: 1px solid var(--wp--preset--color--border); }
.ztat-pkg__cta {
	display: inline-block;
	font-weight: 600;
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--accent);
	text-decoration: none;
	transition: transform 0.2s var(--ztat-ease);
}
.ztat-pkg__cta:hover { transform: translateX(3px); text-decoration: none; }
.ztat-pkg__credit { font-size: var(--wp--preset--font-size--xs); color: var(--wp--preset--color--ink-subtle); margin: 0.6rem 0 0; }

/* --------------------------------------------------------- founder note */

.ztat-founder__portrait { margin: 1.75rem 0 0; }
.ztat-founder__portrait img {
	width: 148px;
	height: 148px;
	border-radius: 16px;
	object-fit: cover;
	object-position: top center;
	background: rgba(20, 16, 13, 0.045);
	border: 1px solid var(--wp--preset--color--border);
}
.ztat-founder__portrait figcaption {
	margin-top: 0.6rem;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	letter-spacing: 0.04em;
	color: var(--wp--preset--color--ink-subtle);
}

/* ------------------------------------------------ voices: quote + client */

.ztat-voices__grid {
	display: grid;
	grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
	gap: 1.5rem;
	align-items: stretch;
}

@media (max-width: 800px) {
	.ztat-voices__grid { grid-template-columns: 1fr; }
}

.ztat-quote {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 1.75rem;
	margin: 0;
	padding: clamp(1.75rem, 4vw, 2.75rem);
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 16px;
}

.ztat-quote__body { margin: 0; border: 0; padding: 0; }
.ztat-quote__body p {
	margin: 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.25rem, 2.2vw, 1.6rem);
	font-weight: 500;
	line-height: 1.4;
	letter-spacing: -0.02em;
	color: var(--wp--preset--color--ink);
	text-wrap: pretty;
}
.ztat-quote__body p::before { content: "\201C"; }
.ztat-quote__body p::after  { content: "\201D"; }

.ztat-quote__by { display: flex; align-items: center; gap: 0.9rem; }
.ztat-quote__photo {
	width: 56px; height: 56px;
	border-radius: 50%;
	object-fit: cover;
	flex-shrink: 0;
	border: 2px solid var(--wp--preset--color--border);
}
.ztat-quote__meta { display: flex; flex-direction: column; gap: 0.1rem; }
.ztat-quote__name { font-weight: 600; font-size: var(--wp--preset--font-size--sm); }
.ztat-quote__role {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	letter-spacing: 0.04em;
	color: var(--wp--preset--color--ink-subtle);
}

/*
 * Client card. Visually distinct from the quote card ON PURPOSE: no
 * quotation marks, no oversized display type, nothing that could read as
 * words attributed to Jeremy. He has not given a quote.
 */
.ztat-client {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	padding: clamp(1.5rem, 3vw, 2rem);
	background: var(--wp--preset--color--base);
	border: 1px dashed var(--wp--preset--color--border);
	border-radius: 16px;
}
.ztat-client__photo {
	width: 72px; height: 72px;
	border-radius: 50%;
	object-fit: cover;
	object-position: top center;
	background: rgba(20, 16, 13, 0.045);
	margin-bottom: 0.6rem;
}
.ztat-client__name { margin: 0; font-weight: 600; font-size: var(--wp--preset--font-size--lg); letter-spacing: -0.015em; }
.ztat-client__role {
	margin: 0;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	letter-spacing: 0.04em;
	color: var(--wp--preset--color--ink-subtle);
}
.ztat-client__note {
	margin: 0.6rem 0 0;
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--ink-muted);
}
.ztat-client__link { margin: 0.5rem 0 0; font-size: var(--wp--preset--font-size--sm); font-weight: 600; }

/* ---------------------------------------------------------- process */

.ztat-steps {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
	gap: 1.75rem;
	counter-reset: ztat-step;
}

.ztat-step { position: relative; padding-top: 2.75rem; }

.ztat-step::before {
	content: "";
	position: absolute;
	top: 1.1rem;
	left: 0;
	right: -1.75rem;
	height: 1px;
	background: var(--wp--preset--color--border);
}
.ztat-step:last-child::before { right: 0; }

.ztat-step__num {
	position: absolute;
	top: 0;
	left: 0;
	display: grid;
	place-items: center;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: 50%;
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--border);
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.8125rem;
	color: var(--wp--preset--color--accent);
	z-index: 1;
}

.ztat-step__title { font-size: var(--wp--preset--font-size--lg); font-weight: 600; margin: 0 0 0.4rem; letter-spacing: -0.015em; }
.ztat-step__desc { font-size: var(--wp--preset--font-size--sm); color: var(--wp--preset--color--ink-muted); margin: 0; }

/* -------------------------------------------------------------- FAQ */

.ztat-details {
	border-bottom: 1px solid var(--wp--preset--color--border);
	padding: 1.1rem 0;
}
.ztat-details summary {
	cursor: pointer;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	letter-spacing: -0.015em;
	list-style: none;
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 1rem;
}
.ztat-details summary::-webkit-details-marker { display: none; }
.ztat-details summary::after {
	content: "+";
	font-family: var(--wp--preset--font-family--mono);
	font-size: 1.25rem;
	font-weight: 400;
	color: var(--wp--preset--color--accent);
	transition: transform 0.22s var(--ztat-ease);
	flex-shrink: 0;
}
.ztat-details[open] summary::after { transform: rotate(45deg); }
.ztat-details p {
	margin: 0.9rem 0 0;
	color: var(--wp--preset--color--ink-muted);
	max-width: 68ch;
}

/* -------------------------------------------------------- post cards */

.ztat-card-grid { gap: 1.5rem !important; }

.ztat-card {
	display: flex;
	flex-direction: column;
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 14px;
	overflow: hidden;
	background: var(--wp--preset--color--base);
	transition: border-color 0.22s var(--ztat-ease), box-shadow 0.22s var(--ztat-ease);
	height: 100%;
}
.ztat-card:hover { border-color: var(--wp--preset--color--ink-subtle); box-shadow: var(--wp--preset--shadow--md); }
.ztat-card__media img { width: 100%; object-fit: cover; }
.ztat-card__body { padding: 1.25rem 1.5rem 1.5rem; display: flex; flex-direction: column; gap: 0.5rem; flex: 1; }
.ztat-card__body .wp-block-post-title { margin: 0; letter-spacing: -0.015em; }
.ztat-card__body .wp-block-post-title a { color: var(--wp--preset--color--ink); text-decoration: none; }
.ztat-card__body .wp-block-post-title a:hover { color: var(--wp--preset--color--accent); }
.ztat-card__body .wp-block-post-excerpt { color: var(--wp--preset--color--ink-muted); margin: 0; }
.ztat-card__eyebrow, .ztat-card__date { color: var(--wp--preset--color--ink-subtle); margin: 0; }
.ztat-card__date { margin-top: auto; padding-top: 0.5rem; }

.ztat-pagination { margin-top: var(--wp--preset--spacing--50); gap: 0.75rem; }

/* ------------------------------------------------------------ article */

.ztat-article .wp-block-post-content { max-width: 720px; margin-inline: auto; }
.ztat-article .wp-block-post-content > * + * { margin-top: 1.35rem; }
.ztat-article .wp-block-post-content h2 { margin-top: 2.75rem; }
.ztat-article .wp-block-post-content h3 { margin-top: 2rem; }
.ztat-article__meta { gap: 0.6rem; color: var(--wp--preset--color--ink-subtle); margin-top: 1rem; }
.ztat-article__meta p, .ztat-article__meta div { margin: 0; color: var(--wp--preset--color--ink-subtle); }
.ztat-article__hero img { border-radius: 16px; }

.ztat-page-head__excerpt { max-width: 62ch; color: var(--wp--preset--color--ink-muted); }

/* ------------------------------------------------------------- footer */

.ztat-footer a { color: rgba(255, 255, 255, 0.72); text-decoration: none; transition: color 0.18s var(--ztat-ease); }
.ztat-footer a:hover { color: #fff; text-decoration: none; }
.ztat-footer__tagline { color: rgba(255, 255, 255, 0.6); max-width: 34ch; }
.ztat-footer__label { color: rgba(255, 255, 255, 0.45) !important; margin-bottom: 0.9rem; }
.ztat-footer__list { list-style: none; margin: 0; padding: 0; }
.ztat-footer__list li { margin-bottom: 0.55rem; }
.ztat-footer__rule { border: 0; border-top: 1px solid rgba(255, 255, 255, 0.12); opacity: 1; }
.ztat-footer__legal { color: rgba(255, 255, 255, 0.45); gap: 1rem; }
.ztat-footer__legal p { margin: 0; }

/*
 * Footer logo. The mark is brand, not navigation, so it opts out of the muted
 * link scale above.
 *
 * The `a.` qualifier is load-bearing. `.ztat-footer a` is (0,1,1); a bare
 * `.ztat-footer__logo-link` would be (0,1,0) and quietly lose, leaving the mark
 * at 72% white. Qualifying to (0,2,1) beats it. `.ztat-logo-link` further up
 * sets `color: ink`, which is #0b1220 — the same value as this background — so
 * that one has to be overridden too. Both are handled by the same rule.
 */
.ztat-footer a.ztat-footer__logo-link {
	color: var(--wp--preset--color--base);
	display: inline-block;
	/* The <p> this replaced carried margin-bottom: 0.5rem. An SVG has no
	   descender space below the baseline, so it needs slightly more to keep the
	   gap to the tagline looking the same as before. */
	margin-bottom: 0.9rem;
}

/* gold, not accent: gold is the dark-band tier (10.19:1 on ink), while
   accent #a55726 on #14100d is only 2.1:1. */
.ztat-footer a.ztat-footer__logo-link:hover { color: var(--wp--preset--color--gold); }

/* Slightly larger than the header's 30/34, since this is the closing mark. */
.ztat-footer .ztat-footer__logo { height: 36px; }

@media (min-width: 700px) {
	.ztat-footer .ztat-footer__logo { height: 40px; }
}

/* ------------------------------------------------------------ buttons */

/*
 * Primary buttons use --ztat-gradient-btn, NOT the full brand gradient:
 * white text over the teal end measures 2.09:1. See the token comment.
 */
.wp-block-button:not(.is-style-outline):not(.ztat-btn--invert):not(.ztat-btn--ghost) > .wp-block-button__link {
	background-image: var(--ztat-gradient-btn);
	border-color: transparent;
	box-shadow: 0 1px 2px rgba(11, 18, 32, 0.10);
	transition: box-shadow 0.22s var(--ztat-ease), transform 0.22s var(--ztat-ease), filter 0.22s var(--ztat-ease);
}
.wp-block-button:not(.is-style-outline):not(.ztat-btn--invert):not(.ztat-btn--ghost) > .wp-block-button__link:hover {
	filter: saturate(115%) brightness(1.06);
	box-shadow: 0 8px 20px rgba(0, 87, 255, 0.28);
	transform: translateY(-1px);
}

.wp-block-button.is-style-outline > .wp-block-button__link {
	background: transparent;
	color: var(--wp--preset--color--ink);
	border-color: var(--wp--preset--color--border);
}
.wp-block-button.is-style-outline > .wp-block-button__link:hover {
	border-color: var(--wp--preset--color--ink);
	background: transparent;
	color: var(--wp--preset--color--ink);
}

.ztat-btn--invert > .wp-block-button__link {
	background: #fff;
	color: var(--wp--preset--color--ink);
	border-color: #fff;
}
.ztat-btn--invert > .wp-block-button__link:hover { background: rgba(255, 255, 255, 0.88); border-color: rgba(255, 255, 255, 0.88); color: var(--wp--preset--color--ink); }

/*
 * Ghost button.
 *
 * The selector is doubled up on purpose. `.wp-block-button.is-style-outline >
 * .wp-block-button__link` above is two classes deep, so a single-class
 * `.ztat-btn--ghost` rule loses on specificity and the link inherits the dark
 * outline colour. On a dark band that renders as dark text on a dark
 * background: a button that looks completely empty.
 */
.wp-block-button.ztat-btn--ghost > .wp-block-button__link,
.wp-block-button.ztat-btn--ghost.is-style-outline > .wp-block-button__link {
	background: transparent;
	color: #fff;
	border-color: rgba(255, 255, 255, 0.45);
}
.wp-block-button.ztat-btn--ghost > .wp-block-button__link:hover,
.wp-block-button.ztat-btn--ghost.is-style-outline > .wp-block-button__link:hover {
	border-color: #fff;
	background: rgba(255, 255, 255, 0.08);
	color: #fff;
}

/* ---------------------------------------------------------- contact */

.ztat-contact { align-items: flex-start; }

.ztat-contact__facts {
	list-style: none;
	margin: 2rem 0 0;
	padding: 0;
	display: grid;
	gap: 1.25rem;
}
.ztat-contact__facts li {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--ink-muted);
	padding-left: 0.9rem;
	border-left: 2px solid var(--wp--preset--color--border);
}
.ztat-contact__facts .ztat-label { margin-bottom: 0.2rem; }

/* The form gets a card so it reads as a distinct panel rather than floating
   in the right-hand half of an empty page. */
.ztat-contact__form {
	padding: clamp(1.5rem, 3vw, 2.25rem);
	background: rgba(20, 16, 13, 0.045);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: var(--ztat-r-lg);
}

@media (max-width: 780px) {
	.ztat-contact__form { margin-top: 2rem; }
}

/* ----------------------------------------------------- gravity forms */

.gform_wrapper .gform_fields { gap: 1rem !important; }
.gform_wrapper input[type="text"],
.gform_wrapper input[type="email"],
.gform_wrapper input[type="tel"],
.gform_wrapper input[type="url"],
.gform_wrapper select,
.gform_wrapper textarea {
	border: 1px solid var(--wp--preset--color--border) !important;
	border-radius: 8px !important;
	padding: 0.75rem 0.9rem !important;
	font-family: var(--wp--preset--font-family--body) !important;
	font-size: var(--wp--preset--font-size--sm) !important;
	background: var(--wp--preset--color--base) !important;
}
.gform_wrapper input:focus,
.gform_wrapper select:focus,
.gform_wrapper textarea:focus {
	outline: 2px solid var(--wp--preset--color--accent) !important;
	outline-offset: 1px;
	border-color: transparent !important;
}
.gform_wrapper .gform_button {
	background: var(--wp--preset--color--accent) !important;
	color: #fff !important;
	border: 0 !important;
	border-radius: 8px !important;
	padding: 0.85rem 1.6rem !important;
	font-family: var(--wp--preset--font-family--body) !important;
	font-weight: 600 !important;
	font-size: var(--wp--preset--font-size--sm) !important;
	cursor: pointer;
}
.gform_wrapper .gform_button:hover { background: var(--wp--preset--color--accent-deep) !important; }

/*
 * Gravity Forms chrome. The multi-page progress bar shipped in GF's default
 * green-teal, which read as the retired brand colour sitting on the page.
 */
.gform_wrapper .gf_progressbar { background: var(--wp--preset--color--surface-alt) !important; border-radius: var(--ztat-r-pill) !important; overflow: hidden; }
.gform_wrapper .gf_progressbar_percentage { background-image: var(--ztat-gradient-btn) !important; background-color: transparent !important; border-radius: var(--ztat-r-pill) !important; }
.gform_wrapper .gf_progressbar_title { color: var(--wp--preset--color--ink-subtle) !important; font-family: var(--wp--preset--font-family--mono) !important; font-size: 0.75rem !important; text-transform: uppercase; letter-spacing: 0.08em; }
.gform_wrapper .gform_page_footer .gform_next_button,
.gform_wrapper .gform_page_footer .gform_previous_button,
.gform_wrapper .gform_button {
	background-image: var(--ztat-gradient-btn) !important;
	border-radius: var(--ztat-r-sm) !important;
	border: 0 !important;
	color: #fff !important;
	font-weight: 600 !important;
	padding: 0.85rem 1.6rem !important;
}
.gform_wrapper .gform_page_footer .gform_previous_button {
	background-image: none !important;
	background: transparent !important;
	color: var(--wp--preset--color--ink-muted) !important;
	border: 1px solid var(--wp--preset--color--border) !important;
}
/*
 * Belt and braces against a stray paragraph above the progress bar. The real
 * cause was wpautop wrapping the shortcode when a raw-HTML div split the
 * block context; the wrapper is now a proper group block. This stays because
 * any future raw-HTML sibling would reintroduce it.
 */
.ztat-contact__form > p:empty,
.ztat-contact__form > p:has(> br:only-child),
.ztat-contact__form .gform_wrapper > p:empty { display: none; }

/* ------------------------------------------------------- scroll reveal */

/*
 * IMPORTANT: no hidden state here. motion.js applies the starting state
 * imperatively, and only to elements below the fold. See file header.
 */
.ztat-reveal { will-change: auto; }

@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;
	}
	.ztat-flow__packet { opacity: 0 !important; animation: none !important; }
}

/* ------------------------------------------------------------- print */

@media print {
	.ztat-header, .ztat-footer, .ztat-cta-band, .ztat-flow__packets { display: none !important; }
	body { color: #000; background: #fff; }
}

/* ---------------------------------------------------------------- related work
 *
 * Internal-link strip on the pillar pages. Rendered by [ztat_related_work].
 * Pill links rather than a bulleted list, so a row of client names reads as
 * navigation instead of as body copy someone forgot to format.
 */
.ztat-related {
	margin: clamp(2rem, 5vw, 3rem) 0 0;
	padding-top: 1.5rem;
	border-top: 1px solid var(--wp--preset--color--border);
}

.ztat-related__label {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.75rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--wp--preset--color--ink-muted);
	margin: 0 0 0.875rem;
}

.ztat-related__list {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.ztat-related__list a {
	display: inline-block;
	padding: 0.5rem 0.9375rem;
	/* 24px minimum pointer target: 0.5rem top + 0.5rem bottom + line-height
	   on 0.875rem type clears it with room to spare. */
	font-size: 0.875rem;
	line-height: 1.4;
	text-decoration: none;
	color: var(--wp--preset--color--ink);
	background: rgba(20, 16, 13, 0.045);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: var(--ztat-r-pill);
	transition:
		border-color 0.2s var(--ztat-ease),
		background 0.2s var(--ztat-ease),
		transform 0.2s var(--ztat-ease);
}

.ztat-related__list a:hover,
.ztat-related__list a:focus-visible {
	background: #fff;
	border-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--accent);
	transform: translateY(-1px);
}
