/* Generated by kindling-onboard. Do not edit by hand — re-run `kindling-onboard generate`. */

/* Default :focus-visible ring */
:where(a, button, .wp-element-button, input, select, textarea, [tabindex]):focus-visible {
	outline: var(--wp--custom--motion--focus-ring--outline, 2px solid var(--wp--preset--color--theme-04));
	outline-offset: var(--wp--custom--motion--focus-ring--outline-offset, 2px);
}

:where(a, button, .wp-element-button, input, select, textarea, [tabindex]):focus:not(:focus-visible) {
	outline: none;
}

@keyframes kindling-reveal-fade-up {
	from { opacity: 0; transform: translateY(16px); }
	to   { opacity: 1; transform: translateY(0); }
}

.is-style-reveal-fade-up {
	opacity: 0;
	will-change: opacity, transform;
}

.is-style-reveal-fade-up.is-revealed {
	animation: kindling-reveal-fade-up 200ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes kindling-reveal-fade-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}

.is-style-reveal-fade-in {
	opacity: 0;
	will-change: opacity, transform;
}

.is-style-reveal-fade-in.is-revealed {
	animation: kindling-reveal-fade-in 200ms cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes kindling-reveal-scale-in {
	from { opacity: 0; transform: scale(0.96); }
	to   { opacity: 1; transform: scale(1); }
}

.is-style-reveal-scale-in {
	opacity: 0;
	will-change: opacity, transform;
}

.is-style-reveal-scale-in.is-revealed {
	animation: kindling-reveal-scale-in 320ms cubic-bezier(0.3, 0, 0, 1) both;
}

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

	[class*="is-style-reveal-"] {
		opacity: 1;
		transform: none;
	}
}

/* ── Hand-authored rules preserved via @kindling:keep ────────────────── */

/* @kindling:keep:start */
/* WHY: LIVunLtd header + home-hero chrome. Responsive paddings the fluid
   spacing presets cannot express (header 16/20 -> 12/80, hero 40/20 -> 120/75/91),
   mobile/desktop element reordering (Figma: mobile = logo left + MENU right,
   desktop = MENU left + logo center + CTA right), 3-bar nav toggle matching the
   Figma hamburger (core renders 2 bars), hero line-pattern texture (Figma
   33186:8214 overlay slot), hero image 99px overhang below the navy panel,
   and Figma mobile-artboard type deltas (weight/size) unreachable via attrs. */

/* WHY: 2026-07-29 client asset LIV-Line-Pattern.png replaces
   liv-hero-texture.png as THE texture on every band that carried the wave.
   Source is 3000x1687, cropped to 3000x1615 — exactly 39 x 21 cells of
   76.92px, the one crop that wraps seamlessly in BOTH axes (measured wrap
   delta 1.36 h / 0.15 v against a 15.6 interior baseline; the raw 1687
   height wraps at 77) — then downscaled 0.4 to 1200x646. Tiled at a fixed
   1440px width so one woven cell is ~36.9px at every breakpoint, i.e. the
   scale the asset reads at on the 1440 desktop artboard. That replaces
   `cover`, which rescaled the motif with each section's box. The two navies
   (#023A69 / #02244D) are drawn to sit on theme-02, so navy bands render the
   tile at full opacity / normal blend; cream + teal bands keep a low opacity
   (see each block). Tune motif scale build-wide from
   --liv-line-pattern-size.

   WHY: 2026-07-30 client round 2 (Coeli) — "decrease the pattern's opacity
   another 10% in the navy blue sections ... it's definitely louder on the
   beige and light blue so let's decrease it 20% in those areas. The buttons
   look OK." Both are RELATIVE cuts, applied as build-wide multipliers rather
   than by rewriting each band: the light bands sit at 0.12-0.15, so a literal
   -20 points would go negative, and keeping the baselines visible in each
   rule preserves the Figma-derived per-band ratio. Buttons are untouched by
   design — their 14% is baked into liv-line-pattern-btn.png's alpha, not
   driven from here.

   WHY: 2026-07-30 round 2b — round 2 cut beige and light blue together at
   0.8, which over-corrected beige (Markets went near-invisible) while the
   light-blue bands still read loud, because the two carry different mask
   geometry, not different opacity. So the single light multiplier split by
   background: beige (theme-05 #F0EFE9) holds 0.8, light blue (#D0DEDF) takes
   a further -10% to 0.72.

   WHY: 2026-07-30 round 3 — client rules, which SUPERSEDE the placement above:
     (a) "when used, the pattern should span the full quad — no fading or
         partial application"  -> every mask-image fade is gone; bands are
         full-bleed. This is why the opacities below are re-cut: the approved
         level was judged against a faded wash covering roughly half a box, so
         at full coverage the same number reads far louder.
     (b) "never use the pattern in two consecutive quads"
     (c) "only use it in quads with minimal written content"
     (d) "on the homepage it should appear behind Our Services and Markets We
         Serve only" + "remove from hero"
   Applied build-wide as: heroes never carry it (.liv-home-hero, .liv-svc-hero,
   .liv-page-hero), and neither does .liv-intro — it is the navy band with two
   long paragraphs, i.e. the opposite of (c). What keeps it is the card-grid
   family, which is nearly all chrome and little copy: .liv-svc (ADDED, this is
   the "Our Services" quad the client named), .liv-markets, .liv-values,
   .liv-tcards.liv-on-blue, .liv-jobs, .liv-onepartner.
   Dropping the heroes also resolves (b) on /markets/ (hero+markets were quads
   1-2) and /careers/ (hero+jobs). The one remaining collision is the homepage,
   where Markets and One-Partner are quads 4-5 — hence the `.home` rule further
   down. Audited across all 11 pages; no page now has two adjacent patterned
   quads. Navy multiplier is retired with the navy bands. */
:root {
	--liv-line-pattern: url(../images/liv-line-pattern.png);
	--liv-line-pattern-size: 1440px auto;
	/* 2026-08-05 round 3 pin 2 (Conor): "Can we reduce the opacity on the applied pattern?
	   It's a little too noticeable and clashes with the headline text. This will be a global
	   edit." No percentage was given this time, so it is a -25% RELATIVE cut on both
	   multipliers — beige 0.8 -> 0.6, blue 0.5 -> 0.375 — for the same reason round 2 was
	   applied this way: the per-band baselines below carry the Figma-derived ratio between
	   bands, and cutting the multiplier preserves it. -25% is the smallest step that
	   visibly clears the heading; the complaint is specifically about headline collision,
	   and every previous over-correction here came from a large cut (round 2's -20% took
	   Markets near-invisible). If the client still reads it as loud, drop the multipliers
	   again rather than touching the baselines.
	   2026-08-07 follow-up on the same pin: "let's reduce this another 10% - this is a global
	   adjustment." Taken as a further -10% RELATIVE on both multipliers, which is what the
	   line above prescribes — beige 0.6 -> 0.54, blue 0.375 -> 0.3375. Cumulative from the
	   pre-round-4 values that is -32.5%, and the beige/blue ratio is still 1.6:1 as designed.
	   The rendered beige band is now calc(0.12 * 0.54) = 0.0648; if you change these numbers
	   again, update the pin 2 assertion in .claude/sanity-all-pins.mjs, which hard-codes the
	   computed value. */
	--liv-line-pattern-fade-beige: 0.54;
	/* 2026-07-30 round 3b: 0.72 -> 0.5. Round 3 made the bands full-bleed, which roughly
	   tripled visible texture at an unchanged number, and light blue was the one that read
	   loud again. Beige held at 0.8 — it still read subtle at full coverage.
	   2026-08-07: 0.375 -> 0.3375 with beige, see the -10% note above. */
	--liv-line-pattern-fade-blue: 0.3375;
}

/* ---- Top alert banner (Fitness Equipment Service only) ----
   WHY: client 2026-08-13 — the "Need Immediate Service?" contact line moves out of the
   page's wide callout and up into a site-top strip, "modeled after the banner that shows
   on americanpool.com". That reference is a full-bleed band above the header: bold lead
   phrase + supporting sentence on one centred row, round dismiss control pinned right.

   Printed by `render_alert_banner()` on `wp_body_open`, i.e. as a SIBLING of
   .wp-site-blocks, not inside it. That is deliberate and is what makes the sticky header
   keep working untouched: the header's sticky containing block is .wp-site-blocks, so a
   banner outside it scrolls away normally and the bar then pins at top:0 with no
   compensating offset anywhere. Do not move this inside .wp-site-blocks.

   COLOUR — client pin 108 (2026-08-18): "Green is no longer a brand color. please update to
   one of the approved brand colors that nicely contrasts the site. Not brown please."
   The old value was a one-off #28875E that no other part of the build used.
   Ruling out brown removes theme-03 (#9B7B5E) and theme-07 (#7A6049); theme-04 and
   theme-05 are too pale to carry white text (1.38:1 and 1.15:1). That leaves theme-02
   navy and theme-06 black, and black reads as an error state rather than page furniture.
   So: theme-02 #022F59 — white on it is 13.52:1, and it is already the flyout panel and
   section-heading navy, so the strip reads as brand rather than as a bolt-on.
   NOTE the old green was 4.45:1 against white, i.e. it FAILED WCAG AA (4.5) for body text
   by a hair. This change fixes that as a side effect — worth keeping if the colour is
   ever revisited.
   IF THE CLIENT WANTS AN ALERT-LIKE ACCENT instead of a brand navy, that is a NEW ninth
   palette colour: add it to design-tokens.json and regenerate theme.json — do not
   hand-edit theme.json, and do not go back to a bare hex here. */
:root {
	--liv-alert-bg: var(--wp--preset--color--theme-02);
}
/* WHY sticky, and why the header needs an offset — client pin 105 (2026-08-18): "header
   alert should follow the user down the page."
   The banner is a SIBLING of .wp-site-blocks (see above), so sticky here resolves against
   <body>, which spans the document — it pins for the whole scroll without being taken out
   of flow, so nothing below needs a compensating margin.
   The sticky header inside .wp-site-blocks would then collide with it at top:0, so the
   header's own `top` is offset by --liv-alert-h, which liv-ui.js measures from the live
   banner and resets to 0 when the banner is dismissed or absent. z-index 400 clears both
   the header (100) and the mobile bottom bar (300). */
.liv-alert-banner {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 16px;
	position: sticky;
	top: 0;
	z-index: 400;
	background-color: var(--liv-alert-bg);
	/* Right padding clears the absolutely-positioned close button so a long line
	   never runs under it; left matches so the text stays optically centred. */
	padding: 10px 56px;
	color: var(--wp--preset--color--theme-01);
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 15px;
	line-height: 1.4;
	text-align: center;
}
.liv-alert-banner__text {
	margin: 0;
	/* Matches the reference: the lead phrase is the only bold run, the rest is
	   regular weight in the same size — one sentence, not a heading + body pair. */
	font-weight: 400;
}
/* Uppercased in CSS, not in the PHP string — client pin 106 (2026-08-18) "Make all caps:
   NEED IMMEDIATE SERVICE?". Keeping `Need Immediate Service?` as the source text means a
   screen reader still reads it as a sentence rather than spelling out an initialism, and
   a future French arm in alert_banner_config() is not forced into English casing rules. */
.liv-alert-banner__text strong { font-weight: 700; text-transform: uppercase; margin-right: 10px; } /* WHY margin: client pin 153 (2026-08-31) — same treatment as resolved pin 107, air between the lead-in and the copy (hotelverdant.com example) */
.liv-alert-banner a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 2px;
}
.liv-alert-banner a:hover,
.liv-alert-banner a:focus-visible { text-decoration-thickness: 2px; }
/* WHY absolute, not a flex item: the strip's text is centred on the VIEWPORT in the
   reference, and a third flex child would shift that centre by half the button width. */
.liv-alert-banner__close {
	position: absolute;
	top: 50%;
	right: clamp(0.75rem, 0.4rem + 1.3vw, 2rem);
	transform: translateY(-50%);
	display: flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background-color: rgb(255 255 255 / 0.18);
	color: inherit;
	font-size: 20px;
	line-height: 1;
	cursor: pointer;
	transition: background-color 0.2s ease;
}
.liv-alert-banner__close:hover { background-color: rgb(255 255 255 / 0.32); }
.liv-alert-banner__close:focus-visible {
	outline: 2px solid var(--wp--preset--color--theme-01);
	outline-offset: 2px;
}
/* WHY a mobile block rather than the usual min-width desktop block: this component is
   only ever ONE line at desktop; the thing that needs handling is the narrow viewport,
   where the sentence wraps to two or three lines and the 56px symmetric padding eats
   too much of a 320px row. */
/* WHY nowrap on the two contact links: at 390 the sentence wrapped mid-phone-number
   ("...or call 844-" / "338-9900"), which reads as a broken number rather than a wrap.
   Same treatment .liv-wide-card already gets, and unscoped for the same reason — a phone
   number should never split at any width. Both fit: the email is ~160px at 14px against a
   302px content row. Client pin 4, external board 212f01fd (2026-08-24). */
.liv-alert-banner a[href^="tel:"],
.liv-alert-banner a[href^="mailto:"] { white-space: nowrap; }
@media (max-width: 767.98px) {
	.liv-alert-banner {
		padding: 10px 44px;
		font-size: 14px;
	}
	/* Client pin 4, external board 212f01fd (2026-08-24): "On Mobile for the header alert,
	   the headline should live on the first line and all other content on two lines below
	   it". The lead phrase is the only <strong> in the sentence (see render_alert_banner),
	   so promoting it to a block is the whole fix — the trailing space after </strong>
	   collapses and the rest re-flows underneath. Mobile only: at desktop this component is
	   deliberately one centred row and a block would split it in two. */
	.liv-alert-banner__text strong { display: block; margin-right: 0; margin-bottom: 4px; } /* pin 153: stacked at mobile, the air moves below the lead-in */
}

/* ---- Header bar (parts/header, Figma 33186:10154 desktop / 33186:9681 mobile) ---- */
/* WHY: client 2026-07-30 — "primary navigation should be sticky and follow the user down
   the page." Sticky rather than fixed so the header keeps its place in flow and no page
   needs a compensating top offset. The bar is opaque theme-05, so nothing shows through.
   z-index 100 clears the section ::before pattern layers (which are z-index auto inside
   their own bands); the flyout is position:fixed off this element and stacks above it.

   It has to go on the template-part WRAPPER, not on .liv-header itself: WP wraps the part
   in <header class="wp-block-template-part">, that wrapper is exactly the header's own
   height, and a sticky element cannot travel outside its containing block — so styling
   .liv-header directly computes to position:sticky and then never sticks (verified
   in-browser). The wrapper's parent is .wp-site-blocks, i.e. the whole page.
   :has() keeps this off the <footer> template part, which carries the same class; where
   :has() is unsupported the rule simply drops and the header stays static. */
header.wp-block-template-part:has(> .liv-header) {
	position: sticky;
	/* 0 unless the pin-105 alert banner is on this page; liv-ui.js owns --liv-alert-h. */
	top: var(--liv-alert-h, 0px);
	z-index: 100;
}
.liv-header { box-shadow: 0 1px 12px rgb(16 24 40 / 0.08); }
/* WHY: consequence of the sticky bar — every in-page anchor (the header's own
   "Request a Proposal" -> /#contact, and the footer's) would otherwise scroll its target
   under the header. Matches .liv-header-row min-height (80 mobile / 126 desktop) + 16. */
/* + the alert banner where present, or in-page anchors land under BOTH sticky bars. */
html { scroll-padding-top: calc(96px + var(--liv-alert-h, 0px)); }
@media (min-width: 1024px) {
	html { scroll-padding-top: calc(142px + var(--liv-alert-h, 0px)); }
}
/* WHY the asymmetric padding: pin 24 reply (2026-08-12) — "I think we'd probably want to
   move the logo down a touch too". Top grows 16 -> 28, bottom stays tight. justify-content
   is `center` because the logo is the only in-flow child left once .liv-mobile-bar goes
   position:fixed; both are handed back to the Figma values at 1024 below. */
.liv-header-row {
	padding: 28px clamp(1.25rem, 0.0917rem + 4.31vw, 5rem) 20px;
	min-height: 80px;
	justify-content: center;
}
.liv-header-logo img { width: 119px; height: auto; }

/* ---- Mobile bottom action bar (client mobile pin 24, 2026-08-12) ----
   WHY: "This should be the standard UI for mobile we use / LOGO at the top / Sticky
   menubuttons below: LEFT - MENU, Right - REQUEST FOR PROPOSAL", clarified with a
   americanpool.com reference shot. "Below" means the BOTTOM OF THE VIEWPORT, not a second
   header row — the reference pins a full-width bar to the bottom edge with the menu toggle
   on the left half and the CTA on the right half. So on mobile the header keeps the logo
   alone (centred) and MENU + RAP move to a fixed bar.

   HOW without forking the markup: .liv-mobile-bar wraps .liv-menu-pill + .liv-header-cta in
   the template part, and at desktop it takes `display: contents` so its box disappears and
   both children go back to being flex items of .liv-header-row — the Figma 3-across
   MENU / logo / CTA layout is untouched and still driven by `order`.
   NOTE the selectors above changed from `.liv-header-row > .liv-menu-pill` to a descendant
   combinator: `display: contents` removes the BOX, not the DOM node, so the child
   combinator no longer matches through the wrapper. `order` still applies because the
   element is still a flex item of .liv-header-row.
   z-index 300 clears the sticky header's own 100. The nav overlay renders inside this bar,
   so it inherits the stacking context and still paints over the whole page.

   SCOPED IN A max-width QUERY ON PURPOSE — the one place in this file that inverts the
   mobile-first convention. `display: contents` at desktop removes the WRAPPER's box but
   leaves both children as flex items of .liv-header-row, so every declaration below still
   applies to them at 1440 unless it is switched off: `flex: 1 1 50%` and the button's
   `width: 100%` stretched the desktop CTA across half the header (caught in review). One
   query that cannot leak beats eight individual desktop resets that a later edit can forget. */
.liv-header { --liv-mobile-bar-h: 64px; }
@media (max-width: 1023.98px) {
.liv-header-row > .liv-mobile-bar {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 300;
	display: flex;
	flex-wrap: nowrap;
	min-height: var(--liv-mobile-bar-h);
	background-color: var(--wp--preset--color--theme-05);
	box-shadow: 0 -1px 12px rgb(16 24 40 / 0.12);
}
/* 30/70, not the reference's 50/50 — client pin 130 (2026-08-18): "can we do a 70/30 split so
   the MENU side is less wide? Because then we can increase the REQUEST A PROPOSAL text to be
   the same size as MENU." The literal "70/30" reads left-to-right as MENU:70, which contradicts
   "MENU side is less wide"; the reason clause settles it — the CTA is the side that needs room,
   so MENU takes 30 and the CTA 70.
   flex-basis carries the ratio while grow/shrink stay on, so a narrow viewport falls back to
   min-content instead of overflowing the bar.
   ORDER IS LOAD-BEARING: the pin puts MENU on the left and the CTA on the right, and without
   these the CTA (order:0) would sort ahead of the menu pill. Desktop re-sorts all three
   against the logo at 1024. */
/* REVISED 33/67 — client pin 7, external board 212f01fd (2026-08-24): "MENU needs a little
   more room to breathe here, maybe 10%". Read as a RELATIVE nudge on the pin-130 split
   (30 x 1.1 = 33), not +10 points — "a little more room" does not describe 30 -> 40.
   At 390 that is 117px -> 129px for MENU. The CTA's flat 1rem still fits: its budget is
   (67vw - 20px) against a ~201px label, which clears at any viewport >= ~330px, and at the
   narrowest real device (320) 67vw = 214px leaves ~13px — tighter than the 70% version's
   23px but still clear. Drop below 67 and the clamp the pin-130 note retired has to come
   back. */
.liv-mobile-bar > .liv-menu-pill { flex: 1 1 33%; justify-content: center; order: 1; }
.liv-mobile-bar > .liv-header-cta { flex: 1 1 67%; order: 2; }
/* the CTA fills its half as a solid block (reference has no inset pill at this size);
   border-radius 0 + full height is what makes it read as a bar rather than a floating button */
.liv-mobile-bar .liv-header-cta .wp-block-button { width: 100%; }
.liv-mobile-bar .liv-header-cta .wp-element-button {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: var(--liv-mobile-bar-h);
	border-radius: 0;
	text-align: center;
	/* WHY the retune: "REQUEST A PROPOSAL" is 180px at the header's 16px, and the button's
	   own 20px side padding puts it at 220px against a 195px half at 390 — it wrapped to two
	   lines and pushed the whole bar to 80px tall. The label costs ~11.3px of width per 1px
	   of font-size, so the cap is (50vw - 20px) / 11.3; 3.6vw clears 320, 360 and 390 with
	   room, and 14px is the ceiling because bigger buys nothing once it fits.
	   nowrap is a tripwire, not decoration: if this copy is ever lengthened the label will
	   overflow visibly instead of quietly re-growing the bar.
	   BOTH need !important and neither is avoidable by specificity: the side padding is an
	   INLINE style from the block's own attrs (20px, correct at desktop, so it can't just be
	   edited out in the DB), and the font-size comes from the `has-medium-font-size` preset
	   class, which WordPress always emits as !important. */
	padding-block: 12px;
	padding-inline: 10px !important;
	/* 1rem = the `medium` preset = exactly what MENU uses, which is what pin 130 asked for.
	   The old clamp(0.6875rem, 3.6vw, 0.875rem) was NOT arbitrary — its cap was derived from
	   the 50vw half: (50vw - 20px) / 11.3px-per-px-of-font-size. Widening the CTA to 70%
	   dissolves that constraint, so the recomputed budget is (70vw - 20px) / 11.3:
	   "REQUEST A PROPOSAL" is ~180px at 16px, +20px of side padding = ~201px, and 70vw clears
	   that at any viewport >= ~287px. The narrowest real device is 320 (70vw = 224px), so a
	   flat 1rem fits everywhere with ~23px to spare — no clamp needed any more.
	   white-space: nowrap below stays as the tripwire: if this copy is ever lengthened the
	   label overflows visibly instead of quietly re-growing the bar to two lines. */
	font-size: 1rem !important;
	white-space: nowrap;
}
} /* end max-width 1023.98 — mobile bottom bar */
@media (min-width: 1024px) {
	/* WHY: Figma 33186:10154 pads 80px at 1440; the fluid clamp tops out past 1830 */
	.liv-header-row { min-height: 126px; padding: 12px 80px; justify-content: space-between; }
	/* box disappears; menu-pill and CTA become flex items of .liv-header-row again */
	.liv-header-row > .liv-mobile-bar { display: contents; }
	/* WHY the equal flex sides: client pin 181 (2026-08-31) asked to confirm the logo is
	   centered — it was not: space-between let the wider CTA (≈218px) outweigh MENU (≈118px),
	   sitting the logo ~52px left of true center (measured at 1440). Equal 1fr sides make the
	   centering exact instead of optical. */
	.liv-header-row .liv-menu-pill { order: 1; flex: 1 1 0; justify-content: flex-start; }
	.liv-header-row > .liv-header-logo { order: 2; }
	.liv-header .liv-header-row .liv-header-cta { order: 3; display: flex; flex: 1 1 0; justify-content: flex-end; }
	.liv-header-logo img { width: 205px; }
	/* WHY: Figma 33041:450 (via 33186:10114) supersedes 33186:10154 — desktop trigger
	   shows the MENU label left of the burger; the label paragraph already carries
	   the Figma type attrs, so nothing to hide */
}
/* 3-bar hamburger: hide core 2-bar svg, draw bars with gradients
   (Figma 33187:10753 mobile 30x21 stroke 3 / 33186:10155 desktop 56x30 stroke 5) */
.liv-nav .wp-block-navigation__responsive-container-open svg { display: none; }
.liv-nav .wp-block-navigation__responsive-container-open {
	width: 30px;
	height: 21px;
	background-image:
		linear-gradient(var(--wp--preset--color--theme-03), var(--wp--preset--color--theme-03)),
		linear-gradient(var(--wp--preset--color--theme-03), var(--wp--preset--color--theme-03)),
		linear-gradient(var(--wp--preset--color--theme-03), var(--wp--preset--color--theme-03));
	background-repeat: no-repeat;
	background-size: 100% 3px;
	background-position: 0 0, 0 9px, 0 18px;
}
@media (min-width: 1024px) {
	.liv-nav .wp-block-navigation__responsive-container-open {
		width: 56px;
		height: 30px;
		background-size: 100% 5px;
		background-position: 0 0, 0 12.5px, 0 25px;
	}
}

/* WHY: client 2026-07-30 — "make the word MENU clickable, not just the hamburger icon."
   Done by stretching core's own open button over the whole pill rather than by binding a
   click handler to the paragraph. Two reasons: it needs no JS (and `assets/js/motion.js` is
   overwritten verbatim on every kindling-onboard generate, so nothing can live there), and
   it keeps ONE control in the accessibility tree — a second scripted trigger for the same
   dialog is duplicate noise. Same stretched-overlay technique as the service/market cards.
   The label stays a plain paragraph, so the flyout markup and aria wiring are untouched. */
.liv-menu-pill { position: relative; }
/* core sets .wp-block-navigation{position:relative}, which would catch the overlay below
   and shrink it back to just the burger. This nav is overlayMenu:"always", so it has no
   inline submenus and nothing else needs that containing block — the open flyout is
   position:fixed. Scoped to the pill so no other navigation is affected. */
.liv-menu-pill .liv-nav { position: static; }
.liv-nav .wp-block-navigation__responsive-container-open::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 2;
}
/* WHY: client 2026-07-30 — "add a subtle animation/movement to the MENU element."
   Hover/focus driven, not idle: the same review asks for movement AND calls subtlety out,
   and a nav label that twitches on its own reads as a bug (same call as the arrow-chip
   nudge). Two paired cues — the label underline wipes in from the left, and the three
   hamburger bars stagger-retract — so the pill reads as one control. The global
   prefers-reduced-motion block at the top of this file neutralises both. */
.liv-menu-label { position: relative; }
.liv-menu-label::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -3px;
	height: 2px;
	background-color: currentColor;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 280ms cubic-bezier(0.3, 0, 0, 1);
}
.liv-menu-pill:hover .liv-menu-label::after,
.liv-menu-pill:focus-within .liv-menu-label::after { transform: scaleX(1); }
.liv-nav .wp-block-navigation__responsive-container-open {
	transition: background-size 280ms cubic-bezier(0.3, 0, 0, 1);
}
.liv-menu-pill:hover .wp-block-navigation__responsive-container-open,
.liv-menu-pill:focus-within .wp-block-navigation__responsive-container-open {
	background-size: 62% 3px, 100% 3px, 80% 3px;
}
@media (min-width: 1024px) {
	.liv-menu-pill:hover .wp-block-navigation__responsive-container-open,
	.liv-menu-pill:focus-within .wp-block-navigation__responsive-container-open {
		background-size: 62% 5px, 100% 5px, 80% 5px;
	}
}

/* ---- Flyout menu overlay (Figma 33186:9753 mobile / 33186:10175 desktop).
   WHY: core's overlay is a bare full-screen modal; Figma wants a branded panel:
   white logo header, gold close X, Cormorant links (25/700 mobile — no preset
   fits 25px at 430, `large` fluid renders ~19px — vs 33/500 = x-large desktop),
   white lvl-2 dropdown cards, a 727px left panel over a scrim on desktop, and a
   mobile-only RAP pill. Panel paddings (36/30, 67/40/52) + gap 38 are off-scale. */
.liv-nav .wp-block-navigation__responsive-container.is-menu-open {
	padding: 0;
	align-items: stretch;
}
/* WHY: client 2026-07-30 — "clicking Menu should slide the navigation in." Figma anchors
   the panel to the LEFT edge on desktop (33186:10175), so it slides in from the left on
   both breakpoints. Written as `animation`, not `transition`: core flips the container
   from display:none to flex in the same frame it adds .is-menu-open, and a transition on a
   just-displayed element does not run. The scrim fades on its own curve so the dark wash
   does not snap in ahead of the panel.
   CLOSING IS NOT ANIMATED — core removes the class and unmounts immediately, and delaying
   that needs JS that would have to re-implement its focus-trap teardown. Open-only matches
   the ask; flag if they want the reverse too. */
@keyframes liv-nav-slide-in {
	from { transform: translateX(-100%); }
	to   { transform: translateX(0); }
}
@keyframes liv-nav-scrim-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}
.liv-nav .wp-block-navigation__responsive-container.is-menu-open {
	animation: liv-nav-scrim-in 260ms ease both;
}
.liv-nav .is-menu-open .wp-block-navigation__responsive-close {
	animation: liv-nav-slide-in 380ms cubic-bezier(0.3, 0, 0, 1) both;
}
.liv-nav .is-menu-open .wp-block-navigation__responsive-close {
	width: 100%;
	min-height: 100%;
	display: flex;
	flex-direction: column;
}
.liv-nav .is-menu-open .wp-block-navigation__responsive-dialog {
	position: relative;
	flex: 1;
	padding: 36px 30px;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
}
/* WHY there is no panel logo at ANY breakpoint — and why this has moved three times.
   pin 17 (2026-08-05) "Delete logo" -> removed everywhere.
   pin 25 (2026-08-12, mobile) "we can keep the LIV logo on mobile because it's a full
     screen takeover. Just need to cetner the logo" -> restored below 1024 only.
   pin 90 (2026-08-18, mobile) "Mobile Nav needs to mirror the desktop navigation (no logo,
     adding the word 'CLOSE') etc." -> removed again, everywhere.

   pin 90 reverses pin 25 on both of its named points, six days later and on the same mobile
   board, so it wins on recency and on being the more specific instruction ("no logo" is not
   ambiguous). The full-screen-takeover reasoning pin 25 gave still describes the mobile
   panel accurately — the client simply no longer wants the mark in it. If this comes back a
   fourth time, ask which of 25 and 90 is current before editing; do not infer from the
   takeover argument, because that argument survived the reversal.

   Removing it hands back the vertical budget pin 18's "shift upwards" was costed against —
   the 200x70 mark (Figma 33187:10469) plus its 40px bottom margin — so the mobile panel now
   has ~110px more room above pin 19's secondary block than it did on 2026-08-12. Nothing
   below depends on the logo's box, so nothing else needed compensating. */
/* close X 26x26 (Figma 33187:10470, stroke 5) */
/* WHY white and not the Figma gold: client 2026-08-17 pins 92 (desktop) + 93 (mobile) —
   "Make Close and the X white". Overrides theme-03 from Figma 33187:10470. One declaration
   covers both pins and both elements: the ::before CLOSE word and the ::after X mask each
   take `currentColor`, and this rule sits outside any media query, so mobile (X only, the
   word is suppressed per pin 25) recolours from the same line. Do not re-split this into
   per-element colours — that is what made it a one-line fix. */
.liv-nav .is-menu-open .wp-block-navigation__responsive-container-close {
	position: absolute;
	top: 36px;
	right: 30px;
	padding: 0;
	color: var(--wp--preset--color--theme-01);
	/* flex so the pin-13 CLOSE word and the X sit on one row, word first */
	display: flex;
	align-items: center;
	gap: 10px;
}
.liv-nav .is-menu-open .wp-block-navigation__responsive-container-close svg { display: none; }
/* WHY the word is a ::before and not real markup: client 2026-08-05 pin 13 — "Let's add the
   word CLOSE like this:" with a reference shot of hotelbethlehem.com's "CLOSE ✕". The button
   is rendered by core/navigation with no filter or inner-blocks hook to add a label, so the
   word has to be drawn in CSS. It is decorative-only — the button already carries
   aria-label="Close menu", so screen readers get the name from there and this text stays out
   of the accessibility tree (generated content on a labelled control is not announced). */
/* WHY it is back at BOTH breakpoints: pin 25 (2026-08-12, mobile) took it off mobile — "we
   don't need the word 'CLOSE' next to the X" — and pin 90 (2026-08-18, mobile) puts it back:
   "Mobile Nav needs to mirror the desktop navigation (no logo, adding the word 'CLOSE') etc."
   Same reversal as the panel logo above; see that block for why pin 90 is taken as current.
   With the breakpoint gate gone the word is simply part of the base rule again, which is the
   state pin 13 originally asked for. Nothing else changes — the X, its 26px mask and the
   aria-label are untouched, so the control keeps its accessible name at both sizes, and the
   word stays out of the accessibility tree per the note above. */
.liv-nav .is-menu-open .wp-block-navigation__responsive-container-close::before {
	content: "CLOSE";
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 14px;
	font-weight: 700;
	letter-spacing: 0.08em;
	line-height: 1;
	color: currentColor;
}
.liv-nav .is-menu-open .wp-block-navigation__responsive-container-close::after {
	content: "";
	display: block;
	width: 26px;
	height: 26px;
	background-color: currentColor;
	-webkit-mask: url(../images/liv-close-x.svg) center / contain no-repeat;
	mask: url(../images/liv-close-x.svg) center / contain no-repeat;
	flex-shrink: 0;
}
.liv-nav .is-menu-open .wp-block-navigation__responsive-container-content {
	display: flex;
	flex-direction: column;
	flex: 1;
}
.liv-nav .is-menu-open .wp-block-navigation__container {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--30); /* Figma item gap 24 = spacing-30 exact */
}
.liv-nav .is-menu-open .wp-block-navigation-item { padding-left: 8px; } /* Figma lvl-1 pl 8 */
.liv-nav .is-menu-open .wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--cormorant-garamond);
	/* 25 -> 30px: mobile half of client 2026-08-05 pin 18 ("make all primary navigation
	   elements larger"). Held to 30 because the panel is full-width on mobile and
	   "Request A Proposal" already runs the column at 30px. */
	font-size: 30px;
	font-weight: 700;
	letter-spacing: -0.03em;
	line-height: 1.2;
	padding: 0;
}
/* Whole submenu row is one hit target — client 2026-08-05 pins 4 & 5: "Markets shouldn't be
   anchor linking; clicking on 'markets' OR THE ARROW should trigger the dropdown."
   The nav block now carries submenuVisibility:"click" (header template part 27), which makes
   core render the label as a <button> instead of an <a> — that half is free. But in click mode
   core also moves the icon OUT of the button into a bare sibling <span>, so the arrow stops
   being clickable. Stretching the button across the row and making the icon transparent to
   the pointer puts the arrow back inside the button's hit area without any JS.
   NOTE for future edits: the icon is a <span> in click mode and a <button> in hover mode.
   Anything that assumes it is focusable will silently stop working if the mode changes. */
.liv-nav .is-menu-open button.wp-block-navigation-submenu__toggle {
	width: 100%;
	text-align: left;
	justify-content: flex-start;
}
.liv-nav .is-menu-open .wp-block-navigation__submenu-icon { pointer-events: none; }

/* Submenu toggle = the brand arrow chip, rotated to point down.
   WHY: client 2026-08-05 pin 12 — "For the down arrows, can we take our current arrow icons
   and rotate them down?" (attachment on the pin is the tan circle + white arrow chip). This
   replaces the ivory 24x24 chevron from Figma 33187:10504.
   WHY the same circle-plus-mask construction as figure.liv-chip rather than an <img>: core
   renders its own inline <svg> and there is no markup hook to swap it, so the svg is hidden
   and the chip is painted on the element itself — background for the circle, ::after for the
   masked arrow. Reusing liv-chip-arrow.svg keeps one arrow asset in the build.
   The rotation is on ::after only: rotating the box would rotate its focus ring too. */
.liv-nav .is-menu-open .wp-block-navigation__submenu-icon {
	position: relative;
	width: 32px;
	height: 32px;
	padding: 0;
	border-radius: 50%;
	background-color: var(--wp--preset--color--theme-03);
	flex-shrink: 0;
	transition: background-color 200ms var(--liv-reveal-ease);
}
.liv-nav .is-menu-open .wp-block-navigation__submenu-icon svg { display: none; }
/* inset:0 and NOT a smaller centred box — liv-chip-arrow.svg is a 33x33 artboard with the
   arrow inset to ~16px, i.e. the padding is baked into the asset. Masking it over the full
   circle is what figure.liv-chip does and is what gives the arrow its correct weight; sizing
   the mask box down instead scales the padding too and the arrow comes out half-size. */
.liv-nav .is-menu-open .wp-block-navigation__submenu-icon::after {
	content: "";
	position: absolute;
	inset: 0;
	background-color: var(--wp--preset--color--theme-01);
	-webkit-mask: url(../images/liv-chip-arrow.svg) no-repeat center / contain;
	mask: url(../images/liv-chip-arrow.svg) no-repeat center / contain;
	transform: rotate(90deg);
	transition: transform 260ms var(--liv-reveal-ease);
}
/* Open state points the arrow back up, so the control reads as a toggle rather than a
   decoration — the chevron it replaced got this for free from core.
   WHY :has() on the li rather than [aria-expanded] on the icon: in click mode aria-expanded
   lives on the sibling label button, not on the icon. :has() is already load-bearing a few
   rules below, so this adds no new support floor. */
.liv-nav .is-menu-open li.wp-block-navigation-submenu:has(> button[aria-expanded="true"]) > .wp-block-navigation__submenu-icon::after {
	transform: rotate(-90deg);
}
/* theme-07 on hover — same token as the card arrow chips (Figma button styles row 2,
   33191:12282), so the two chips behave identically wherever they appear. Driven off the row
   and not the chip itself: the chip is pointer-events:none now, and the row is one control,
   so hovering the word should light the chip too. */
.liv-nav .is-menu-open li.wp-block-navigation-submenu:hover > .wp-block-navigation__submenu-icon {
	background-color: var(--wp--preset--color--theme-07);
}
/* lvl-2 accordion links: parent serif, ivory, plain indented list — client direction
   2026-07-23 PM supersedes Figma's white rounded lvl-2 card (33186:10213). Background
   stays transparent via core's own modal reset. */
.liv-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
	/* !important: core's modal reset pads submenu containers 2rem at (0,5,0) after motion.css */
	padding: 4px 0 0 var(--wp--preset--spacing--30) !important;
	display: flex;
	flex-direction: column;
	gap: 12px;
	margin-top: 8px;
}
.liv-nav .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item { padding-left: 0; }
.liv-nav .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--cormorant-garamond);
	font-size: 20px;
	font-weight: 500;
	letter-spacing: -0.03em;
	line-height: 1.2;
	color: var(--wp--preset--color--theme-05);
}
/* WHY: core forces submenus open inside the modal; Figma wants a chevron-toggled accordion */
.liv-nav .is-menu-open .wp-block-navigation-submenu:not(:has(> button[aria-expanded="true"])) > .wp-block-navigation__submenu-container { display: none; }
/* WHY: Figma 33186:10175 desktop / 33186:9753 mobile — Markets/Services carry a
   right-aligned theme-05 down caret (24x24, right edge at 361, core flips it when
   expanded). Core's modal reset hides submenu icons (`...responsive-container-content
   .wp-block-navigation__submenu-icon { display: none }`) and columns the item AFTER
   motion.css, hence !important + absolute pinning to the label row. */
.liv-nav .is-menu-open .wp-block-navigation__responsive-container-content { width: 100%; } /* dialog is align-items:flex-start; content shrink-fits without this */
.liv-nav .is-menu-open .wp-block-navigation__container { width: 100%; } /* ul shrink-wraps to widest label otherwise; carets need the full 361 column */
.liv-nav .is-menu-open li.wp-block-navigation-submenu {
	position: relative;
	width: 100%;
	max-width: 361px; /* Figma interaction-zone width, both breakpoints */
}
.liv-nav .is-menu-open li.wp-block-navigation-submenu > .wp-block-navigation__submenu-icon {
	display: inline-block !important;
	position: absolute;
	top: 2px; /* centers the 32px chip on the 36px label row (30px / 1.2) — (36-32)/2 */
	right: 0;
	margin: 0;
	width: 32px;  /* was 24 — pin 12 swapped the bare chevron for the 32px arrow chip */
	height: 32px;
}
/* mobile-only RAP pill at flyout bottom (Figma 33187:10622) */
.liv-nav .is-menu-open .wp-block-navigation-item.liv-nav-pill { margin-top: 40px; padding-left: 0; }
.liv-nav .is-menu-open .liv-nav-pill .wp-block-navigation-item__content {
	background-color: var(--wp--preset--color--theme-03);
	color: var(--wp--preset--color--theme-01);
	border-radius: 999px;
	padding: 12px 20px;
	font-family: var(--wp--custom--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	letter-spacing: 0.02em;
	line-height: 1;
	text-transform: uppercase;
}
.liv-nav .is-menu-open .liv-nav-pill .wp-block-navigation-item__content:hover { background-color: var(--wp--preset--color--theme-07); }
.liv-nav .is-menu-open .liv-nav-pill .wp-block-navigation-item__content:active { background-color: var(--wp--preset--color--theme-05); color: var(--wp--preset--color--theme-06); }
.liv-nav .is-menu-open .liv-nav-pill .wp-block-navigation-item__content:focus-visible { outline: 2px solid var(--wp--preset--color--theme-04); outline-offset: -2px; }
@media (min-width: 1024px) {
	/* WHY: Figma 33186:10175 — desktop flyout is a 727px left panel over a page scrim.
	   The preset bg class on the container carries !important, hence the override. */
	.liv-nav .wp-block-navigation__responsive-container.is-menu-open {
		background-color: rgb(0 0 0 / 0.45) !important;
		justify-content: flex-start;
	}
	/* margin overrides core's `margin: 0 auto` centering — Figma anchors the panel left */
	.liv-nav .is-menu-open .wp-block-navigation__responsive-close { width: min(727px, 100%); margin: 0 auto 0 0; }
	.liv-nav .is-menu-open .wp-block-navigation__responsive-dialog {
		background-color: var(--wp--preset--color--theme-02);
		box-shadow: 0 24px 48px -12px rgb(16 24 40 / 0.25); /* Figma shadow-2xl */
		padding: 67px 52px 67px 40px;
		align-items: flex-end;
	}
	/* pin 17 — desktop sizing for the panel logo. The base rule it modified is gone again as of
	   pin 90 (2026-08-18); kept here only so a fourth restore has the desktop numbers to hand.
	.liv-nav .is-menu-open .wp-block-navigation__responsive-dialog::before {
		width: 418px;
		height: 122px;
		background-size: 260px auto;
		margin-bottom: 38px;
	} */
	.liv-nav .is-menu-open .wp-block-navigation__responsive-container-close { top: 67px; right: 52px; }
	.liv-nav .is-menu-open .wp-block-navigation__responsive-container-content { width: 418px; flex: initial; padding: 18px 0; }
	/* WHY 40px and not the x-large preset: client 2026-08-05 pin 18 — "Make all primary
	   navigation elements larger and shift upwards". x-large is 33px, which is the Figma
	   value; the client is overriding Figma here, so this is deliberately off-token. 40px is
	   the next step that still fits "Request A Proposal" on one line inside the 418px column
	   (measured — 44px wraps it, and a wrapped primary item breaks the caret alignment). */
	.liv-nav .is-menu-open .wp-block-navigation-item__content { font-size: 40px; font-weight: 500; }
	/* pin 23 moved the dropdown items to the 16px uppercase Proxima eyebrow treatment at every
	   width, so the old desktop 24px serif step is gone. The type block lives with the rest of
	   the pin 23 rule further down the file — deliberately NOT restated here, because two
	   same-specificity rules for one thing is how the 24px ended up outliving its replacement. */
	/* chip centers on the 48px label row (40px / 1.2) against the 32px chip — (48-32)/2 */
	.liv-nav .is-menu-open li.wp-block-navigation-submenu > .wp-block-navigation__submenu-icon { top: 8px; }
	/* !important: core's modal reset re-flexes nav items after motion.css */
	.liv-nav .is-menu-open li.liv-nav-pill { display: none !important; }
}

/* ---- Home hero (Figma 33186:8214 desktop / 33187:10758 mobile) ---- */
/* WHY: pattern removed 2026-07-30 (client round 3, rule d "remove from hero"). The
   position/z-index stay — .liv-hero-content and the image still stack against them. */
.liv-home-hero { position: relative; z-index: 2; overflow: visible; }
.liv-home-hero > .liv-hero-content,
.liv-home-hero > .liv-hero-media { position: relative; }
.liv-home-hero { padding: 0; }
.liv-hero-content { padding: 40px 20px; }
.liv-home-hero h1 { max-width: 560px; font-weight: 500; letter-spacing: -0.05em; }
/* WHY: client mobile pin 77 (2026-08-12) — "Let's decrease the font size to get
   'performance-driven' on one line". The `display` preset renders 58.06px at 390, which
   breaks the h1 after the hyphen into "Performance-" / "Driven Solutions". Measured at this
   weight and letter-spacing, "Performance-Driven" costs ~6.92px of width per 1px of
   font-size, so it needs <= 48px in the 350px column 390 leaves after .liv-hero-content's
   40px of padding.
   Fluid rather than a flat 48px because the constraint tracks viewport width: 360px phones
   only have 320px of column (<=46px) and 320px phones 280px (<=40px). 12.2vw clears all
   three with headroom; the 3rem cap holds it at 48px from ~394 up to the desktop
   breakpoint, and the 2.25rem floor stops it collapsing on very narrow screens.
   SCOPED to the home hero on purpose: `display` is a shared fluid preset, so retuning the
   token would move every page. This is a deliberate departure from the mobile Figma type
   scale (33187:10758) at the client's request — read a gate diff here as intended.
   !important is required, not sloppiness: the h1 carries core's `has-display-font-size`
   class and WordPress emits every font-size PRESET class as `!important`, so a plain
   declaration here loses no matter how specific the selector. The 1024 reset below has to
   carry it for the same reason. */
.liv-home-hero h1 { font-size: clamp(2.25rem, 12.2vw, 3rem) !important; }
/* WHY: client mobile pin 26 (2026-08-12) — "Hero image carousel should be above the intro
   quad", read against the americanpool.com reference supplied for pin 24, which runs
   logo -> hero photo -> intro copy block. "Intro quad" is the hero's own four-element stack
   (h1 / eyebrow / gold rule / sub-paragraph); nothing else on the home page is a quad —
   wp_block 46 "Our Services" has six cells. The hero is a core grid, and grid items honour
   `order`, so the DOM (and therefore the reading order for assistive tech and the editor)
   is untouched. ASSUMPTION worth re-confirming with the client if the next round disagrees.

   768, NOT the usual 1024: the pin is about the STACKED hero. wp_block 28 authors the grid
   at minimumColumnWidth 24rem, so it holds two columns down to 768px — between 768 and 1023
   an unscoped `order` would not stack anything, it would just swap the columns left-for-right
   and put the photo on the wrong side of a layout nobody complained about (seen at 900 in
   review). Below 768 there is one column and `order` means what the pin means. */
@media (max-width: 767.98px) {
	.liv-home-hero > .liv-hero-media { order: -1; }
}
.liv-hero-sub { max-width: 510px; font-weight: 400; letter-spacing: 0.01em; } /* WHY 400: client pin 190 (2026-08-31) — "un-bold across all intro quads across the entire website"; matches .liv-intro-text.
   WHY 0.01em (was 0): client 2026-09-02 (text round) — "That is the font size, weight, etc. we are looking for across every intro quad. It could be helpful to increase kerning a bit." The reference screenshot is the HOME hero sub-paragraph, so .liv-hero-sub is the target style and every other intro quad has to match it: 400 weight, `large` (25px) Cormorant, lh 1.2 — all six intro blocks already carry identical block attrs (fontSize large / cormorant-garamond / lineHeight 1.2), so the only thing that ever differed was weight and tracking HERE. Kerning: the desktop rules tracked -0.03em; opened to 0.01em at BOTH breakpoints so the ask reads as an actual increase over default rather than just removing the tightening (0.25px/char at 25px). Same value on both classes on purpose — the client is asking for ONE intro-quad style, not two. */
.liv-hero-eyebrow { font-size: 0.875rem; }
/* WHY: 2026-07-29 client asset LIV-Divider.png replaces the solid theme-03
   bar on every .liv-rule / .liv-sec-rule. The asset is a 2816x91
   dot-line-dot at 31:1 — scaled into the 112px rule slot that yields 3.6px
   dots over a 0.5px line, i.e. invisible. Drawn instead as a 3-layer CSS
   mask (dot, dot, stretchy hairline) over the separator's OWN
   background-color: every pattern authors these as core/separator with
   backgroundColor:theme-03, so the shape inherits the token, recolors for
   free, and stays crisp at any DPR with no raster shipped. Dots are a fixed
   7px at both breakpoints (the "fixed dots" call) — mobile rules therefore
   grow 4px -> 7px tall; widths are untouched. */
.liv-divider-shape,
.liv-rule,
.liv-sec-rule {
	height: 7px;
	-webkit-mask:
		radial-gradient(circle closest-side, #000 98%, #0000) left center / 7px 7px no-repeat,
		radial-gradient(circle closest-side, #000 98%, #0000) right center / 7px 7px no-repeat,
		linear-gradient(#000 0 0) center center / 100% 1.5px no-repeat;
	mask:
		radial-gradient(circle closest-side, #000 98%, #0000) left center / 7px 7px no-repeat,
		radial-gradient(circle closest-side, #000 98%, #0000) right center / 7px 7px no-repeat,
		linear-gradient(#000 0 0) center center / 100% 1.5px no-repeat;
}
.liv-rule { width: 112px; border: none; margin: 0; opacity: 1; }
.liv-hero-media img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }

/* ---- Home hero carousel (client review 2026-07-30) ----
   WHY: "convert the static image to a 4-image auto-rotating carousel" + "overlay the
   circles from the new divider branding element on the bottom of the image to showcase
   carousel functionality; may need a gradient behind them so they're visible."

   Timing is the house pattern already proven on the American Pool Kindling build
   (hero-background-carousel.js / splide-autoplay.js there): pause on hover, crossfade
   rather than translate. Dwell was 6s / fade 1.8s there; this build runs 4s / 1.2s per
   client request (2026-08-03 — "switch sooner"). WHY the fade shortened too: at a 4s dwell
   an 1.8s fade leaves only 2.2s of settled image, so the hero reads as permanently
   dissolving; 1.2s keeps ~2.8s settled. The dwell lives in liv-ui.js; the fade lives here
   with the rest of the section geometry. Slides are stacked and cross-faded so the
   panel never changes height and the flush photo/text edge (Figma 33186:8214) holds.

   .liv-hero-dots is BUILT BY JS, not authored in the pattern — keeps wp:html out of the DB
   pattern (FSE audit) and keeps the control count locked to the slide count. Everything
   here is scoped under .has-carousel, which JS only adds once there are 2+ slides, so a
   single-image hero renders exactly as it did before with no stray chrome. */
.liv-hero-carousel { position: relative; }
.liv-hero-carousel .liv-hero-slide { margin: 0; }
/* No-JS / pre-hydration fallback: show slide 1 only. Without this the four figures stack
   in flow and the hero renders four images tall before (or forever without) liv-ui.js.
   JS adds .has-carousel, which overrides this and takes every slide out of flow. */
.liv-hero-carousel .liv-hero-slide:not(:first-child) { display: none; }
.liv-hero-carousel.has-carousel .liv-hero-slide:not(:first-child) { display: block; }
/* Only stack once JS confirms a real carousel; without this a no-JS visitor would get
   four images collapsed on top of each other with no way to advance them.
   WHY absolute and not a 1x1 grid: the hero sizes itself through a percentage-height chain
   (.liv-hero-media -> figure -> img all height:100% at desktop, so the photo ends flush
   with the text panel per Figma 33186:8214). Stacking the slides IN FLOW makes that chain
   circular — the row asks the images for a height while the images ask the row — and it
   resolved to a 1500px hero. Taking every slide OUT of flow breaks the cycle: the group has
   no in-flow content, so its height comes from the row, and the row is driven by the text
   column exactly as it was with a single static image. */
.liv-hero-carousel.has-carousel { aspect-ratio: 4 / 3; }
.liv-hero-carousel.has-carousel .liv-hero-slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 1.2s ease-in-out;
	pointer-events: none;
}
.liv-hero-carousel.has-carousel .liv-hero-slide.is-active { opacity: 1; pointer-events: auto; }
.liv-hero-carousel.has-carousel .liv-hero-slide img { height: 100%; aspect-ratio: auto; }

/* WHY: the dots sit ON the photo, so they need their own contrast floor — the client
   anticipated this ("may need a gradient behind them"). Applied on every slide rather than
   only where it fails, because the image underneath changes every 4s and a scrim that
   comes and goes would read as a flicker. Sized to clear the dot row, not the whole photo. */
.liv-hero-carousel.has-carousel::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	height: 140px;
	background: linear-gradient(to top, rgb(0 27 51 / 0.7), rgb(0 27 51 / 0));
	pointer-events: none;
	z-index: 1;
}
.liv-hero-dots {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 20px;
	z-index: 2;
	display: flex;
	justify-content: center;
	gap: 12px;
}
/* WHY: 17x18 transparent hit area with the visible circle drawn in ::after — the American
   Pool precedent, and necessary here because the divider's dot is only 7px, far below a
   usable tap target. The 7px/theme-03 circle is the divider motif exactly (same size and
   token as the .liv-rule mask above), so the pagination reads as the brand element the
   client asked for rather than a generic dot row. */
.liv-hero-dot {
	width: 17px;
	height: 18px;
	padding: 0;
	border: none;
	background: none;
	cursor: pointer;
	position: relative;
	display: inline-flex;
	transition: width 300ms ease;
}
/* WHY: the active dot stretches into a pill rather than just filling — client picked this
   over the fill-and-scale alternative on 2026-07-30. 51px is the American Pool ratio applied
   to our dot, not their number: their bar is 102px against a 14px dot (7.3x), and 7 x 7.3 =
   51. A literal 102px would be 14.5x our circle and would swamp the photo. Height stays 7px
   where apool grew 14 -> 19 — holding the diameter is what keeps this reading as the divider
   element, whose motif is dot-line-dot, so a pill at the circle's own height reads as the
   divider's LINE rather than as a generic progress bar.
   Exposed as a custom property because this number was tuned by eye and will likely be
   re-tuned once the client's real hero images land. */
.liv-hero-carousel { --liv-dot-bar-w: 51px; }
.liv-hero-dot.is-active { width: var(--liv-dot-bar-w); }
.liv-hero-dot::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background-color: var(--wp--preset--color--theme-03);
	transform: translate(-50%, -50%);
	opacity: 0.55;
	/* WHY: the slide underneath changes every 4s and slide 2 is a bright pool shot, so the
	   scrim alone cannot guarantee the brown reads. A 1px dark halo gives every dot an edge
	   against whatever image is behind it, without introducing a second colour. */
	box-shadow: 0 0 0 1px rgb(0 27 51 / 0.35);
	transition: opacity 300ms ease, width 300ms ease, border-radius 300ms ease;
}
.liv-hero-dot:hover::after { opacity: 0.8; }
.liv-hero-dot.is-active::after {
	opacity: 1;
	width: var(--liv-dot-bar-w);
	border-radius: 999px;
}
.liv-hero-dot:focus-visible { outline: none; }
.liv-hero-dot:focus-visible::after {
	opacity: 1;
	box-shadow: 0 0 0 2px var(--wp--preset--color--theme-01);
}

/* The dot row's outer bounds are FIXED, which is why the stretching bar does not jitter the
   layout: exactly one dot is ever wide, so the row is always 3x17 + 51 + 3x12 = 138px and
   stays centred (measured — bounds identical across all four active states, and dot 1 never
   moves). The bar therefore reads as sliding along a fixed track rather than as the row
   reflowing under it. Adding or removing a slide changes that constant, not the behaviour. */
/* The global reduced-motion block at the top of this file already zeroes transitions;
   liv-ui.js separately declines to auto-advance, so the dots stay usable as manual
   controls rather than the carousel becoming a dead single image. */
@media (min-width: 1024px) {
	.liv-home-hero { padding: 0 0 0 75px; grid-template-columns: 653fr 712fr; }
	/* WHY the inline padding is computed rather than the old fixed `75px … 16px`:
	   client 2026-08-05 pin 3 — "I think the hero content should be centered more in the quad;
	   I'm looking at this against the alignment of 'One-Partner Advantage' which looks great."
	   One-Partner is symmetric (measured 120/120 at 1512px, 358/358 at 2035px). The hero was
	   16px from the quad's left edge and 161px from its right at 1512 — and because the quad is
	   a `653fr` grid track while the copy has a fixed 560px measure, ALL the extra width landed
	   on the right as the viewport grew: 16 vs 412 at 2035px. It got visibly worse on big
	   screens, which is where the client was looking.
	   Centring the 560px column (the h1's max-width, i.e. the widest child) makes the gaps equal
	   at every width and keeps every child sharing one left edge, so the copy stays left-aligned
	   — it is the column that is centred, not the text.
	   max(32px, …) is the floor just above the 1024px breakpoint, where the track is narrower
	   than the column and the calc would otherwise go negative.
	   WHY 32px (was 16px) — markup.io pin 289 (Conor 2026-09-11): "There needs to be sitewide
	   consistency". The service heroes (.liv-svc-hero-content, further down) now run this SAME
	   formula — a capped copy column centred in the navy panel with a minimum gutter to the photo —
	   and 32px is the floor both use, so the two hero types cannot drift apart again. Only the
	   1024–~1380px band on the home page feels this (the calc already exceeds 32px above that). */
	.liv-hero-content {
		padding-block: 120px;
		padding-inline: max(32px, calc((100% - 560px) / 2));
	}
	/* hand the `display` preset back — pins 77 and 26 are mobile-only asks */
	.liv-home-hero h1 { font-weight: 400; letter-spacing: -0.06em; font-size: var(--wp--preset--font-size--display) !important; }
	/* WHY max-width 560 (was the base 510, briefly 533): client 2026-09-02 — first "the right edge
	   lines up with the right end of Performance-Driven", then "expand the width of the container
	   … to match the width of the heading". The second ask settles the ambiguity in the first:
	   they want the CONTAINER matched, not the optical ink edge. 560px is the h1's own max-width
	   (declared at the base .liv-home-hero h1 rule), so the two now share one measure and wrap on
	   exactly the same boundary — which also means a copy change can never desync them the way a
	   hand-measured number would. Keep these two values equal if either is ever retuned.
	   Consequence worth knowing: both blocks are ragged-right, so a given paragraph line can still
	   end past the heading's longest line (currently by ~17px) — that is the boxes agreeing, not a
	   misalignment. DESKTOP ONLY: below 1024 the hero stacks and the base 510px governs. */
	.liv-hero-sub { font-weight: 400; letter-spacing: 0.01em; max-width: 560px; } /* WHY 400 (was 700): client pin 190 (2026-08-31) — un-bold intro quads site-wide. WHY 0.01em (was -0.03em): client 2026-09-02 kerning ask — see the .liv-hero-sub note above the 1024 block. */
	.liv-hero-eyebrow { font-size: var(--wp--preset--font-size--medium); }
	/* WHY: Figma 33186:8214 — photo ends flush with the blue text panel (hero row 621px);
	   fixed 720px + negative margin made the image hang ~80px below the panel. */
	.liv-hero-media { height: 100%; }
	.liv-hero-media figure { height: 100%; }
	.liv-hero-media img { height: 100%; aspect-ratio: auto; }
	/* carousel: drop the mobile 4/3 box and go back to filling the row (see above) */
	.liv-hero-carousel.has-carousel { aspect-ratio: auto; }
}
/* @kindling:keep:end */

/* @kindling:keep:start */
/* WHY: LIVunLtd HOME sections 2-6 chrome. Section paddings + type sizes that differ
   between the mobile and desktop artboards (section titles 33px -> 79px, rules
   150x4 -> 112x7, wide/one-partner quotes 19 -> 33), grid stacking below 1024,
   line-pattern textures (overlay bands on Markets/One-Partner), and GF form
   skinning to the Figma field spec (white r4 inputs, brown pill submit). */

/* ---- shared section head ---- */
.liv-sec-title { font-size: var(--wp--preset--font-size--x-large); font-weight: 500; letter-spacing: -0.03em; line-height: 1.2; }
.liv-card-title { font-size: 1.5625rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1.2; }
.liv-sec-rule { width: 150px; border: none; margin: 0; opacity: 1; } /* height comes from the shared .liv-divider-shape mask (7px dots) */
@media (min-width: 1024px) {
	.liv-sec-title { font-size: var(--wp--preset--font-size--display); font-weight: 400; letter-spacing: -0.06em; line-height: 1.1; }
	.liv-sec-rule { width: 112px; }
}
.liv-sec-head-center { align-items: center; text-align: center; }
.liv-sec-head-center .liv-sec-rule { margin: 0 auto; }

/* ---- services grid ---- */
/* WHY: 2026-07-30 client round 3 (d) — "on the homepage it [the pattern] should appear
   behind Our Services and Markets We Serve only". This band had no texture before, so this
   is the one ADD in the round. Full bleed and no mask per rule (a); beige multiplier because
   the band is theme-05, same as Markets. Also lands on /services/, which shares .liv-svc and
   where it is the only patterned quad. */
.liv-svc { position: relative; padding: 40px 20px; }
.liv-svc::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-beige)); /* beige theme-05 band, full bleed */
	pointer-events: none;
}
.liv-svc > * { position: relative; }
.liv-svc > .liv-sec-head { margin-bottom: 24px; }
.liv-svc-grid { grid-template-columns: 1fr; }
.liv-card { overflow: hidden; }
.liv-card { gap: 16px !important; padding-bottom: 16px; }
.liv-card-body { padding: 0 16px; width: 100%; }
.liv-card-body .liv-chip img { width: 25px !important; }
/* WHY: client 2026-07-30 — "Our Services: arrow CTAs are not currently functional".
   Same result as .liv-market-card, reached a different way: that grid is a Query Loop so
   its post-title carries the link, while this grid is 6 hand-written cards (each with a
   per-card image that is not a featured image, which is what still blocks converting it).
   So the anchor was added to the card <h3> in wp_block 46 and is stretched from here —
   card and arrow both clickable, exactly ONE link in the accessibility tree. `position`
   is needed because .liv-card was static; `overflow: hidden` (card radius) clips the
   overlay to the same box, which is the box we want. */
.liv-card { position: relative; }
.liv-card .liv-card-title a {
	text-decoration: none;
	color: inherit;
}
.liv-card .liv-card-title a::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}
@media (min-width: 1024px) {
	.liv-svc { padding: 60px; }
	.liv-svc > .liv-sec-head { margin-bottom: 54px; }
	.liv-svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; row-gap: 16px; }
	.liv-card { gap: 24px !important; padding-bottom: 24px; }
	.liv-card-body { padding: 0 24px; }
	.liv-card-body .liv-chip img { width: 33px !important; }
}

/* ---- wide band ---- */
.liv-wide { padding: 20px; }
/* pin 9: only the .liv-on-blue variant gets a positioning context, because only it carries the
   pattern ::before. Plain .liv-wide is left unpositioned so nothing changes on home / services /
   markets. The `> *` rule is what keeps the cover and card above the texture — same pairing as
   .liv-values / .liv-tcards, and without it the pattern paints over the photo. */
.liv-wide.liv-on-blue,
.liv-wide.liv-on-cream { position: relative; }
.liv-wide.liv-on-blue > *,
.liv-wide.liv-on-cream > * { position: relative; }
.liv-wide-cover { border-radius: 16px; overflow: hidden; }
.liv-wide-cover { min-height: 263px !important; }
.liv-wide-card { padding: 24px; max-width: 350px; margin-left: auto; margin-right: auto; }
.liv-wide-quote { font-size: 1.1875rem; font-weight: 500; max-width: 302px; margin-left: auto; margin-right: auto; }
@media (min-width: 1024px) {
	.liv-wide { padding: 56px 60px; }
	.liv-wide-cover { min-height: 718px !important; }
	.liv-wide-card { padding: 50px; max-width: 892px; }
	.liv-wide-quote { font-size: var(--wp--preset--font-size--x-large); max-width: none; }
}
/* WHY: client 2026-07-30 — "divider length is shorter than the standard used elsewhere
   on the site." The callout box was pinning 80px against the shared 150/112 rule, so the
   width override is dropped and only the centering stays. */
.liv-wide-card .liv-sec-rule { margin: 0 auto; }

/* WHY: client pin 110 (2026-08-18) put a phone number and an email into this card's copy.
   At 390px the measure is ~300px, which is narrow enough to break "844-338-9900" after a
   hyphen — a wrapped phone number reads as two numbers and is harder to tap accurately.
   Applied to the links rather than the paragraph so only the contact tokens are protected
   and the sentence around them still wraps normally. The email is long enough to be worth
   the same guard: at 390 it fits on its own line, but a narrower phone would push it. */
.liv-wide-card a[href^="tel:"],
.liv-wide-card a[href^="mailto:"] { white-space: nowrap; }

/* ---- markets ---- */
.liv-markets { position: relative; padding: 40px 20px; }
.liv-markets::before {
	content: "";
	position: absolute;

	/* WHY: the wave was cropped to the lower-left 60x60% via inset, which
	   read as a soft corner wash only because a 12% grey wave has no hard
	   edge. A uniform woven tile would show that inset as a crisp
	   rectangle, so the crop becomes a mask fade on the same lower-left
	   axis — same composition, no seam. */
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-beige)); /* beige theme-05 band, full bleed */
	pointer-events: none;
}
.liv-markets > * { position: relative; }
.liv-markets > .liv-sec-head { margin-bottom: 24px; }
.liv-market-card { width: 100%; position: relative; padding: 16px 56px 16px 16px; }
/* WHY: client 2026-07-30 — "arrow CTAs are not currently functional, need to be wired up".
   This was blocked until the markets became liv_market posts with real URLs. The grid is now
   a Query Loop whose post-title is the only genuine link, so it gets stretched over the whole
   card: the card AND the arrow become clickable while exactly ONE link stays in the
   accessibility tree. Wrapping the card in an anchor instead would nest the title link inside
   it, which is invalid HTML. The chip is decorative (empty alt) and deliberately NOT a second
   link — a duplicate link to the same destination is noise for screen readers.
   The overlay sits above the absolutely-positioned chip, which is what makes the arrow
   clickable; hover/active states still key off .liv-market-card so they are unaffected. */
.liv-market-card .liv-card-title a {
	text-decoration: none;
	color: inherit;
}
.liv-market-card .liv-card-title a::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}
@media (min-width: 1024px) {
	.liv-markets { padding: 95px 60px; }
	.liv-markets > .liv-sec-head { margin-bottom: 54px; }
	/* WHY: Figma card is a fixed 320x237 with the arrow on its own row (33186:8340).
	   The chip is position:absolute (out of flow), so without a reserved bottom band
	   (24 pad + 33 chip + 16 gap = 73px) the card collapses to text height and the
	   arrow lands on the last line of copy. min-height pins the Figma box. */
	.liv-market-card { width: 320px; padding: 24px 24px 73px; min-height: 237px; }
}
.liv-market-card .liv-chip { position: absolute; right: 16px; bottom: 16px; margin: 0; }
.liv-market-card .liv-chip img { width: 25px !important; }
@media (min-width: 1024px) {
	.liv-market-card .liv-chip { right: 24px; bottom: 24px; }
	.liv-market-card .liv-chip img { width: 33px !important; }
}

/* ---- one-partner ---- */
.liv-onepartner { position: relative; padding: 30px 20px; }
.liv-onepartner::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.15 * var(--liv-line-pattern-fade-blue)); /* light-blue #D0DEDF band, full bleed */
	pointer-events: none;
}
/* WHY: 2026-07-30 client round 3 (b) "never use the pattern in two consecutive quads", plus
   (d) naming Our Services and Markets as the ONLY homepage bands. On the homepage this band
   is quad 5, directly under Markets at quad 4 — the one adjacency left after the heroes were
   dropped. It has to be page-scoped rather than removed outright, because the identical
   synced pattern (wp_block 49) is also quad 4 on /markets/campus-university/, where nothing
   precedes it and it stays. */
.home .liv-onepartner::before { display: none; }
/* WHY markets loses it too: client 2026-08-05 pins 40 + 55 — "Pattern should not be applied
   here" / "For all markets pages, this should not have the pattern", both on this One-Partner
   band. Read together with pins 39 + 56, which ADD the texture to the beige card band directly
   ABOVE it, the pair is not two conflicting opinions — it is the texture moving up one quad.
   That also keeps the standing 2026-07-30 round 3 rule (b), "never use the pattern in two
   consecutive quads": once the card band is textured, leaving this one textured would have
   broken it. The comment above is now out of date on one point — campus-university no longer
   keeps this band's pattern. */
body.single-liv_market .liv-onepartner::before { display: none; }
/* WHY the accountability variant loses it as well: client 2026-08-05 pin 67 — "This quad
   should not have the pattern", on the "Built Around Accountability" band. That band is
   .liv-onepartner.liv-accountability and appears on /our-approach/ only (checked every other
   page), so no scoping selector is needed beyond the variant class itself.
   Third pin in the same family — 40/55 stripped the markets One-Partner band, this strips the
   our-approach one. The client is consistently removing this texture from One-Partner quads. */
.liv-onepartner.liv-accountability::before { display: none; }
.liv-onepartner > * { position: relative; }
/* WHY: client mobile pin 27 (2026-08-12) — "Need to fix this empty spacing on mobile".
   wp_block 49 authors blockGap:84px, which is a sensible COLUMN gap for the desktop 2-up
   (and is re-stated as column-gap below). At mobile the grid collapses to one column and
   that same token becomes a ROW gap: measured 84px of dead air between the gold rule and
   the quote block, in a band only 369px tall. Row gap is pinned to spacing-70 (40px at
   this width) so the two stacked halves still read as separate without the void. */
.liv-onepartner-grid { grid-template-columns: 1fr; row-gap: var(--wp--preset--spacing--70); }
@media (min-width: 1024px) {
	.liv-onepartner { padding: 83px 120px; }
	.liv-onepartner-grid { grid-template-columns: 596fr 520fr; column-gap: 84px; }
}

/* ---- contact ---- */
.liv-contact-cover { min-height: 0 !important; padding: 40px 20px; }
.liv-contact-card { padding: 40px 24px; width: 100%; }
@media (min-width: 1024px) {
	/* WHY: cover is alignfull (photo edge-to-edge per 33186:8416); 120px side padding
	   keeps the card at x120/w1200 exactly where Figma puts it on the 1440 artboard. */
	.liv-contact-cover { min-height: 832px !important; padding: 80px 120px; }
	.liv-contact-card { padding: 40px; }
}
/* GF form skin per Figma contact card (white r4 fields, 24px row gap, brown pill submit) */
.liv-contact-card .gform_wrapper input[type="text"],
.liv-contact-card .gform_wrapper input[type="email"],
.liv-contact-card .gform_wrapper input[type="tel"],
.liv-contact-card .gform_wrapper select,
.liv-contact-card .gform_wrapper textarea {
	/* WHY: background-COLOR, not the `background` shorthand. GF Orbital gives the select its
	   only dropdown affordance as a background-image chevron (--gf-ctrl-select-icon) and sets
	   appearance:none, so the shorthand was resetting background-image to none and leaving a
	   bare white box the browser also draws no native arrow on. Root cause of the client's
	   2026-07-30 "Market Type dropdown is glitchy" report. */
	background-color: var(--wp--preset--color--theme-01);
	border: 1px solid rgba(0, 0, 0, 0.1);
	border-radius: 4px;
	padding: 8px;
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: var(--wp--preset--font-size--medium);
	width: 100%;
}
/* WHY: Figma 33186:8421 sizes the How Can We Help field 1120x139; client confirmed
   2026-07-30 "cut the textarea to Figma's 139px". The existing min-height:139px here had
   never actually applied — GF Orbital ships `textarea.large { min-block-size: 18rem }`
   (288px), a LOGICAL property, and the field carries .large, so the two collide on the same
   computed property and GF was winning. Hence !important on min-height, matching the
   precedent already set for GF's submit line-height further down.
   Two declarations, because GF sizes the control with LOGICAL properties and those beat
   physical `height` here no matter what we do — an inline `height: 260px !important` still
   measured 139px, so setting `height` at all is pointless on this control:
     · `--gf-local-height` is the var GF's own `block-size` rule reads, so overriding it
       sets the size through GF's mechanism instead of fighting it (its default is 130px;
       pinning it means a future GF default change cannot quietly resize the field).
     · `min-height !important` is still needed to beat `textarea.large { min-block-size:
       18rem }` in the foundation sheet, which is what was really forcing 288px — the old
       plain `min-height: 139px` here had never once applied.
   NOTE: this field is not user-resizable and was not before this change either. GF declares
   `resize: vertical`, but the grabber works by writing an inline `height`, which loses to
   GF's own `block-size` — verified at HEAD too, so it is not a regression from the 139px
   cut. Raise it separately if a drag handle is actually wanted. */
.liv-contact-card .gform_wrapper textarea {
	--gf-local-height: 139px;
	min-height: 139px !important;
}
/* WHY: 40px box per Figma. Our own `line-height: 38px` is dropped — it only duplicated
   GF's framework value (--gf-ctrl-size-md: 38px, which GF applies itself), so carrying a
   second copy just meant the box and its leading could drift apart on any GF upgrade.
   Vertical centring is left to the fixed height, which is what a single-line control does
   natively. padding-right clears GF's chevron so long market names cannot run under it. */
.liv-contact-card .gform_wrapper select {
	height: 40px;
	padding-top: 0;
	padding-bottom: 0;
	padding-right: 32px;
}
/* Match the select to the other five controls while it is still showing its hint —
   client 2026-08-18, "the market type dropdown is a different color than the other inputs".
   The box was never the problem: background and border already matched exactly. The TEXT
   did — the inputs render their hint through ::placeholder at GF's 70% placeholder colour,
   while the select shows a real <option>, which is full-opacity control text. So the one
   field looked filled-in while the other five looked empty.
   :has() rather than :invalid — GF does not mark this select `required` at the HTML level,
   so :invalid never matches it. The placeholder option is the one with value="", and the
   rule stops applying the moment a real market is chosen, which is the behaviour we want.
   :has() is already relied on for the sticky header, so this is not a new dependency.
   Both colours come from GF's own variables, so they cannot drift from the inputs. */
.liv-contact-card .gform_wrapper select:has(option[value=""]:checked) {
	color: var(--gf-ctrl-placeholder-color);
}
/* Keep the open list at full-strength text — only the closed, unset control is greyed. */
.liv-contact-card .gform_wrapper select option { line-height: normal; color: var(--gf-ctrl-color); }
/* Placeholder size — client pin 116 follow-up (2026-08-18), "the placeholder text should
   match the Figma". The STRINGS already match Figma exactly (33186:8416 field-text layers:
   "Full Name *", "Email *", "Phone *", "Company *", "Market Type *", "How Can We Help? *").
   What did not match is the size: this build shows those strings AS placeholders, and GF
   styles ::placeholder independently of the control — it renders them at 14px while the
   input itself is 16px and the design specifies 16px. Pin it to the control's own size so
   the two cannot drift again on a GF upgrade, which is exactly how the submit button broke.
   COLOUR IS DELIBERATELY LEFT ALONE: Figma's layer is #000000 because in the design it
   represents FILLED text, not a placeholder. Rendering an empty field's hint at solid black
   would make empty fields read as completed. The current 70% is the safer default —
   flagged for the designer rather than silently matched. */
/* Override GF's VARIABLE, not its rule. GF's framework sheet sets
   `--gf-ctrl-placeholder-font-size: 14px` and applies it from its own high-specificity
   `::placeholder` selector, so a competing ::placeholder rule here just loses — measured:
   a `.liv-contact-card .gform_wrapper input::placeholder` pin had no effect on the inputs.
   Feeding the variable makes GF's own rule compute 16px, which is the same tactic the
   textarea uses with --gf-local-height further up.
   (Also worth recording: `:is(input, textarea)::placeholder` silently does not apply to the
   inputs at all — it only took on the textarea. Do not use :is() before a pseudo-element.) */
.liv-contact-card .gform_wrapper {
	--gf-ctrl-placeholder-font-size: var(--wp--preset--font-size--medium);
}
.liv-contact-card .gform_wrapper .gform_fields { grid-row-gap: 24px; }
.liv-contact-card .gform_wrapper .gfield_label {
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-weight: 700;
	color: var(--wp--preset--color--theme-02);
}
/* WHY: .liv-contact-cover (core/cover) sets color:#fff on everything inside it; the
   inputs and labels above re-pin their own colour but GF's confirmation div does not,
   so "Thank you for reaching out..." rendered white-on-cream (invisible) after submit.
   Client test 2026-09-16. Match the field-label token. */
.liv-contact-card .gform_wrapper .gform_confirmation_message {
	color: var(--wp--preset--color--theme-02);
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: var(--wp--preset--font-size--medium);
}
/* WHY: Conor killed the /thank-you/ pages on the redirect matrix (2026-09-16,
   "I don't want a thank you page URL... include the deck download after
   submitting the form"), so on the four lead-magnet pages the download link
   arrives INSIDE the confirmation message — it is that page's whole payoff and
   has to read as a button, not as a run of body copy. Matches the
   .gform_button pill below (theme-03 on theme-01, 999px) so submit and
   download look like one family. !important for the same reason as the GF
   Orbital pins further down: Orbital styles anchors inside the confirmation at
   a higher specificity than a plain class selector. */
.liv-contact-card .gform_wrapper .gform_confirmation_message a.liv-resource-link {
	display: inline-block;
	margin-top: 8px;
	background-color: var(--wp--preset--color--theme-03) !important;
	color: var(--wp--preset--color--theme-01) !important;
	text-decoration: none !important;
	border-radius: 999px;
	padding: 12px 20px;
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-weight: 700;
	letter-spacing: 0.02em;
	font-size: var(--wp--preset--font-size--medium);
	transition: background 150ms ease;
}
.liv-contact-card .gform_wrapper .gform_confirmation_message a.liv-resource-link:hover {
	background-color: var(--wp--preset--color--theme-07) !important;
}
.liv-contact-card .gform_wrapper .gform_button {
	background-color: var(--wp--preset--color--theme-03);
	color: var(--wp--preset--color--theme-01);
	border: none;
	border-radius: 999px;
	padding: 12px 20px;
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-weight: 700;
	letter-spacing: 0.02em;
	font-size: var(--wp--preset--font-size--medium);
	cursor: pointer;
	transition: background 150ms ease;
}
.liv-contact-card .gform_wrapper .gform_button:hover { background-color: var(--wp--preset--color--theme-07); }
.liv-contact-card .gform_wrapper { margin: 0; }
/* GF Orbital loads its own high-specificity button styles; pin the Figma pill.
   MATCH BOTH ELEMENT TYPES — client pin 116 (2026-08-18) "it looks like the CTAs have
   changed, can you look at this sitewide for the forms please". Nothing in this theme
   changed: Gravity Forms 3.0.2 renders the submit as <button class="gform_button">, where
   older versions emitted <input type="submit">. Every pin below was written against the
   input selector, so on the GF upgrade they ALL silently stopped matching and the button
   fell back to GF's own default — #204CE5 blue, 38px tall, 14px/500, 3px radius, no
   uppercase. Verified identical on local and BLD, both on GF 3.0.2.
   `:is(input[type="submit"], button)` keeps the same specificity as the old selector while
   surviving a change back, so this cannot regress the same way twice. */
.liv-contact-card :is(input[type="submit"], button).gform_button {
	background-color: var(--wp--preset--color--theme-03) !important;
	color: var(--wp--preset--color--theme-01) !important;
	border: none !important;
	border-radius: 999px !important;
	padding: 12px 20px !important;
	font-family: var(--wp--preset--font-family--proxima-nova) !important;
	font-size: var(--wp--preset--font-size--medium) !important;
	font-weight: 700 !important;
	letter-spacing: 0.02em !important;
	/* The Figma pill (33186:10162) is uppercase and every other CTA on the site renders that
	   way. This currently LOOKS right only because the GF form's button label happens to be
	   stored as "SUBMIT FORM"; rename it to "Submit form" in the form settings and it would
	   render lowercase while nothing else does. Pin the case here so the label text is free. */
	text-transform: uppercase !important;
	/* WHY: client 2026-07-30 "resize CTA" — the submit was 40px against every other CTA's
	   52px. The shared line-height pin below can't reach it: GF's framework rule
	   (.gform-theme--framework.gform-theme.gform_wrapper input[type=submit].button.gform_button)
	   sets line-height from --gf-local-line-height at a specificity nothing sane matches, so
	   the value joins the !important pins here like the rest of the GF skin. */
	line-height: 1.4375 !important;
}
@media (min-width: 1024px) {
	.liv-contact-card :is(input[type="submit"], button).gform_button { line-height: 1.75 !important; }
}
.liv-contact-card :is(input[type="submit"], button).gform_button:hover { background-color: var(--wp--preset--color--theme-07) !important; }
/* click + focus states per the Figma button matrix (33186:10371/10377) */
.liv-contact-card :is(input[type="submit"], button).gform_button:active { background-color: var(--wp--preset--color--theme-05) !important; color: var(--wp--preset--color--theme-06) !important; }
.liv-contact-card :is(input[type="submit"], button).gform_button:focus-visible { outline: 2px solid var(--wp--preset--color--theme-04) !important; outline-offset: -2px !important; }

/* WHY: Figma 33186:10162 "simple button" (pattern refs 33186:10344 /
   33191:12281) — every filled button carried the LIV texture multiply-blended
   over the state color, on all states (neutral/hover 33186:10364ff, click
   33186:10371, focus 33186:10377); Ghost/Subtle are unfilled and were excluded.
   2026-07-29 swapped the wave for the client's LIV-Line-Pattern on a dedicated
   936x504 cut tiled at 468px, with 14% baked into the PNG alpha because the GF
   submit is an <input> and cannot carry a pseudo-element.

   REMOVED 2026-07-30 — client: "remove the brand pattern from Request a Proposal
   and all other CTAs", confirmed by email and superseding Coeli's "the buttons
   look OK" from the same morning. Buttons are now flat state color, which is
   what theme.json's button element already emits, so the rules are deleted
   rather than overridden — nothing here has to fight the GF Orbital pins.
   assets/images/liv-line-pattern-btn.png is now UNREFERENCED (kept on disk; it
   is the only asset carrying the 14%-alpha cut, so restoring is a revert of
   this hunk). The band tile --liv-line-pattern is unaffected. */

/* WHY: client 2026-07-30 — "the Our Approach CTA looks too small, should be the same size
   as CTAs elsewhere on the site", plus "resize CTA" on the form submit. Root cause was not
   size but leading: theme.json pins the button element to line-height 1 (a 40px box at
   16px/12px padding), and only the header Request-a-Proposal button escapes it, carrying a
   1.75 block attr from its DB pattern that yields the 52px Figma box (33186:10162, and the
   contact submit at 156x52 in the home desktop tree). Rather than bolt that attr onto each
   button one at a time — and the GF submit is an <input>, so it cannot take one at all —
   the 1.75 becomes the default here, which lands every CTA on 52px and makes new buttons
   correct without an attr. Specificity has to clear theme.json's
   `:root :where(.wp-element-button, ...)`, hence the :root prefix; the header button's own
   inline 1.75 still wins over this and agrees with it.

   Per breakpoint, because the leading is what sets the box: mobile buttons are 47px in
   Figma (home tree-mobile, 138x47 throughout) and desktop 52px, on the same 16px text and
   12px vertical padding — so 23/16 = 1.4375 and 28/16 = 1.75. Mobile was previously 40px
   off the line-height-1 default; it moves to its Figma value here rather than inheriting
   desktop's 52. */
:root .wp-element-button,
:root .wp-block-button__link {
	line-height: 1.4375;
}
@media (min-width: 1024px) {
	:root .wp-element-button,
	:root .wp-block-button__link {
		line-height: 1.75;
	}
}

/* WHY: Figma button styles map row 2 (33191:12278 neutral / 12282 hover / 12285 click /
   12288 focus) — the card arrow chips are buttons: theme-03 circle at rest, theme-07 on
   hover, theme-02 (navy) on click, theme-02 + 2px theme-03 ring on focus. The DB patterns
   render each chip as ONE baked SVG <img> (circle + arrow), which can't restate, so the
   circle is painted on the figure and the arrow masked on ::after; the img keeps the
   25/33px layout box (motion.css width pins above) but is hidden. Cards are not links yet
   (most services/markets have no page) — hover/click read from the card, and the
   focus-visible rule is pre-wired for whenever a wrapping link lands in the patterns. */
figure.liv-chip {
	position: relative;
	border-radius: 9999px;
	background-color: var(--wp--preset--color--theme-03);
	transition: background-color 180ms ease;
}
figure.liv-chip img { visibility: hidden; }
figure.liv-chip::after {
	content: '';
	position: absolute;
	inset: 0;
	background-color: var(--wp--preset--color--theme-01);
	-webkit-mask: url(../images/liv-chip-arrow.svg) no-repeat center / contain;
	mask: url(../images/liv-chip-arrow.svg) no-repeat center / contain;
}
.liv-card:hover figure.liv-chip,
.liv-job-card:hover figure.liv-chip,
.liv-market-card:hover figure.liv-chip { background-color: var(--wp--preset--color--theme-07); }
.liv-card:active figure.liv-chip,
.liv-job-card:active figure.liv-chip,
.liv-market-card:active figure.liv-chip { background-color: var(--wp--preset--color--theme-02); }
a:focus-visible figure.liv-chip,
.liv-card:focus-within figure.liv-chip,
.liv-job-card:focus-within figure.liv-chip,
.liv-market-card:focus-within figure.liv-chip {
	background-color: var(--wp--preset--color--theme-02);
	box-shadow: 0 0 0 2px var(--wp--preset--color--theme-03);
}
/* WHY: client 2026-07-30 — "add animation to the arrows (e.g. a 'bounce') to make it
   clearer they're clickable", on both the Our Services and Markets We Serve cards. Two
   nudges then a rest, rather than a continuous jitter: the same review calls the site
   "flat and static" but also asks for SUBTLE movement, and 13 arrows oscillating
   nonstop reads as noise. The long 0%/60% hold is the pause, so one 1.6s cycle is
   nudge-nudge-wait.
   3px is safe inside the circle: liv-chip-arrow.svg is a 33x33 viewBox whose glyph spans
   x 8.47-24.44, i.e. ~8.5px of clearance each side (~6.4px once scaled to the 25px mobile
   chip), so the tip never approaches the edge — the figure has no overflow clip.
   Driven by the card, matching the background-color states directly above, and paired
   with focus-within so keyboard users get the same cue. The global
   prefers-reduced-motion block at the top of this file already neutralises it. */
/* WHY the nudges sit at the FRONT of the cycle: client 2026-08-05 pin 6 — "I like the
   arrow animation where it moves, but can that happen as soon as we enter hover state
   over it?" The original ran nudge-nudge in the last 40% of the cycle, so hovering bought
   0.96s of nothing before the first move and the cue read as broken on a quick hover.
   Same 1.6s rhythm and same nudge-nudge-wait shape — the rest is simply moved to the tail,
   which is also where it belongs for a loop that starts on hover-enter. */
@keyframes liv-chip-nudge {
	0%, 20%, 40%, 100% { transform: translateX(0); }
	10% { transform: translateX(3px); }
	30% { transform: translateX(2px); }
}
.liv-card:hover figure.liv-chip::after,
.liv-job-card:hover figure.liv-chip::after,
.liv-market-card:hover figure.liv-chip::after,
a:focus-visible figure.liv-chip::after,
.liv-card:focus-within figure.liv-chip::after,
.liv-job-card:focus-within figure.liv-chip::after,
.liv-market-card:focus-within figure.liv-chip::after {
	animation: liv-chip-nudge 1.6s cubic-bezier(0.3, 0, 0, 1) infinite;
}

/* WHY: client 2026-07-30 round 2, answering the ambiguous "center the Submit button
   vertically" note — "center the submit button between the How Can We Help text area and
   the bottom of the card." The band between the textarea's bottom edge and the card's
   bottom edge is the footer's top margin plus the card's bottom padding: 8 + 40 = 48px,
   with the 52px button sitting hard against the bottom of it. Splitting that 48 evenly
   (24 above, 24 below) centres the button in the band and, because it only redistributes
   space that already existed, leaves the card's outer box EXACTLY as it was — no change to
   card height, and no reflow of the 832px cover. Both values are set here together so the
   pairing is obvious; changing one without the other de-centres it.
   Expressed as margin/padding rather than a fixed offset so it survives the textarea being
   resized — which is still an open question (live 288px vs Figma 139px). */
.liv-contact-card .gform_wrapper .gform_footer { margin: 24px 0 0; padding: 0; }
.liv-contact-card { padding-bottom: 24px; }

/* ---- footer ---- */
/* WHY the bottom padding: the mobile action bar (pin 24) is position:fixed, so it would
   otherwise sit on top of the last footer row. Padding on .liv-footer rather than body so
   the cream background extends behind the bar instead of leaving a strip of body colour. */
.liv-footer { padding: 40px 20px calc(20px + var(--liv-mobile-bar-h, 64px)); }
/* WHY: client mobile pin 28 (2026-08-12) — "Let's stack and center the mobile footer
   hierarchy". .liv-footer-main is a core flex layout with flexWrap:wrap +
   justifyContent:space-between, which at 390px left-aligned the logo, links and badge but
   flung the LinkedIn icon to the right edge (measured x=306 against x=20 for everything
   else). Column + centre replaces the space-between split; the legal row gets the same
   treatment or the copyright and the four policy links stay pinned to opposite edges. */
.liv-footer-main {
	row-gap: 32px;
	margin-bottom: 40px;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	text-align: center;
}
.liv-footer-legal { justify-content: center; text-align: center; }
.liv-footer-links { align-items: center; }
.liv-footer-logo img { width: 180px; height: auto; }
.liv-footer-link a, .liv-footer-legal a { text-decoration: none; }
.liv-footer-link a { color: var(--wp--preset--color--theme-03); }
.liv-footer-legal { row-gap: 8px; }
/* WHY: 2026-07-30 client round 3 — "change the navy color tertiary navigation elements to
   black to simplify", listing the copyright, Terms of Use, Privacy Policy, Accessibility and
   Your Privacy Choices. Only the LINKS were navy: the paragraphs already carry theme-06
   (which is #000000) from the footer part's block attrs, but the anchors inside them took
   theme-02 from theme.json's link element. So this pins the anchors rather than touching the
   markup, and the copyright line — the one item with no link — already rendered black and is
   unchanged. :hover is pinned too, or the links would flick back to navy on hover, which is
   the opposite of "simplify". */
.liv-footer-legal a,
.liv-footer-legal a:hover,
.liv-footer-legal a:focus { color: var(--wp--preset--color--theme-06); }
@media (min-width: 1024px) {
	.liv-footer { padding: 60px 80px 20px; }
	.liv-footer-logo img { width: 242px; }
	/* undo the pin 28 mobile stack — desktop keeps the Figma row */
	.liv-footer-main {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		text-align: left;
	}
	.liv-footer-legal { justify-content: space-between; text-align: left; }
	.liv-footer-links { align-items: flex-start; }
}
/* WHY: user direction 2026-07-23 — USA Today badge renders GREEN. Figma 33186:8195
   authors the badge as a color-masked silhouette (there in theme-03), so same technique:
   the uploaded mono PNG becomes the mask, color lives here. PROVISIONAL green —
   swap this one value when the designer supplies the exact hex. */
figure.liv-footer-award { position: relative; }
figure.liv-footer-award img { visibility: hidden; }
figure.liv-footer-award::after {
	content: '';
	position: absolute;
	inset: 0;
	/* WHY: client 2026-07-30 — "the USA Today Top Workplaces badge is showing green,
	   should be brown to match Figma." This resolves the open provisional-green
	   question: Figma 33186:8195 authors the badge in theme-03, so the mask takes the
	   token rather than the stand-in #2e7d32 that was holding the slot. */
	background-color: var(--wp--preset--color--theme-03);
	-webkit-mask: url(/wp-content/uploads/2026/07/twp-award.png) no-repeat center / contain;
	mask: url(/wp-content/uploads/2026/07/twp-award.png) no-repeat center / contain;
}
/* WHY: client 2026-08-05 pin 16 — "This should be bottom corner aligned", pinned to the
   LinkedIn icon. .liv-footer-main is a core flex layout with verticalAlignment:center, so the
   64px icon floated in the middle of a row whose height is set by the award badge beside it.
   align-self drops just this one item to the row's bottom edge and leaves the logo and link
   column centred, which is what the pin asks for — the group's own alignment is untouched.
   Pairs with pin 15 (badge 97 -> 126px): the badge defines the row height, so it decides
   where "bottom" is. Changing either alone means aligning this twice. */
/* DESKTOP ONLY since pin 28 (2026-08-12): .liv-footer-main is flex-direction:column at
   mobile now, where align-self:flex-end means the RIGHT edge, not the bottom — it would
   undo the centring pin 28 asks for. The cross axis only means "bottom" in the row layout
   this pin was written against. */
@media (min-width: 1024px) {
	.liv-footer-main > figure.liv-footer-social { align-self: flex-end; }
}
/* align-self alone leaves the ICON 6px above the badge's bottom edge even though the figure
   is flush: core wraps a linked image in an inline-block <a>, so the figure box is 70px tall
   for a 64px icon and the difference is inline descender space underneath. The client is
   looking at the icon, not the box, so the gap has to go too. */
/* WHY min 40x40 + centring, MOBILE (the desktop block below shrinks it back): Alex 2026-09-18 — "someone's gotta have
   a small thumb to hit that facebook icon in the middle". Literal, and measurably so: the bare Facebook "f" is only
   12.9px wide (the set is normalised by height, so the narrowest glyph gets the smallest hit area), which fails the
   24x24 WCAG 2.5.8 minimum outright. The <a> is the tap target and it shrink-wrapped the glyph, so padding it out to
   40x40 gives every icon the same thumb-sized target WITHOUT changing how big the glyph draws. flex centring also
   supersedes the display:block below — both kill the inline descender space, this one just also centres the glyph in
   its target. The 40px target is what sets the mobile spacing too, hence gap: 0 on the row — see the group rule. */
figure.liv-footer-social > a { display: flex; align-items: center; justify-content: center; min-width: 40px; min-height: 40px; }
/* WHY .liv-footer-socials: every footer (wp_template_part 51 footer, 367 footer-fr, 1226 footer-fitness-ca) wraps its social
   icons in one flex Group so row/stack geometry is a single object. Icon SET per Conor 2026-09-16, superseding the
   09-14 CA-only set: ALL THREE footers now carry LinkedIn + Facebook + Instagram (attachments 45 / 1231 / 1233).
   The ONLY remaining difference is the LinkedIn URL — the Canada footer (1226, swapped in by inc/liv-page-footer.php)
   points at /company/livunltdcanada/, the site-wide footers at /company/liv-unltd/. That one URL is the entire reason
   1226 still exists as a separate part, so do not "simplify" it away by folding it back into 51. */
/* WHY gap: 0 on mobile and NOT the 22px the desktop column uses: the 40x40 tap targets on the <a> above already carry
   the spacing here. Each icon sits in a 40px box, so the visible space between two glyphs is 40 - (w1 + w2) / 2 ~= 21.6px
   — the same "tad more" as desktop, arrived at by padding rather than gap. Adding a real gap on top would stack with
   that and blow the row out to ~44px. The trade-off is that `gap` no longer reads as the visual spacing on mobile;
   it is 0 precisely so the tap targets sit edge to edge and never overlap, which is what stops a thumb aimed at
   Facebook landing on LinkedIn. Change the min-width above, not this, to retune mobile spacing. */
.liv-footer-main > .liv-footer-socials { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: center; gap: 0; } /* WHY 24px icons (the size is a per-image height block attr, NOT set here; it has run 64px -> 40px -> 24px): Alex 2026-09-18 — "can we just pull out the icons and make them brown?", supplying bare brown glyphs (attachments 1379/1381/1383) to replace the brown rounded-square tiles with knocked-out white glyphs (45/1231/1233). Dropping the tile drops its padding too, so 40px had to come down with it: the glyph inside the old 40px tile measured ~22px, and reusing 40px would have rendered a glyph nearly twice the weight of the one it replaced. 24px holds the previous optical weight and matches the 24x24 bare-icon frames Figma already carries in the footer's unbuilt "Social links" row (33186:8417). Three 24px glyphs + two 12px gaps = 96px, so the stack is now SHORTER than the 126px award badge where it used to be taller at 144px — which is why the align-self below is center and no longer flex-start. Applies to ALL THREE footers (51 EN, 367 FR, 1226 CA). */ /* mobile: centred row, the seat the lone LinkedIn figure takes in the default footer's column stack (pin 28) */
@media (min-width: 1024px) {
	/* WHY column + flex-end DESKTOP ONLY: Alex 2026-09-14 — "vertically stack the icons in the right column". Mirrors the
	   single-figure align-self rule above, which is also desktop-only, so the mobile stack stays centred like every other footer. */
	/* WHY align-items: center (was flex-end): since 2026-09-18 the icons are bare glyphs, not uniform 40px tiles, so
	   their widths now differ (LinkedIn 23.9px, Instagram 24px, Facebook 12.9px — the designer normalised the set by
	   HEIGHT, see the height:24px block attrs). Right-aligning unequal widths staggered the Facebook "f" off the shared
	   axis; centring seats each glyph in the column the way Figma's 24x24 social frames do. */
	.liv-footer-main > .liv-footer-socials { align-self: flex-end; flex-direction: column; align-items: center; gap: 22px; }
	/* WHY 22px (was 12px): Alex 2026-09-18 — "can you add maybe 10 pixels in between?" on the vertical stack, pre-empting
	   a note from Conor. Straight 12 + 10. Stack goes 96px -> 140px, still under the 126px badge's 166px figure box, so
	   the centring above is unaffected. Desktop is a mouse target, so the 40x40 tap box from mobile is dropped here and
	   the glyphs shrink-wrap again — otherwise the 40px boxes would add ~16px of their own and the gap would read 38px. */
	.liv-footer-socials > figure.liv-footer-social > a { min-width: 0; min-height: 0; }
	/* WHY :has() split, Alex 2026-09-14 evening — "can the linkedin icon be aligned to the bottom like it was originally?":
	   a LONE tile takes the pin-16 bottom-corner seat with the award centred in the row; a stack of two or more keeps the
	   top-aligned award + top-aligned column asked for earlier in the day. The parts share .liv-footer-socials with no
	   distinguishing class, so the icon count is the selector; :has() is supported everywhere this build targets.
	   INERT since 2026-09-16: every footer now carries three icons, so the >= 2 branch always wins. Side effect worth
	   knowing — 51/367 moved from the bottom-corner seat to the top-aligned treatment purely by gaining icons, which is
	   a real visual change nobody explicitly asked for. Kept rather than deleted because it is what makes a footer
	   degrade correctly if a client ever drops back to a single icon. */
	/* WHY center, superseding the flex-start above: Alex 2026-09-18 — "can we center this against the rest of the footer?
	   the column needs to be pushed down", with a red line drawn through the row's mid-axis. Measured before: the row
	   centres on 747.1 and the logo, links and award badge all sat exactly there, but the top-pinned icon column centred
	   on 736 — 11.1px high, which is the gap the line called out. center puts it on the same axis as everything else and
	   holds there now the stack is 96px (3x24 + 2x12) instead of 144px, i.e. shorter than the badge rather than taller. */
	.liv-footer-main > .liv-footer-socials:has(> figure + figure) { align-self: center; }
	/* The award figure is the tallest item in the row, so it defines the flex line and align-self is a no-op for it —
	   centred here only so the row reads as one rule rather than leaving a stale flex-start to puzzle over later. */
	.liv-footer-main:has(> .liv-footer-socials > figure + figure) > figure.liv-footer-award { align-self: center; }
}
.liv-footer-socials > figure.liv-footer-social { margin: 0; }
/* WHY width: auto — the 2026-09-18 bare glyphs are sized by the block's height attr (24px) alone, because the three SVGs
   share a height but NOT a width and any fixed width would squash one of them. An <img> given only a height keeps its
   INTRINSIC width, though: core ships `.wp-block-image img { height: auto }` but never declares width, so these boxes
   measured 169/101/188px wide (the SVGs' own width attrs) with the glyph letterboxed in the middle of all that empty
   space — which dragged the column to 188px and pulled the icons off the footer's right edge. Declaring width auto lets
   it follow the height down the aspect ratio. Must out-specify `.wp-block-image img`, hence the figure in the selector. */
.liv-footer-socials > figure.liv-footer-social img { width: auto; }

/* WHY: Figma 32993:283 — CPRA toggle glyph (bronze pill, white chevrons) sits 8px
   before "Your Privacy Choices"; glyph is decorative so it rides the link's ::before */
.liv-privacy-choices a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}
.liv-privacy-choices a::before {
	content: '';
	flex-shrink: 0;
	width: 39px;
	height: 20px;
	background: url(../images/liv-privacy-toggle.svg) no-repeat center / contain;
}
/* @kindling:keep:end */

/* @kindling:keep:start */
/* WHY: LIVunLtd inner-page section chrome (About / Our Approach / Services x2 /
   Markets C&U). Same rationale as the HOME blocks: responsive geometry the
   spacing presets cannot express, line-pattern textures, and the hub-and-spoke diagram. */

/* ---- FAQ accordion (all six service pages) ---- */
/* WHY: Figma 33478:953, the FAQ artboard at the far right of the Internal LIVunLtd Dev page.
   Built on core/details rather than a custom block so every question stays editable in the Site
   Editor AND the answer text is in the DOM whether or not the item is open. That second point is
   the whole reason this section exists: the copy doc adds it as an AEO play, to get quoted by
   answer engines, and a JS-built accordion that injects its answers on click gives them nothing
   to read.

   Background is theme-05 cream under a theme-04 wash, per the Figma fill
   (linear-gradient(14.78deg, rgba(208,222,223,0) 1.72%, rgb(208,222,223) 43.13%) over #F0EFE9);
   rgba(208,222,223,0) is theme-04 at zero alpha, which no token can express.

   Texture opacity follows the site convention, NOT the Figma frame. Figma has the pattern at a
   flat 3%; the shared multiplier resolves to calc(0.12 * 0.3375) = 4.05%. The multipliers exist
   because the client cut pattern opacity twice by pin (2026-08-05 and 2026-08-07), and hard-coding
   3% here would silently opt this band out of the next adjustment. Blue multiplier because the
   band reads as a theme-04 blue band, matching .liv-markets.

   Adjacency: the pattern rule is one patterned quad per page. On all six service pages this band
   sits between Engage (.liv-split, unpatterned) and the contact band (.liv-contact, unpatterned),
   and the only other patterned quad is Wide, three sections up. No collision. */
.liv-faq { position: relative; padding: 40px 20px; background-color: var(--wp--preset--color--theme-05); background-image: linear-gradient(14.78deg, rgba(208, 222, 223, 0) 1.72%, var(--wp--preset--color--theme-04) 43.13%); }
.liv-faq::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-blue)); /* light-blue theme-04 band, full bleed */
	pointer-events: none;
}
.liv-faq > * { position: relative; }
.liv-faq .liv-sec-head { margin-bottom: 32px; }

/* Card: Figma 24px padding, 16px radius, theme-08 surface, shadow-md from the design's effect
   token (0 2px 4px -2px #1018280F, 0 4px 8px -2px #1018281A). */
.liv-faq-item {
	background-color: var(--wp--preset--color--theme-08);
	border-radius: 16px;
	padding: 24px;
	box-shadow: 0 2px 4px -2px rgba(16, 24, 40, 0.06), 0 4px 8px -2px rgba(16, 24, 40, 0.1);
}

/* WHY the marker is killed three ways: `display: block` covers Firefox, `list-style: none` covers
   the spec-compliant path, and the -webkit pseudo-element covers Safari, which honours neither. */
.liv-faq-item > summary { display: block; list-style: none; cursor: pointer; }
.liv-faq-item > summary::-webkit-details-marker { display: none; }

/* The summary is the flex row: question left, chevron right, aligned to the first line so a
   two-line question does not drag the chevron down to its centre (Figma items-start). */
.liv-faq-item > summary {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 16px;
	color: var(--wp--preset--color--theme-02);
	font-family: var(--wp--preset--font-family--cormorant-garamond);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 700;
	letter-spacing: -0.03em;
	line-height: 1.2;
}
.liv-faq-item > summary::after {
	content: "";
	flex: 0 0 24px;
	width: 24px;
	height: 24px;
	background: url(../images/liv-faq-chevron.svg) center / 24px 24px no-repeat;
	transition: transform 0.2s ease;
}
.liv-faq-item[open] > summary::after { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .liv-faq-item > summary::after { transition: none; } }

/* Answer copy: Figma step-0 / 1.35 / black, 8px under the question. Selector is "any child that
   is not the summary" so an editor can add a second paragraph or a list without new CSS. */
.liv-faq-item > *:not(summary) { margin-top: 8px; margin-bottom: 0; color: var(--wp--preset--color--theme-06); font-size: var(--wp--preset--font-size--medium); line-height: 1.35; }
.liv-faq-item > *:not(summary) ~ *:not(summary) { margin-top: 12px; }

/* ---- page intro band (navy, centered) ---- */
/* WHY: pattern removed 2026-07-30 (client round 3, rule c) — this band carries two long
   paragraphs, so it is exactly the "minimal written content" test failing. */
.liv-intro { position: relative; padding: 40px 20px; overflow: hidden; }
.liv-intro > * { position: relative; }
.liv-intro-eyebrow { font-size: 0.875rem; }

.liv-intro-text { max-width: 876px; font-weight: 400; letter-spacing: 0.01em; } /* WHY 400 (was 500) + 0.01em: client 2026-09-02 (text round) — "That is the font size, weight, etc. we are looking for across every intro quad. It could be helpful to increase kerning a bit." The reference screenshot is the HOME hero sub-paragraph, so .liv-hero-sub is the target style and every other intro quad has to match it: 400 weight, `large` (25px) Cormorant, lh 1.2 — all six intro blocks already carry identical block attrs (fontSize large / cormorant-garamond / lineHeight 1.2), so the only thing that ever differed was weight and tracking HERE. Kerning: the desktop rules tracked -0.03em; opened to 0.01em at BOTH breakpoints so the ask reads as an actual increase over default rather than just removing the tightening (0.25px/char at 25px). Same value on both classes on purpose — the client is asking for ONE intro-quad style, not two. */

/* Service-page intro band spacing — client 2026-08-05 pins 47 + 49.
   Pin 47: "Can we tighten the padding between H1 and H2 across all service pages".
   Pin 49, on /services/fitness-equipment-sales/: "This padding is perfect re #47 and #46".

   There is no literal H2 — the eyebrow is a <p> and the lead lines are <p>. What he is
   comparing is the eyebrow-to-title pair: the FES-sales band renders those 8px apart
   (measured), every other service page 32px, because .liv-sec-head is a flex column with a
   uniform 32px row-gap and FES-sales uses a different, shorter pattern for that band.
   So: match the reference at 8px, and give the rule back the 32px it had on both sides so
   only the eyebrow-to-title relationship changes. Scoped to .liv-intro, which is the service
   intro band — .liv-sec-head is shared with "What We Deliver" / "How We Operate" / the
   homepage sections, and none of those were part of the complaint. */
.liv-intro .liv-sec-head { row-gap: 8px; }
.liv-intro .liv-sec-head > .liv-sec-rule { margin-block: 24px; }
/* Client pin 107, FES service only: "add space between H1 and copy (see hotelverdant.com
   example)". Only the space BELOW the rule grows — the eyebrow-to-title relationship above
   it is the 8px the client explicitly signed off in pins 47 and 49, so it must not move.
   24 -> 48 takes the H1-to-copy distance from 71px to 95px.
   SCOPED to .liv-fes-service (body class from functions.php, keyed on post_name so it
   covers EN and FR) because .liv-intro is every service page's intro band and pins 46/47/49
   approved the current spacing there. If the client wants this everywhere, drop the body
   class from the selector — that is the whole change. */
body.liv-fes-service .liv-intro .liv-sec-head > .liv-sec-rule { margin-block-end: 48px; }
/* WHY this rule now only re-states the base values instead of going 700/-0.03em: client 2026-09-02 —
   "Not the bold fonts on all other intro sections that are there now please." The 700 here was the
   bold the client is pointing at; About / Approach / Consulting / Equipment Sales / Campus all render
   their intro paragraph through .liv-intro-text, so this single line was the whole complaint. Kept as
   an explicit desktop declaration (rather than deleted) so it still overrides the -0.03em that the
   sibling desktop hero rule used to establish, and so a future desktop-only retune has a home. */
@media (min-width: 1024px) { .liv-intro-text { font-weight: 400; letter-spacing: 0.01em; } }
.liv-split-title-md { letter-spacing: -0.05em; }
/* WHY: Figma 33186:8689/8790 split "When to Engage" titles track -0.03em (79px), not the -0.06em display default; 33186:8543 md variant is 64px/500/lh1.2/-0.05em */
@media (min-width: 1024px) { .liv-split .liv-sec-title { letter-spacing: -0.03em; } .liv-sec-title.liv-split-title-md { font-size: 4rem; font-weight: 500; line-height: 1.2; letter-spacing: -0.05em; } }
.liv-tcard-photo { max-width: 487px; } .liv-tcard-photo img { border-radius: 16px; }
.liv-tcard-wide-copy { flex: 1 1 400px; }
/* WHY 1320: client 2026-08-19 "it needs to be larger like the figma", the third pass at pin 86.
   1320 is the band's own content box at 1440 (1440 - 2x60 padding), i.e. the hard ceiling before
   this would have to eat the section gutter — not a picked number.
   CORRECTION to the note that used to live here: 961 was NEVER this graphic's Figma extent.
   33186:8551 renders the "Your Amenity" hub-and-spoke graphic, a different design; its PNG
   (attachment 71) is referenced by 0 published posts. .liv-diagram carries the six-service wheel
   (wp_block 85 EN / 353 FR), whose only Figma source is the standalone artboard 33345:1165 —
   there is no page-context placement of it in the file, so there is no design-specified on-page
   width to override. Sizing here is a client call end to end.
   The old 2000w srcset ceiling that capped this at 1120 is gone: the master is now rendered from
   the artboard's outlined SVG at 2560x1542, so 1320 CSS still resolves at 1.94x on retina —
   better than the 1.79x that was accepted at 1120.
   Aspect is now the artboard's own 1.660 (was 1.406), so 1320 wide renders 795px tall and the
   band height is unchanged at ~931 — this is bigger at zero cost to the vertical rhythm pins
   86/87 tuned. */
.liv-diagram-img img { max-width: 1320px; width: 100%; height: auto; }
@media (min-width: 1024px) {
	/* WHY: Figma inner intro bands are 48px tall (33186:8505/8578/8905); About variant is 90px (33186:8421) via .liv-intro-tall */
	.liv-intro { padding: 48px 60px; }

	/* WHY: Figma 33478:953 is a 1440 artboard with 95px/60px section padding and a 54px gap
	   between the title block and the card stack. Card width (926px) is set on the block itself,
	   not here, so an editor can see and change it in the Site Editor. */
	.liv-faq { padding: 95px 60px; }
	.liv-faq .liv-sec-head { margin-bottom: 54px; }
	/* WHY: client 2026-07-30 — "padding in the intro quad is off, use the Our Approach page
	   as the reference, its padding is correct." That SUPERSEDES Figma 33186:8421, which
	   specs the About variant at 90px against the other intros' 48px. Client direction wins
	   (same precedent as the nav lvl-2 call on 2026-07-23). The .liv-intro-tall class stays
	   in the About pattern markup, inert, so this is one line to revert if they change
	   their mind. */
	.liv-intro.liv-intro-tall { padding: 48px 60px; }
	.liv-intro-eyebrow { font-size: var(--wp--preset--font-size--medium); }
}

/* ---- full-width photo banner ---- */
.liv-banner img { width: 100%; height: clamp(200px, 29.4vw, 423px); object-fit: cover; display: block; }

/* Banner as a 4-image carousel — client 2026-08-05 pins 30-36 / 59-64 / 70-72, "make into
   4 image carousel, similar to homepage". It reuses the homepage machinery wholesale
   (.liv-hero-carousel + .liv-hero-slide; liv-ui.js adds .has-carousel and builds the dots),
   so the only thing needed here is SIZING.
   WHY that is needed at all: the generic .liv-hero-carousel.has-carousel rule sets
   aspect-ratio 4/3 — correct for the homepage hero, whose mobile box is square-ish and whose
   desktop height comes from the text column beside it. The banner has no such row; it is a
   fixed-height band. Left alone, every markets banner would go 4/3 and render as a giant
   square on phones. So the aspect-ratio is cancelled and the band's own clamp restated —
   the slides are position:absolute inset:0, so the container must carry a real height. */
.liv-banner.liv-hero-carousel.has-carousel {
	aspect-ratio: auto;
	height: clamp(200px, 29.4vw, 423px);
}
.liv-banner.liv-hero-carousel.has-carousel .liv-hero-slide img { height: 100%; }

/* WHY: the band is a ~3.6:1 letterbox, so object-fit:cover on a PORTRAIT source keeps only
   ~19% of its height and the default 50% centre lands on the subject's waist — pin 72's
   careers slide 1 (2000x3000) cropped both heads off. Opt-in class rather than a rule keyed
   to one attachment ID, because the client supplies portrait photos every round and the next
   one will need the same treatment. 33% frames head-and-shoulders on a standing subject —
   measured, not guessed: 50% lands on the waist and 18% overshoots into the ceiling. */
.liv-banner .liv-crop-top img { object-position: 50% 33%; }

/* WHY a SECOND crop class rather than reusing 33%: the amount depends on the source aspect, not
   on taste. This one is for a LANDSCAPE source with a standing full-body subject (pin 72 slide 4,
   1024x683) — cover keeps ~42% of its height there, so the centre crop opens below the subject's
   chin. 15% lifts the window to just above the head. Applying the 33% above to this image would
   still cut it. Pick by source: portrait -> liv-crop-top, landscape full-body -> liv-crop-standing. */
.liv-banner .liv-crop-standing img { object-position: 50% 15%; }

/* ---- text-card grid (What We Deliver / How We Operate / market bullets) ---- */
.liv-tcards { position: relative; padding: 40px 20px; }
.liv-tcards > .liv-sec-head { margin-bottom: 24px; }
.liv-tcard { width: 100%; box-shadow: 0 4px 6px -2px rgba(16, 24, 40, 0.05), 0 12px 16px -4px rgba(16, 24, 40, 0.1); }
.liv-tcard ul { padding-inline-start: 24px; } /* WHY: Figma list indent — browser default 40px narrows the text column and adds a wrap line (33186:8923 et al) */
.liv-tcards:not(.liv-on-blue) .liv-tcard:has(> ul) > .liv-card-title { min-height: 0; } /* WHY: client pin 161 (2026-08-31) — markets bullet cards: headline-to-bullets gap must match the services pages' headline-to-copy gap; the title min-height floor left a phantom line under these one-line titles */
.liv-quad2 .liv-tcard figure.liv-quad2-img { margin: 0; } /* pin 191: card photo, flush */
.liv-quad2 .liv-tcard .liv-quad2-img img { width: 100%; aspect-ratio: 495 / 280; object-fit: cover; display: block; }
/* WHY (client 2026-09-02): "match the styling on the homepage and apply it to the tiles on
   careers". The home Our Services tiles (.liv-card) are a full-bleed photo clipped to the card's
   own 16px radius, no shadow, copy inset 16/24px, with 24px between photo and copy. This quad
   was built the other way — photo inset inside 24px card padding with its own 8px radius, plus a
   drop shadow. The block markup now mirrors the home card (card padding removed, blockGap 24px,
   copy wrapped in .liv-card-body so it inherits the SAME padding rule home uses); these three
   declarations are the rest of it. `overflow: hidden` is what makes the photo take the card's
   top corners — same mechanism as .liv-card. Scoped to .liv-quad2, which only careers uses
   (wp_block 586 is the sole post carrying the class), so the shadowed .liv-tcard everywhere
   else is untouched. Revert = drop this block and restore the 8px img radius above. */
.liv-tcards.liv-quad2 .liv-tcard { overflow: hidden; box-shadow: none; padding-bottom: 16px; }
.liv-tcard ul li + li { margin-top: 20px; } /* WHY: Figma listSpacing 20 between card bullets (33186:8923 et al) */
.liv-tcard-wide { width: 100%; }
@media (min-width: 1024px) {
	.liv-tcards { padding: 95px 60px; } /* WHY: Figma 33186:8591/8626/8727/8815 card-grid sections are 95px */
	.liv-tcards > .liv-sec-head { margin-bottom: 48px; }
	/* WHY: client 2026-08-05 — "ensure all of these blocks are the same size across the
	   pages." Figma "Feature Text" cards are a fixed 344x237 box (33186:8599 et al), but
	   live copy runs longer than Figma's, so cards grew past 237 unevenly: a swept
	   measurement of all 73 narrow cards on the 13 services/markets pages returned six
	   distinct heights (237/246/257/267/279/300), and because the grid is flex-wrap each
	   ROW sized to its own tallest card (FES "How We Operate" was 246 on row 1, 237 on
	   row 2 — the screenshot the client sent). 300px is the tallest real card
	   (/markets/master-planned-communities/ "Consulting & Development"), so pinning the
	   floor there makes every card identical site-wide without clipping anything.
	   This SUPERSEDES Figma's 237 on client direction — same precedent as the About
	   intro padding call on 2026-07-30. Revert = put 237 back; nothing else depends on it.
	   Paired with align-items:stretch below so a future longer card re-equalises its row
	   instead of silently reintroducing the ragged edge. */
	/* SUPERSEDED 2026-08-06 by client pin 42 — see the grid rules below. The 300px floor made
	   every card identical site-wide, which fixed the ragged rows but bought it with dead
	   space: on /services/consulting-development/ "What We Deliver" the content measured 133px
	   inside a 300px box. Conor: "All of the boxes should be a fixed length, and that length
	   should be to accommodate the box with the most content. There's too much empty space."
	   i.e. equalise PER SECTION to that section's tallest card, not site-wide to the tallest
	   card anywhere. Width stays; the height floor is gone. */
	.liv-tcard { width: 344px; }
	/* WHY (markup.io pin 96, 2026-08-17): "Body copy isn't aligned with the two tiles to the
	   left" on /services/fitness-equipment-sales. Its three Deliver titles run 2/2/1 lines, so
	   the third card's copy started 30px higher than its neighbours — one line at this rule's
	   25px x 1.2. Every other service page happens to run 2/2/2 and lines up by luck, which is
	   why only this page drew the pin.
	   2.4em is exactly two lines of THIS element, so the floor tracks the font size instead of
	   hard-coding 60px. Scoped to `:not(.liv-on-blue)` — that modifier marks the "How We
	   Operate" decks, which hold 5-6 cards, wrap onto several rows, and are mostly 1-line
	   titles; a floor there would inject space the client never asked for, including on
	   consulting-development, which pin 94 names as approved and must not move. */
	.liv-tcards:not(.liv-on-blue) .liv-card-title { min-height: 2.4em; }
	/* WHY: same client call as .liv-tcard above (2026-08-05), applied to the wide markets card.
	   Figma authors it as a fixed 1046x408 (33186:8936) but the copy column, not the photo,
	   drives the height (measured: photo 265 or 324, copy 334-377, card = copy + 48 padding),
	   so the 7 markets pages rendered 382/404/425. 425 is the tallest real one
	   (/markets/master-planned-communities/), so the floor goes there — 17px over Figma's 408,
	   accepted for the sake of one uniform card.
	   The photo USED to stay top-aligned here, because the img is object-fit:fill and stretching
	   it would have distorted rather than cropped. That left 53-112px of white under the photo
	   inside the card, which is exactly what client pin 38 objected to — "Image should extend
	   through the quad". Fixed below by switching the img to object-fit:cover, which crops, so
	   the photo can now safely fill the full height. */
	.liv-tcard-wide { width: 1046px; max-width: 100%; min-height: 425px; align-items: stretch; }
	/* pin 38: photo fills the card's full content height (card height minus the 24px padding),
	   instead of sitting at its intrinsic height with white beneath it. cover + a min-height of 0
	   because the figure is a flex item — without it the img cannot shrink below its intrinsic
	   height and the card would grow instead of the photo cropping. */
	.liv-tcard-wide > .liv-tcard-photo { align-self: stretch; display: flex; min-height: 0; }
	.liv-tcard-wide > .liv-tcard-photo img { height: 100%; width: 100%; object-fit: cover; }
	/* WHY (client 2026-09-17 pin 316): the wide-card photo can now be a PORTRAIT source (hospitality
	   1600x2400). With the img in flow, the figure's hypothetical cross size is the img's natural
	   height at 487px wide (730px), so align-items:stretch grows the CARD to the photo instead of
	   cropping the photo to the copy (card went 425 -> 778px, empty space under the bullets).
	   Taking the img out of flow removes it from the figure's intrinsic size; the figure then only
	   stretches to the copy column, and cover crops the photo into that box. The explicit flex
	   basis replaces the width the in-flow img used to give the figure. Landscape sources are
	   unaffected (retail/campus measured 487x377 before and after). */
	.liv-tcard-wide > .liv-tcard-photo { position: relative; flex: 0 0 487px; }
	.liv-tcard-wide > .liv-tcard-photo img { position: absolute; inset: 0; }
	/* Card grid — client 2026-08-05 pin 42 (+ pin 43, "See #42").
	   Requirement is two things at once: every card the same height, AND that height set by
	   the tallest CARD IN THE SECTION so there is no dead space. Flex cannot do the second
	   part: with flex-wrap each row is its own line box, so stretch equalises WITHIN a row
	   and rows still disagree (the 246-vs-237 raggedness the client sent a screenshot of in
	   the previous round). The 300px floor that replaced it solved raggedness by making the
	   dead space uniform — which is what he is now objecting to.
	   Grid with grid-auto-rows:1fr equalises across ALL rows to the tallest item, so both
	   constraints hold with no magic number and nothing to re-measure when copy changes.

	   WHY 6 columns of 168 and each card spanning 2, rather than 3 columns of 344: it is what
	   lets an orphan row be centred. A 5-card section renders 3 + 2, and flex was centring
	   that pair (measured lefts 408/760 against 232/584/936). Grid places items on tracks, so
	   an odd last row would go hard left unless it can start on a HALF column — hence the
	   half-width track. 168*2 + 8 gap = 344, the exact card width, and 6 tracks + 5 gaps =
	   1048 = the exact 3-card row width. No fractional drift.

	   Descendant selector (0,2,0) because core prints .wp-container-core-group-is-layout-*
	   (0,1,0) in wp_head AFTER this file.

	   :not(:has(> .liv-tcard-wide)) is LOAD-BEARING, not defensive tidiness. The markets pages
	   reuse .liv-tcards-grid for a different layout — four narrow cards plus one 1046px wide
	   card in the same container. Applying this grid there put the wide card in a 344px track
	   and grid-auto-rows:1fr then dragged all five to a uniform 790px. Measured on all seven
	   markets pages before this guard went in. Those grids stay on flex. */
	.liv-tcards .liv-tcards-grid:not(:has(> .liv-tcard-wide)) {
		display: grid;
		grid-template-columns: repeat(6, 168px);
		grid-auto-rows: 1fr;
		align-items: stretch;
		justify-content: center;
	}
	.liv-tcards .liv-tcards-grid:not(:has(> .liv-tcard-wide)) > .liv-tcard {
		grid-column: span 2;
		width: auto; /* the track span owns the width now; 344px would just restate it */
	}
	/* WHY per-row heights on the on-blue "How We Operate" decks: client pins 156/157 (FES)
	   + 187 (Amenity), 2026-08-31 — "tighten padding (see row above)" / "padding to be as
	   short as the longest caption". grid-auto-rows:1fr (pin 42, above) equalises to the
	   tallest card in the SECTION, which left dead space in every other row of these
	   5-card decks. auto still stretches cards WITHIN a row, so each row hugs its own
	   longest caption. Pin 42's section-wide rule still stands on the beige Deliver decks. */
	.liv-tcards.liv-on-blue .liv-tcards-grid:not(:has(> .liv-tcard-wide)) {
		grid-auto-rows: auto;
	}
	/* ---- Careers 2x2 pillars band — client pin 191 (2026-08-31) ----
	   "add a new quad between the intro and People Make The Difference ... 2x2 tiles with
	   the attached content. This design from ACG comes to mind. But make it LIV branding."
	   The base grid above would lay 4 cards 3+1; this variant is a fixed 2-up. Specificity
	   (0,3,0) + later position beat the base grid rule on purpose. */
	.liv-tcards.liv-quad2 .liv-tcards-grid {
		display: grid;
		grid-template-columns: repeat(2, 519px);
		grid-auto-rows: auto;
		justify-content: center;
	}
	.liv-tcards.liv-quad2 .liv-tcards-grid > .liv-tcard { grid-column: auto !important; width: auto; } /* !important: the base grid's orphan-centering :nth-child rules are (0,6,0) and would push cards 3/4 onto implicit tracks */
	.liv-tcards.liv-quad2 .liv-tcard { padding-bottom: 24px; } /* 2026-09-02: home-card parity — .liv-card steps 16 -> 24 at this breakpoint too */
	/* Centre a trailing row that does not fill its three columns. :nth-child(3n+1) is the
	   first card of a row; :nth-last-child(n) says how many are left including it.
	   Two orphans -> start half a column in. One orphan -> start a full column in. */
	.liv-tcards .liv-tcards-grid:not(:has(> .liv-tcard-wide)) > .liv-tcard:nth-child(3n+1):nth-last-child(2) { grid-column: 2 / span 2; }
	.liv-tcards .liv-tcards-grid:not(:has(> .liv-tcard-wide)) > .liv-tcard:nth-child(3n+1):nth-last-child(1) { grid-column: 3 / span 2; }

	/* The markets grid keeps the old behaviour: flex, and the 425px floor on the wide card
	   below is what holds its rows even. Pin 42 was scoped "across all service pages", so the
	   markets layout is deliberately untouched here — if the client wants the same dead-space
	   cut there, it needs its own pass because the wide card changes the geometry. */
	.liv-tcards .liv-tcards-grid:has(> .liv-tcard-wide) { align-items: stretch; }
}
/* Beige card band gets the texture too — client 2026-08-05 pin 57: "This should also have
   the pattern for all service pages", pinned on the "What We Deliver" band. Its blue sibling
   ("How We Operate", .liv-on-blue below) already had it, so the two bands on every service
   page read as a matched pair now instead of one textured and one flat.
   Uses the beige multiplier and the same 0.12 base as .liv-svc / .liv-markets / .liv-jobs,
   so pin 2's global opacity control still governs it — do not hard-code an opacity here.
   :not(.liv-on-blue) so it cannot double up with the blue rule below.

   MARKETS PAGES ARE INCLUDED TOO, via pins 39 + 56 ("Pattern should be applied here for all
   Markets pages" / "for all markets pages, this should have the pattern"), both pinned on this
   same beige card band. An earlier note here claimed pins 39 and 40 contradicted each other —
   they do not: 39/56 ADD the texture to this beige band, 40/55 REMOVE it from the blue
   One-Partner band below (see the suppression rule further down). Different sections, one
   consistent instruction. Still scoped to the two CPTs rather than left bare, so the homepage
   and standalone pages keep whatever their own pins decided. */
body.single-liv_service .liv-tcards:not(.liv-on-blue)::before,
body.single-liv_market .liv-tcards:not(.liv-on-blue)::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-beige));
	pointer-events: none;
}
.liv-tcards.liv-on-blue::before,
/* Client 2026-08-05 pin 9: "Our Purpose quad should be the same background as Core Values with
   the pattern extending up here." Core Values is .liv-values — theme-04 with this same blue
   texture — so About Purpose was moved to theme-04 in the DB (wp_block 80) and joins this rule
   to pick up the pattern, which is what makes the texture read as continuing UP from Core
   Values into the quad above it rather than stopping at a hard edge.
   Uses the .liv-on-blue modifier already established by .liv-tcards.liv-on-blue rather than a
   page-id selector, so the treatment is reusable and .liv-wide stays untextured everywhere
   else (home, services, markets all use it with a navy background). */
.liv-wide.liv-on-blue::before,
.liv-onepartner.liv-accountability::before {
	content: "";
	position: absolute;

	/* WHY: left-60% inset -> left-to-right mask fade, same reason as
	   .liv-markets::before */
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-blue)); /* light-blue #D0DEDF bands, full bleed */
	pointer-events: none;
}

/* WHY .liv-values has its own copy of that rule now, on the BEIGE multiplier: client pin 195
   (2026-09-02) — "Let's make this background the tan color with brand pattern (what you're
   using in the quad below)" — moved Core Values off theme-04 onto theme-05 (wp_block 81, and
   the FR twin 357). The two fade multipliers exist because the same texture reads heavier on
   cream than on light blue, so a band that changes base has to change multiplier with it;
   leaving it in the blue group above would have printed the pattern too faint to see.

   This also breaks the 2026-08-05 pin-9 continuity above — the Purpose quad (.liv-wide
   .liv-on-blue) stays theme-04 + blue-fade pattern, so the texture no longer reads as one run
   from Core Values up into it. That is what pin 195 asks for; flag it if the client reads the
   new seam as a regression.

   2026-09-03 client pin 222: "Our Purpose to have exact same background as Core Values (so
   they're still sharing a background). We just wanted the colors swapped." So the Purpose quad
   moves with Core Values: .liv-wide.liv-on-cream (theme-05 base, set in the About Us page
   content, EN 21 + FR 391) joins THIS beige-multiplier rule and leaves the blue group above.
   The pin-9 continuity is restored, now on cream. */
.liv-wide.liv-on-cream::before,
.liv-values::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-beige)); /* beige theme-05 band, full bleed */
	pointer-events: none;
}
.liv-tcards > * { position: relative; }

/* ---- photo/text split ---- */
.liv-split { padding: 40px 0 40px 0; }
/* WHY: client mobile pins 78 + 79 (2026-08-12) — "spacing between image and headline
   doesn't look right" (/our-approach, "Managing Complexity Requires Coordination") and
   "spacing looks off" (/services/consulting-development, "When to Engage"). Same defect,
   one cause: the split patterns author blockGap:0px so the image can sit flush to the band
   edge beside the copy on desktop, where column-gap:140px does the separating. Stacked at
   mobile that 0 becomes the ROW gap and the photo butts straight into the heading —
   measured gap was exactly 0px on both pages. spacing-60 = 32px at this width. */
.liv-split-grid { grid-template-columns: 1fr; row-gap: var(--wp--preset--spacing--60); }
.liv-split-img img { width: 100%; height: auto; object-fit: cover; display: block; }
.liv-split-copy { padding: 0 20px; }
@media (min-width: 1024px) {
	/* WHY: Figma 33186:8518/8664/8765 "Center Content" band: 54px vertical padding, image col 600 + 140 gap + copy col 700 (title 596, body 528), image 556 tall.
	   Band color stays theme-05 cream — manifest's #C4BDA8 is a Figma variable fallback; render pixel-sample says #F0EEE9 (Rule 16, screenshot wins). */
	.liv-split { padding: 54px 0; }
	.liv-split-grid { grid-template-columns: 600fr 700fr; column-gap: 140px; align-items: center; }
	.liv-split-img img { height: 556px; }
	.liv-split-copy { padding: 0 104px 0 0; }
	.liv-split-copy p { max-width: 528px; }
}
.liv-split-title { font-size: var(--wp--preset--font-size--x-large); font-weight: 500; letter-spacing: -0.03em; line-height: 1.2; }
@media (min-width: 1024px) { .liv-split-title { font-size: var(--wp--preset--font-size--xx-large); } }

/* ---- FES split hero (navy panel + partner logos) ---- */
/* WHY: pattern removed 2026-07-30 (client round 3, rule d "remove from hero"). */
.liv-svc-hero { position: relative; overflow: visible; }
.liv-svc-hero > * { position: relative; }
.liv-svc-hero-content { padding: 40px 20px; }
/* WHY these are live again, and bigger: the Life Fitness / Hammer Strength lockup came OFF the
   US page on 2026-08-19 (it contradicted US copy promising sourcing "without brand bias" — the
   2026-08-03 open question) and went ON the new Canada page the same day, where the copy sells
   the opposite posture: "the exclusive distributor of Life Fitness in Canada". So this rule now
   serves the CA page only. US and FR heroes have no lockup; do not "restore" it there.

   WHY 70px and not the old 34px: measured off Figma 33186:8708 (frame 33186:8706 is literally
   named "Services - Fitness Equipment Sales (CA)"), the lockup ARTWORK is 53px tall. The PNG is
   1356x217 canvas holding 1308x164 of artwork, so a 34px canvas was rendering the artwork at
   ~26px — under half the design, which is the "make them larger to match the figma" complaint.
   Canvas height for 53px of artwork = 53 * (217/164) = 70px. At 70px the lockup is ~437px wide,
   which clears the 653px hero copy column.

   Mobile keeps height:auto so the lockup scales to the column instead of overflowing it — the
   inner-page Figma frames are desktop-only by design, so there is no mobile spec to match. */
.liv-svc-hero-logos { filter: none; width: 100%; } /* width:100% for the same load-order reason as .liv-svc-hero-marks below */
/* WHY width-capped rather than the old `height:70px; width:auto` at desktop: 437px IS the 70px
   canvas (1356/217 x 70), so the rendered size is unchanged where the column is wide enough. But
   the copy column now carries a gutter (pin 289, below), and at 1024–1100px it is narrower than
   437px; `max-width:100%` + a fixed height squashed the lockup there. A width cap with height:auto
   scales it down in proportion instead. */
.liv-svc-hero-logos img { width: min(437px, 100%); height: auto; }
/* WHY (markup.io pin 287, Conor 2026-09-10): "can we utilize the hero + intro we have on the
   Equipment sales Canada page on this one too? Then we can display the logos side by side and it
   should be a much more seamless fit. LIV Consulting can go on the left and Advantage can go on
   the right." That retires the pin-284 treatment, where the same two marks sat STACKED in the
   right-hand gutter of the centred .liv-intro band. The FR twin (post 374) was rebuilt onto this
   same hero on 2026-09-14, so the stacked .liv-intro-marks rules that served pin 284 are gone.

   Sized by HEIGHT, not width, for the same reason .liv-svc-hero-logos above is: these are two
   separate files (2560x710 and 834x230) and only a shared height makes them read as one lockup.
   Their aspect ratios agree to within 0.6%, so equal height also lands near-equal width — which
   is what "side by side" wants and what a shared `width` could not give.

   WHY 53px on desktop: that is the CA lockup's ARTWORK height (1356x217 canvas around 1308x164
   of artwork, shown at 70px canvas = 52.9px of artwork), so both country heroes carry the same
   optical weight. These two PNGs are cropped tight to their artwork, so 53px of canvas here IS
   53px of artwork. Pair sits ~423px wide, inside the 653px copy column.

   WHY 36px below that: keeps both marks on ONE ROW inside the content column on a 360px phone
   (130 + 130 + 32px gap = 292 in a ~320px column). flexWrap on the group is the backstop only. */
/* WHY (client, 2026-09-10): "can we add some space above the logos?" on the US Equipment Sales hero. The marks row inherits the hero-content flex gap (24px), which reads as another paragraph break rather than a partner lockup sitting under the intro. Preset spacing-40 adds 24px phone / 32px desktop on top of that gap (48/56 total) so the pair separates from the copy while staying inside the 80px hero bottom padding. Scoped to .liv-svc-hero-marks, so the CA page (.liv-svc-hero-logos) is untouched. The parent selector is REQUIRED: core's flex layout emits `.is-layout-flex > :is(*, div) { margin: 0 }` (0,1,1), which beats a bare `.liv-svc-hero-marks` (0,1,0) and silently zeroed this margin on the first attempt. */
/* WHY the marks are now sized by WIDTH, and bigger — markup.io pin 288 (Conor 2026-09-11): "Just
   confirming these logos are the same size as life fitness / hammer strength on the CA equipment
   sales page. These logos look smaller." They were the same 53px box height as the CA lockup's
   ARTWORK, but the LIV file carries 42px of transparent padding on a 710px canvas (so its letters
   rendered at 46.7px) and both US marks spend part of their height on small secondary lines, so at
   equal box height they read lighter than the solid Life Fitness / Hammer Strength wordmarks.
   Each mark now caps at 254px wide, which is a 70px canvas for both files (2560x710 -> 70.4px,
   834x230 -> 70.0px) — the same 70px canvas the CA lockup renders at, so the two country heroes
   carry the same lockup mass. Pair is 254 + 32 + 254 = 540px, inside the 653px copy column.
   Width-based (flex-basis + img width:100%) so the pair SHRINKS in proportion in a narrower column
   instead of wrapping onto two rows: a 320px phone column gives 144px per mark (40px tall), the
   1024px desktop column ~180px (50px). nowrap overrides the block's own flexWrap:wrap, which with
   fixed-basis items would wrap before shrinking; the parent selector is needed for the same
   specificity reason as the margin rule above. */
/* width:100% is load-order insurance: the row is a shrink-to-fit item in the column flex parent, and
   a shrink-to-fit flex row sizes from its items' CONTENT, not their flex-basis — so until the two
   images have loaded (lazy, or a slow connection) the row measured 32px (just the gap) and both
   marks rendered at 0px. An explicit width lets the basis do its job from the first paint. The
   parent's max-width above still caps it at the 653px measure. */
.liv-svc-hero-content > .liv-svc-hero-marks { width: 100%; align-items: center; flex-wrap: nowrap; margin-top: var(--wp--preset--spacing--40); }
.liv-svc-hero-marks .liv-svc-hero-mark { margin: 0; flex: 0 1 254px; min-width: 0; }
.liv-svc-hero-marks .liv-svc-hero-mark img { width: 100%; height: auto; }
.liv-svc-hero-media img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
/* WHY (markup.io pin 1, CA board 5fcc4d5b 2026-08-24): "Hero image should be placed above the
   intro content" — filed on the MOBILE board only. The hero is a core grid whose DOM order is
   the desktop order (copy column, then media column), so the swap is an `order` flip rather
   than a block reorder in the DB.

   Scoped two ways on purpose. `.liv-hero-media-first` is carried by the CA and US hero groups
   (US added 2026-09-10 with pin 287): before that rebuild the US page ran a full-width banner
   ABOVE its intro band at every width, so media-first is what PRESERVES the phone order Conor
   already signed off on there. The FR twin (374) carries the same class since its 2026-09-14
   rebuild.
   And max-width:767.98px, not 1023.98px, because the grid's minmax(24rem, 1fr) still resolves to
   TWO columns between 768 and 1024 — flipping order there would move the photo to the left of
   the copy instead of above it, which is not what the pin asked for. */
@media (max-width: 767.98px) {
	.liv-hero-media-first .liv-svc-hero-media { order: -1; }
}
@media (min-width: 1024px) {
	/* WHY: Figma 33186:8708 hero frame carries 75px left padding; content col (653) then holds the H1 (641) on one line with zero inner side padding */
	.liv-svc-hero { grid-template-columns: 653fr 712fr; padding-left: 75px; }
	/* WHY (markup.io pin 289, Conor 2026-09-11, three screenshots): "On my smaller laptop, the text is
	   too close to the image. On my larger monitor, the text width doesn't align with the headline.
	   Then on the homepage, there is no shift in the text. There needs to be sitewide consistency
	   that follows best practices."
	   All three are one cause. This block used to be `padding: 80px 0` with only the body copy
	   capped (`> p { max-width: 653px }`, pin 95): so on a ~1440px laptop the 653fr track IS about
	   653px and the paragraph ran flush into the photo (Figma 33186:8708 draws it that way, 0px
	   gutter — the client is overruling the frame), while on a wide monitor the H1 grew with the
	   track and the paragraph did not, so their right edges disagreed. The home hero never showed
	   either symptom because it centres ONE capped column (.liv-hero-content, 560px, gutter floor)
	   that the H1 and paragraph share — that is the "no shift" Conor saw, and it is the behaviour
	   the client asked for there (pin 3, 2026-08-05; text round 2026-09-02).
	   So the service heroes now run the home hero's formula: every direct child shares the 653px
	   Figma measure (H1, rule, copy, logos/marks all wrap on the same boundary), and the column is
	   centred in the track with a 32px floor on both sides — identical floor to .liv-hero-content.
	   The measure differs per hero (560 home / 653 service) because each is its own Figma frame;
	   the BEHAVIOUR is what is now shared. Known consequence: between ~1440 and ~1550px the H1 is
	   now two lines (needs 641px, has ~589–641) — it already was at every width below 1440. */
	.liv-svc-hero-content {
		padding-block: 80px;
		padding-inline: max(32px, calc((100% - 653px) / 2));
	}
	.liv-svc-hero-content > * { max-width: 653px; }
	.liv-svc-hero-media { height: 100%; }
	/* The figure between the group and the img was missing from this chain, so img{height:100%}
	   resolved against an auto-height parent and the photo stopped at its intrinsic 562px inside
	   a 682px column, leaving a navy strip under it. Only became visible once pin 50 merged the
	   hero copy into one longer Cormorant paragraph and the content column grew past the photo;
	   the bug was latent before that, and would have surfaced on any copy change. */
	.liv-svc-hero-media > figure { height: 100%; margin: 0; }
	.liv-svc-hero-media img { height: 100%; aspect-ratio: auto; }
}

/* ---- core values cards — Figma 33186:8447, restored 2026-08-17 ----
   REVERTS the 2026-08-14 row rebuild (33324:2070). markup.io pin 81: "In the Figma file,
   the core values were stacked and had white boxes around them. That's what we want to do
   here", restated by Conor on the phone 2026-08-17. Only the value CELLS go back. The
   alternating-line background stays exactly as built — he confirmed he wants those lines
   over the waves Figma draws — and so does the click-through pop-up. Gone with the row:
   the 3px gutter hairlines and the long closing rule, neither of which the cards had.

   Row split is 2 then 3, from Conor's reply on the same pin: "First row: Safety |
   Excellence / Second row: Passion | Boldness | Partnership". The Figma screenshot he
   attached to that very pin shows the opposite, 3 then 2 — SETTLED 2026-08-17: the markup
   comment is what we follow, so the written reply wins over the attachment. Do not "fix"
   this back to 3+2 on the strength of the screenshot; it is the deliberate choice. */
.liv-values { position: relative; padding: 40px 20px; }
.liv-values > * { position: relative; }
.liv-values > .liv-sec-head { margin-bottom: 24px; }
/* WHY width: 100% — below 1024 the desktop grid rule lapses and the block's own flex
   layout takes over, which would otherwise shrink each card to its label. Full-width is
   what makes them read as the stack Conor asked for on mobile. Harmless under the grid,
   where a card already fills its 2-column span. */
.liv-value-card { width: 100%; text-align: center; }
/* Icon sizes are per-glyph, not uniform: the SVG canvases ARE the design boxes
   (49–80 x 75–89), and theme.json's rung-3 `.liv-value-icon img { width/height: auto
   !important }` already forces them past the pattern's 64x64 resize. So the BOX gets the
   fixed height, not the image — bottom-aligned art puts all five words on one baseline
   across both rows, which a per-image clamp cannot do once the glyphs differ in height. */
.liv-value-icon { display: flex; align-items: flex-end; justify-content: center; height: 89px; margin: 0; }
.liv-value-name { font-size: var(--wp--preset--font-size--x-large); font-weight: 500; letter-spacing: -0.05em; line-height: 1.2; }
/* The pop-up copy ships as real core/paragraph blocks inside each card, so it stays
   editable in the Site Editor and no wp:html enters the DB (FSE audit). This file is
   front-end only — functions.php enqueues it, while add_editor_style() registers just
   style.css — so hiding it here leaves the editor canvas showing the copy. liv-ui.js
   clones it into the dialog. */
.liv-value-detail { display: none; }
@media (min-width: 1024px) {
	.liv-values { padding: 95px 60px; } /* WHY: 33186:8447 px-60 py-95 */
	.liv-values > .liv-sec-head { margin-bottom: 48px; }
	/* WHY 6 columns of grid rather than the flex wrap the block declares: natural wrap
	   gives 3+2 (380*3 + 24*2 = 1188 fits, a fourth card does not), and Conor asked for
	   2+3. Every card spans 2 columns, so both rows draw the SAME card width — the thing
	   fixed per-row widths would break — and row 1 starting at column 2 centres itself.
	   max-width 1188 is what keeps the card at the 380px it was before the row rebuild:
	   column = (1188 - 5*24) / 6 = 178, and a 2-column span = 178*2 + 24 = 380.
	   Two-selector specificity beats core's generated
	   `.wp-container-core-group-is-layout-*{display:flex}` without !important; below 1024
	   the rule lapses and the block's own flex layout stacks the cards. */
	.liv-values .liv-values-grid {
		display: grid;
		grid-template-columns: repeat(6, 1fr);
		max-width: 1188px;
		margin-inline: auto;
	}
	.liv-value-card:nth-child(1) { grid-column: 2 / span 2; }
	.liv-value-card:nth-child(2) { grid-column: 4 / span 2; }
	.liv-value-card:nth-child(n+3) { grid-column: span 2; }
	.liv-value-name { font-size: var(--wp--preset--font-size--xx-large); } /* WHY: 33186:8447 step-4 56px / -2.8px = -0.05em */
}

/* WHY (pin 10, client call 2026-08-12): Conor asked for the "bounce" the reference site does —
   "add subtle animation to mirror what TAC have". Measured on amenitycollective.com/overview,
   where the same five values run: each cell is `transition-all duration-300
   hover:-translate-y-[10px]`, i.e. the WHOLE cell lifts 10px over 300ms on Tailwind's default
   ease cubic-bezier(.4,0,.2,1). No scale, no colour change, no icon swap — mirrored to their
   numbers rather than invented, which is what "mirror what TAC have" asks for.
   Their cells also carry `cursor-pointer` + `modal-trigger` for the lightbox. That lightbox has
   now landed (2026-08-14, Figma 33325:2127), so the pointer cursor is no longer a lie and is
   switched on — but only under .has-value-modals, the class liv-ui.js adds once it has actually
   wired the triggers, so a no-JS visitor still gets a default cursor over cells that open nothing.

   The lift is back on the whole CARD (2026-08-17). Under the row design it had to move onto the
   icon and word, because the cell also drew the gutter hairline and lifting the cell would have
   lifted the hairline with it; the cards have no hairline, and "the blocks need to bounce when
   hovered on" is asking for the block to move, not its contents.

   Easing is a back-out overshoot rather than TAC's flat ease. He has now called it a "bounce"
   twice, and an overshoot that settles at -10px is a bounce where a linear glide is not. Same
   10px and same ~300ms as TAC — only the curve differs, so it still mirrors their motion.
   (hover: hover) gates it so a tap on touch does not leave a card stuck 10px up; the global
   prefers-reduced-motion block at the top of this file zeroes the duration, same contract as the
   .liv-card / .liv-tcard photo zoom below. */
.liv-value-card { transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1); }
@media (hover: hover) {
	.liv-value-card:hover { transform: translateY(-10px); }
}

/* ---- core values pop-up — Figma INTERNAL 33325:2127 "Core Values – Pop-up" (2026-08-14) ----
   Interaction copied from amenitycollective.com/overview, the reference the client named:
   measured live there, the five values are `modal-trigger` cells that open a fixed full-screen
   overlay (black @ 40%) holding one centred card with a close X — NOT an inline accordion. Only
   the Safety card was drawn in Figma; the other four take the same treatment with TAC's copy.

   Card chrome is built by liv-ui.js, not authored in the pattern: the same reason the hero
   carousel's dots are (keeps wp:html out of the DB and the FSE audit green) plus a native
   <dialog> gives us the focus trap, Esc-to-close and focus restore for free. Only the COPY lives
   in the pattern, as core/paragraph blocks, so the client can edit it in the Site Editor.

   The trigger button is JS-built around the existing figure + heading rather than authored,
   because core has no block that wraps an image and a heading in a <button>. With JS off nothing
   is wrapped and the row renders exactly as it did before the pop-up existed. */
.liv-value-trigger {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	width: 100%;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	color: inherit;
	font: inherit;
	text-align: inherit;
}
.liv-value-trigger > * { margin: 0; }
.liv-values.has-value-modals .liv-value-trigger { cursor: pointer; }
.liv-value-modal {
	width: min(816px, calc(100vw - 32px)); /* WHY: 33325:2127 card is 816 = 716 copy + 2 x 50 padding */
	max-width: none;
	padding: 0;
	border: 0;
	background: transparent;
	color: inherit;
	overflow: visible;
}
.liv-value-modal::backdrop { background-color: rgb(0 0 0 / 40%); }
.liv-value-modal__card {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 21px; /* WHY: 33325:2127 */
	padding: 24px;
	border-radius: 16px;
	background-color: var(--wp--preset--color--theme-08);
	/* WHY: 33325:2127 shadow-md — #1018280F y2 blur4 spread-2, #1018281A y4 blur8 spread-2 */
	box-shadow: 0 2px 4px -2px rgb(16 24 40 / 6%), 0 4px 8px -2px rgb(16 24 40 / 10%);
	text-align: center;
}
.liv-value-modal__title { margin: 0; } /* carries .liv-sec-title, i.e. the same 33/79px display treatment */
/* WHY the column + gap: client pin 220 (2026-09-02) — "these lightboxes aren't quite where it
   needs to be ... there should be the statement, then a space, then the guiding behaviour, then
   a space, then the next guiding behaviour", against TAC's lightbox. The three paragraphs are
   authored as separate core/paragraph blocks but `p { margin: 0 }` below closed every gap, so
   the statement and the two behaviours ran together as one eight-line slab with nothing to say
   where one ended and the next began. 1.2em is one empty line at this line-height (1.2), which
   is the separation TAC draws, and em rather than px so it tracks the 20px -> 33px step at the
   1024 breakpoint instead of needing a second value there. */
.liv-value-modal__body {
	display: flex;
	flex-direction: column;
	gap: 1.2em;
	max-width: 716px;
}
.liv-value-modal__body p {
	margin: 0;
	/* WHY: 33325:2134 is Headline M — Cormorant 500, step-3 33px, lh 1.2, -0.99px = -0.03em.
	   The family has to be named because paragraphs default to Proxima; headings do not. */
	font-family: var(--wp--preset--font-family--cormorant-garamond);
	font-size: 1.25rem;
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: -0.03em;
}
/* WHY named rather than left to `bolder` (pin 220): the statement is bold in full and each
   guiding behaviour bolds its lead-in, which is what separates "Safety Mindset." from the
   sentence explaining it. `bolder` against a 500 parent resolves to 700 in every current
   engine, but only 400/500/700 Cormorant faces are self-hosted — naming 700 pins it to a real
   face instead of letting a future weight change synthesise one. */
.liv-value-modal__body strong { font-weight: 700; }
/* Close control is not in the Figma frame; it is TAC's, and a modal needs one regardless.
   Reuses the flyout's masked X so there is one close glyph in the build, recoloured to theme-03
   the way TAC's is gold. 44px box keeps the tap target legal at a 20px glyph. */
.liv-value-modal__close {
	position: absolute;
	top: 8px;
	right: 8px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--theme-03);
	cursor: pointer;
}
.liv-value-modal__close::before {
	content: "";
	width: 20px;
	height: 20px;
	background-color: currentcolor;
	-webkit-mask: url(../images/liv-close-x.svg) center / contain no-repeat;
	mask: url(../images/liv-close-x.svg) center / contain no-repeat;
}
.liv-value-modal__close:hover,
.liv-value-modal__close:focus-visible { color: var(--wp--preset--color--theme-07); }
/* Scroll lock. showModal() makes the page behind inert but does not stop it scrolling.
   scrollbar-gutter rides along because hiding the overflow also removes the scrollbar, and
   without the reserved gutter the whole page jumps ~7px sideways the moment the dialog opens. */
html.liv-modal-open { overflow: hidden; scrollbar-gutter: stable; }
@media (min-width: 1024px) {
	.liv-value-modal__card { padding: 50px; } /* WHY: 33325:2127 */
	.liv-value-modal__close { top: 16px; right: 16px; }
	.liv-value-modal__body p { font-size: var(--wp--preset--font-size--x-large); } /* 33px */
}

/* ---- People Make The Difference (careers, pin 22) — Figma INTERNAL 33223:927 ----
   REBUILT 2026-08-12 from Amanda's design, which supersedes the centred 4-across uniform row
   shipped 2026-08-11 (that was built with no mock available; the mock was in INTERNAL_LIVunLtd,
   not the EXTERNAL file every earlier lookup targeted).

   The design is the SAME "Center Content with Design Element" component as .liv-split — 54px
   vertical padding, 140px column gap, theme-05 band, Headline L + rule + 16/1.35 body — with the
   single photo swapped for a 2x2 collage. So this REUSES .liv-split wholesale and overrides only
   the two things that genuinely differ. In particular the whole mobile behaviour is inherited,
   which is the point: .liv-split's stacked row-gap is the value the client already signed off in
   mobile pins 78/79, so this section cannot re-introduce that defect. */

/* WHY not .liv-split's 600fr/700fr: Amanda's row is cluster 591 + gap 140 + copy 579 = 1310
   inside 1440 — it deliberately stops 130px short of the right edge instead of filling it.
   591fr/709fr reproduces that (591 + 709 = 1300 = 1440 - 140) and the copy column keeps its own
   579 max-width, so the trailing 130px stays real whitespace rather than a wider text measure. */
@media (min-width: 1024px) {
	/* ---- People cluster re-cut to Figma 33469:1166 + 33469:1216 (client 2026-09-02) ----
	   Supersedes the 33290:978/984 three-row cluster below. The new pair of frames draws the
	   band as FOUR photos in two staggered rows, not six in three: row A pinned to the left
	   viewport edge (0 -> 651.33 of 1440), row C pinned to the RIGHT edge (606 -> 1440.43),
	   so the bottom row wraps under the copy from the other side. The middle row is gone from
	   the design, so wp_block 300 drops it (pin-125 photos 297/298 are recoverable from
	   ../backups/wp_block-300-*.html on BLD if the client wants them back).
	   Gaps: client specified 14.33px horizontal AND vertical. Figma's own vertical gap reads
	   27px only because 1166 and 1216 are two separate artboards stacked; 14.33 is the value
	   to build, which is why the grid's inherited 52.34px row-gap is zeroed here.
	   Columns 651.33/720 with a 68.67px gutter sum to 1440 exactly and put the copy's text at
	   x=752 as drawn (col2 starts 720, + the component's own 32px pad). */
	.liv-people .liv-split-grid { grid-template-columns: 651.33fr 720fr; column-gap: 68.67px; row-gap: 0; }
	.liv-people .liv-people-row-a { grid-template-columns: 248fr 389fr; aspect-ratio: 651.33 / 340; }
	/* 32px is the component's own gutter (33223:949 px-[32px]) — it puts the headline at x=763 as drawn */
	.liv-people .liv-split-copy { max-width: 579px; padding: 0 0 0 32px; }
	/* Client pin 124: "shift the h1/copy up". .liv-split-grid centres the copy against the image
	   cluster (align-items:center, line ~1780). With a third photo row the cluster grew ~294px,
	   so centring pushed the headline further down the band — the copy did not move, the images
	   grew around it. Aligning the copy to the top of the grid row is the actual ask, and it is
	   scoped to .liv-people so every other .liv-split band keeps the centred treatment. */
	.liv-people .liv-split-grid { align-items: start; }
	/* WHY row-c spans the grid: client pin 160 (2026-08-31) — "this bottom row is supposed
	   to be an extension of the row above it, essentially wrapping around beneath the copy".
	   The pattern moves row-c out of the cluster to be a direct grid child (source order:
	   cluster, copy, row-c), and this rule stretches it under both columns. 1300/280 keeps
	   its image height equal to rows a/b (cluster is 591/1300 of the grid; 591fr basis). */
	/* Merged bottom row — client 2026-09-02: "row b and row c need to be combined". Row B sat at
	   x0..651 and row C at x606..1440, so they overlapped horizontally and could only stack, leaving
	   dead beige to the right of B and to the left of C. One full-bleed row of four closes both voids.
	   Row C keeps its Figma 33469:1212 size EXACTLY (373.106 + 14.33 + 447 = 834.43, right edge on
	   1440); the old row-B pair is re-fitted into the 591.67 that remains on the left, holding its own
	   389:248 ratio. 352.7 + 224.6 + 373.106 + 447 + three 14.33 gaps = 1440. Height follows row C's
	   280, not row A's 340, because a single grid row has one aspect-ratio and 280 is the value the
	   Figma frame actually specifies. */
	.liv-people .liv-split-grid > .liv-people-row-c { grid-column: 1 / -1; width: 100%; aspect-ratio: 1440 / 280; grid-template-columns: 352.7fr 224.6fr 373.106fr 447fr; margin-top: 14.33px; }
}

/* WHY two row groups and not one 2x2 grid: the rows MIRROR each other — portrait+landscape, then
   landscape+portrait. A single grid cannot express that without per-cell column placement, and
   the Figma is literally two row frames (33290:978 / 33290:984). */
.liv-people-cluster { display: flex; flex-direction: column; gap: 14.33px; }
.liv-people-row { display: grid; gap: 14.33px; aspect-ratio: 591 / 280; } /* 14.33 = client spec 2026-09-02 (was 14) */
.liv-people-row-a { grid-template-columns: 203.567fr 373.106fr; } /* 33290:979 portrait + 33290:980 landscape */
/* Client pin 124/125 (2026-08-18): "can we shift the h1/copy up and add another row of images
   below it?", with the two photos supplied on pin 125. Row C continues the mirror the design
   establishes — A is portrait+landscape, B is landscape+portrait, so C returns to
   portrait+landscape and reuses row-a's exact column ratio. No new ratio is invented. */
.liv-people-row-c { grid-template-columns: repeat(2, 1fr); aspect-ratio: 591 / 574.33; } /* mobile: the merged 4-up row wraps 2x2, so it needs two rows of height — 280 + 14.33 gap + 280. The desktop rule below overrides both. */
/* pin 160: row-c now lives OUTSIDE .liv-people-cluster (direct split-grid child), so the
   cluster's .liv-split-img figure/img crop rules no longer reach it. Same declarations,
   keyed off the row class, so its images crop to the row box instead of dictating height. */
.liv-people .liv-people-row figure { margin: 0; height: 100%; min-height: 0; }
.liv-people .liv-people-row img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* WHY aspect-ratio on the ROW with height:100% cells, rather than a ratio on each cell: both cells
   in a row are exactly 280 tall in the design, and fr columns plus independent per-cell ratios
   drift a fraction of a pixel at some widths — which shows up as a 1px step between neighbours.
   One ratio on the row means the two cells cannot disagree at any viewport.
   Scoped `.liv-people .liv-split-img img` (0,2,1) so it beats `.liv-split-img img`'s base rule AND
   its desktop height:556px without depending on source order. NO border-radius: the design's
   corners are square (pixel-sampled off the render), unlike .liv-value-card / .liv-job-card. */
.liv-people .liv-split-img figure { margin: 0; height: 100%; }
.liv-people .liv-split-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* WHY (client 2026-09-02): "we don't need the 'feet 6 inches deep' caption below the third image".
   It is not a caption — it is the pool-deck depth marking painted into careers-people-5 itself, so
   there is no markup to remove. The source is portrait (768x984) in a 373x280 landscape cell, which
   leaves ~198px of vertical overflow; at the default 50% the window centres and lands on the deck
   text. 32% lifts it clear while keeping her feet inside the frame, and it reads closer to Figma
   33469:1213, which shows the pool rather than the deck. Revert = drop this rule. */
.liv-people .liv-people-row-c > figure:nth-child(3) img { object-position: 50% 32%; }

/* ---- Our Approach six-service wheel ----
   NAME CORRECTED 2026-08-19: this block was headed "Your Amenity hub-and-spoke diagram", which is
   a DIFFERENT graphic (Figma 33186:8551 / 33066:8499, attachment 71) that no published post uses.
   .liv-diagram has only ever carried the wheel on the live site — wp_block 85 (EN) / 353 (FR). */
/* Mobile side padding 20 -> 8: client pin 91 "graphic should be larger on mobile". The image
   is already width:100%, so the ONLY lever at this width is the band's own gutter — 8px gains
   ~7% (350 -> 374 at a 390 viewport). Worth saying plainly: that is the whole budget available
   without going edge-to-edge. The desktop max-width increase of 2026-08-19 does NOT help here —
   374 is below any cap, so phones get only the ~2% the artboard's tighter margins give back.
   If the client wants it substantially larger on a phone, the real fix is still a portrait/stacked
   variant of the artwork: at the artboard's 1.66:1 a landscape diagram in a 375px column can only
   ever be ~225px tall (it was ~265px at the old 1.41:1 — the wheel itself is bigger, but the
   picture is shorter). */
.liv-diagram { position: relative; padding: 40px 8px; }
.liv-diagram-circle {
	width: 200px;
	height: 200px;
	border-radius: 50%;
	background: linear-gradient(180deg, #9B7B5E 0%, #D0DEDF 100%);
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0 auto;
}
.liv-diagram-chip {
	background: var(--wp--preset--color--theme-04);
	border-radius: 4px;
	padding: 12px 24px;
	text-align: center;
}
.liv-diagram-chips { row-gap: 16px; }
@media (min-width: 1024px) {
	/* WHY not the Figma 95px both sides (33186:8551) any more: client pins 86 + 87 (2026-08-18).
	   86 "shift it up slightly" -> top 95 -> 64. 87 "space between the graphic and next quad can
	   be a little tighter" -> bottom 95 -> 72, which is spacing-70's desktop value, i.e. one
	   preset step down rather than an invented number.
	   The two are kept ASYMMETRIC on purpose: equal padding would shrink the band without the
	   graphic moving up inside it, and "shift it up" is the half of the request that needs the
	   top gap to be the smaller one. */
	.liv-diagram { padding: 64px 60px 72px; }
	.liv-diagram-circle { width: 220px; height: 220px; }
}

/* ---- standalone page hero band (Get In Touch 33210:9571 / 33213:8308, Careers 33210:9601) ----
   The "Header Hero Sections" component: navy band, line-pattern texture, eyebrow + title + rule,
   left-aligned on Get In Touch and centered on Careers. */
.liv-page-hero { position: relative; overflow: hidden; padding: 40px 20px; } /* WHY: Figma 33213:8308 mobile frame padding 40/20 */
/* WHY: pattern removed 2026-07-30 (client round 3, rule d "remove from hero"). Dropping it
   here also clears rule b on /markets/ and /careers/, where the hero sat directly above the
   Markets grid and the Jobs grid as quads 1-2. */
.liv-page-hero > * { position: relative; }
.liv-page-hero-center { text-align: center; }
/* WHY: Figma 33210:9611 body column is 876px; 33210:9612 carries both paragraphs in one
   TEXT node split at "\n\n" — the blank line is one 30px line box, so p2 gets a 30px gap
   (same treatment as the cd intro split in pattern 88). */
.liv-page-hero-body { max-width: 876px; margin-left: auto; margin-right: auto; }
/* WHY: hero H1 tracks its own scale — Figma 33213:8313 mobile 56/500/lh1.2/-0.05em,
   33210:9578 + 33210:9607 desktop 79/400/lh1.0/-0.06em (section titles use lh 1.1). */
.liv-hero-title { font-weight: 500; letter-spacing: -0.05em; line-height: 1.2; }
@media (min-width: 1024px) {
	.liv-page-hero { padding: 68px 60px; } /* WHY: Figma 33210:9571/9601 frame padding 68px top/bottom */
	/* WHY: textCase TITLE on the desktop artboards (33210:9578/9607) only — the mobile
	   hero (33213:8313) is ORIGINAL, so this must not leak below 1024 */
	.liv-hero-title { font-weight: 400; letter-spacing: -0.06em; line-height: 1; text-transform: capitalize; }
}
/* WHY: Figma 33210:9573 content column is 1174px inside the 1440 frame = 133px side inset */
@media (min-width: 1024px) { .liv-page-hero:not(.liv-page-hero-center) { padding-left: 133px; padding-right: 133px; } }

/* ── Prose pages (Terms of Use, Accessibility) — added 2026-08-05, Teamwork #46241431.
   WHY these get their own small block instead of reusing .liv-tcards or .liv-intro:
   they are the FIRST pages on this build with no Figma reference and no
   banner/intro/cards structure — long-form legal copy, where the only real design
   requirement is a readable measure and an even vertical rhythm.
   NOTE the two things deliberately NOT done here:
     * the reading measure is a contentSize:800px block ATTRIBUTE on .liv-prose-body,
       not a width here — rung-1 beats rung-3 on this build;
     * paragraph rhythm is a blockGap:24px attribute on the same group, so an editor
       can retune it in the Site Editor without touching CSS.
   Only the things blockGap cannot express live below. */
.liv-prose { padding: 40px 20px; }
.liv-prose-body > .liv-prose-h { margin-top: 40px; } /* WHY: blockGap is uniform; a numbered section heading needs more air above it than sits between two paragraphs, or the 19 sections read as one wall */
.liv-prose-body > .liv-prose-h:first-child { margin-top: 0; }
.liv-prose-h { font-size: 1.5625rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1.2; } /* WHY: mirrors .liv-card-title — .liv-sec-title is the display treatment and is far too large repeated 19 times down a legal page */
.liv-prose ul { padding-inline-start: 24px; } /* WHY: same call as .liv-tcard ul — the browser default 40px eats the measure */
.liv-prose li + li { margin-top: 12px; }
.liv-prose-meta { opacity: 0.7; } /* WHY: "Last Modified" is a footnote, not body copy */
@media (min-width: 1024px) {
	.liv-prose { padding: 68px 60px; } /* WHY: matches .liv-page-hero above it so hero -> body reads as one page, not two stacked bands */
	.liv-prose-h { font-size: var(--wp--preset--font-size--x-large); font-weight: 500; }
	.liv-prose-body > .liv-prose-h { margin-top: 56px; }
}
/* WHY: Figma 33213:8310 stacks eyebrow/title, rule and contact rows at 24px; desktop
   33210:9574 tightens to 32px but 33210:9573 opens the contact row to 62px. */
@media (min-width: 1024px) {
	.liv-page-hero { gap: 32px; }
	.liv-page-hero > .liv-ci { margin-top: 30px; }
}

/* ---- hero contact rows (Figma 33210:9581 desktop / 33213:8318 mobile) ---- */
.liv-ci-item { flex-direction: row; align-items: center; } /* WHY: Figma 33213:8319 mobile pill sits beside its label */
.liv-ci-pill { padding: 4px 16px; } /* WHY: Figma 33213:8320 pill is 52x28 (20px icon + 16px side padding) */
.liv-ci-icon { margin: 0; }
.liv-ci-icon img { display: block; }
.liv-ci-text { font-weight: 500; letter-spacing: 0; } /* WHY: Figma 33213:8323 mobile 19/500/lh1.2 */
@media (min-width: 1024px) {
	/* WHY: Figma 33210:9581 is a 3-up row of 280/280/344 columns, pill stacked above the
	   label with a 16px gap (33210:9582); pill 104x56 = 40px icon + 32px side padding. */
	.liv-ci { flex-direction: row; gap: 0; }
	.liv-ci-item { flex-direction: column; align-items: flex-start; width: 280px; }
	.liv-ci-item:last-child { width: auto; }
	.liv-ci-pill { padding: 8px 32px; }
	.liv-ci-icon img { width: 40px !important; }
	.liv-ci-text { font-weight: 700; letter-spacing: -0.03em; }
}

/* ---- careers job-card grid (Figma 33210:9614 desktop / 33213:8338 mobile) ----
   Same "Feature Grid Icons" band as Markets: cream base + the 18deg teal fade (theme.json
   styles.css) + line-pattern texture. Cards reuse .liv-market-card (320x237 / r16 / chip). */
.liv-jobs { position: relative; padding: 40px 20px; }
.liv-jobs::before {
	content: "";
	position: absolute;

	/* WHY: was anchored center-bottom; the weave keeps that bias as a
	   bottom-up mask fade */
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-beige)); /* beige theme-05 band, full bleed */
	pointer-events: none;
}
.liv-jobs > * { position: relative; }
/* WHY: Figma 33213:8340 mobile title-to-cards gap is 16 — below the root 24px blockGap,
   so the grid's own margin-top has to be zeroed or it wins the collapse and yields 24 */
.liv-jobs > .liv-sec-head { margin-bottom: 16px; }
.liv-jobs > .liv-sec-head + * { margin-top: 0; }
.liv-sec-rule-sm { width: 64px; } /* WHY: Figma 33213:8344 careers mobile rule is 64x4, not home's 150x4 */
/* WHY: unlike .liv-market-card (chip absolute over a reserved 73px band, Figma 33186:8340),
   the job card keeps its chip IN FLOW: Figma 33213:8347 is a padding-16 row [body | chip]
   bottom-aligned, and 33210:9622 is a padding-24 column with SPACE_BETWEEN (33210:9623).
   Padding is a uniform 16/24 at both viewports as a result. */
.liv-job-card { width: 100%; flex-direction: row; flex-wrap: nowrap; align-items: flex-end; padding: 16px; }
/* WHY: basis 0 + min-width 0 — at auto basis the copy column measures wider than the row
   and the chip wraps to its own line, growing the 147px Figma card to 187 (33213:8347) */
.liv-job-card > .wp-block-group { flex: 1 1 0; min-width: 0; }
.liv-job-card .liv-chip { margin: 0; }
.liv-job-card .liv-chip img { width: 25px !important; }
@media (min-width: 1024px) {
	.liv-jobs { padding: 95px 60px; } /* WHY: Figma 33210:9614 section padding 95/60 */
	.liv-jobs > .liv-sec-head { margin-bottom: 54px; } /* WHY: Figma 33210:9614 itemSpacing 54 */
	.liv-sec-rule-sm { width: 112px; } /* WHY: Figma 33210:9619 desktop rule returns to 112x7 */
	/* WHY: Figma 33210:9622 is a fixed 320x237 box, padding 24, arrow on its own row */
	.liv-job-card { width: 320px; min-height: 237px; flex-direction: column; align-items: stretch; justify-content: space-between; padding: 24px; }
	.liv-job-card > .wp-block-group { flex: 0 0 auto; min-width: auto; }
	/* WHY: in the desktop column the chip must not stretch to the card width — Figma
	   33210:9630 sits 33x33 hard against the right padding edge of 33210:9622 */
	.liv-job-card .liv-chip { align-self: flex-end; }
	.liv-job-card .liv-chip img { width: 33px !important; }
	/* WHY: Figma 33210:9626 job titles are 33/500/lh1.2 on desktop; the shared .liv-card-title
	   stays 25/700 (which is exactly the mobile spec, 33213:8351). */
	.liv-job-card .liv-card-title { font-size: var(--wp--preset--font-size--x-large); font-weight: 500; }
}

/* ---- Subtle motion pass (client review 2026-07-31 — Conor: "sections should fade in and
   slide up slightly as they scroll into view", "card and service images should have a
   subtle zoom on hover", "nav and menu interactions should transition smoothly",
   "nothing flashy").

   REFERENCE NUMBERS ARE NOT INVENTED. Both sites named in the review
   (charlestownehotels.com, hotelbethlehem.com) run the same platform — Tambourine
   "symphony" — and share ONE motion primitive: a single `.animate-fade` class doing
   `opacity 0->1` + `translateY(100px)->0` over `all 1.2s cubic-bezier(0.18, 0.32, 0.17,
   0.99)`, `.2s/.4s/.6s` nth-child stagger on grid items, and `transform: scale(1.1)` over
   `transform 0.6s` + `backface-visibility: hidden` on card photos.

   Their EASING and their IMAGE-ZOOM TIMING are adopted verbatim. Their 1.2s/100px travel
   is NOT: 100px reads as a lift, and the ask was "slide up SLIGHTLY". Tuned to 700ms/32px
   (client call 2026-07-31). All four values are :root vars, so the next tuning round is a
   var edit — same contract as --liv-line-pattern-fade-*.

   NO DB WRITES. The theme's own reveal system (.is-style-reveal-* + motion.js) needs a
   class authored per block, i.e. an edit to every pattern row in wp_block. liv-ui.js tags
   sections by selector at runtime instead, so this whole pass is CSS + JS only.

   GATE SAFETY: qa-lib.mjs opens every page with Playwright `reducedMotion: 'reduce'`, the
   global prefers-reduced-motion block at the top of this file zeroes durations, and
   liv-ui.js skips the whole module when that media query matches — so nothing is ever
   hidden or offset when the 1084-check suite measures. Three independent belts because a
   half-revealed section would silently corrupt every bbox, height and pixel gate. */
:root {
	--liv-reveal-rise: 32px;
	--liv-reveal-dur: 700ms;
	--liv-reveal-stagger: 90ms;
	--liv-reveal-ease: cubic-bezier(0.18, 0.32, 0.17, 0.99);
}
/* WHY transform + opacity only: both are compositor-driven, so a dozen sections armed at
   once cost no layout. `transform` does establish a containing block, but every absolutely
   positioned thing inside these bands (the ::before line-pattern overlay, .liv-chip, the
   stretched card-title anchor) is already scoped to the band, so nothing re-anchors. */
.liv-reveal {
	opacity: 0;
	transform: translateY(var(--liv-reveal-rise));
	transition:
		opacity var(--liv-reveal-dur) var(--liv-reveal-ease),
		transform var(--liv-reveal-dur) var(--liv-reveal-ease);
	will-change: opacity, transform;
}
/* will-change is dropped on arrival — leaving a promoted layer per section on an 11-section
   page is exactly the memory cost the property warns about, and it is worthless once the
   transition has run. */
.liv-reveal.is-revealed {
	opacity: 1;
	transform: none;
	will-change: auto;
}
/* Cards arrive in sequence rather than as one slab. The reference does this with
   nth-child(3n+1/2/3) delays, which stagger by COLUMN position — meaningless once the grid
   collapses to one column on mobile, where 3n+1 makes cards 1 and 4 fire together. Driven
   off an index liv-ui.js writes instead, so document order always wins.
   Fade only, no second translate: the section box is already travelling 32px and stacking
   another rise on the children doubles it into exactly the "flashy" the review ruled out. */
.liv-reveal .liv-reveal-item {
	opacity: 0;
	transition: opacity var(--liv-reveal-dur) var(--liv-reveal-ease);
	transition-delay: calc(var(--liv-reveal-i, 0) * var(--liv-reveal-stagger));
}
.liv-reveal.is-revealed .liv-reveal-item { opacity: 1; }
/* Belt-and-braces with the global block above: that one zeroes DURATION, this one holds the
   end STATE, so a reduced-motion visitor can never land on a hidden or offset section. */
@media (prefers-reduced-motion: reduce) {
	.liv-reveal,
	.liv-reveal .liv-reveal-item {
		opacity: 1;
		transform: none;
	}
}

/* ---- Hover zoom on card photography (client review 2026-07-31).
   scale + 600ms are the reference's own numbers; the AMOUNT is 1.06, not their 1.1 —
   .gridServ_pic there is a full-bleed 3-up tile, ours is a 344px card photo where 1.1 crops
   visibly into the subject. `backface-visibility: hidden` is theirs too and is load-bearing,
   not cargo: without it the upscaled bitmap shimmers mid-transition in Safari.

   SCOPE: the two card types that actually carry a photo. .liv-card is the homepage services
   grid — Conor's "card AND service images" are the same six elements — and .liv-tcard-photo
   is the wide markets card. .liv-market-card and .liv-job-card are title + excerpt + chip
   with NO image, so they keep the chip-colour + arrow-nudge states they already have.
   Deliberately NOT applied to .liv-wide-cover / .liv-contact-cover (full-width bands whose
   hover target is the whole viewport width) or .liv-banner-img / the hero (above-fold).

   @media (hover: hover) so a touch tap does not park a card in the zoomed state. */
@media (hover: hover) {
	/* .liv-card already clips (radius, line 668); .liv-tcard-photo does not, and an
	   unclipped scale would push the photo out over the card's copy column. */
	.liv-card-img,
	.liv-tcard-photo { overflow: hidden; }
	.liv-card-img img,
	.liv-tcard-photo img {
		transition: transform 600ms var(--liv-reveal-ease);
		backface-visibility: hidden;
	}
	/* Keyed off the CARD, not the image: on .liv-card the stretched title anchor already
	   covers the whole box, so hovering the copy and hovering the photo must agree. */
	.liv-card:hover .liv-card-img img,
	.liv-card:focus-within .liv-card-img img,
	.liv-tcard:hover .liv-tcard-photo img { transform: scale(1.06); }
}

/* ---- Flyout menu transitions (client review 2026-07-31, hotelbethlehem.com as the
   reference for "nav and menu interactions should transition smoothly").
   The panel slide-in (380ms) and scrim fade (260ms) already shipped in review round 2;
   what was missing is everything INSIDE the panel arriving as one hard block.

   Written as `animation`, not `transition`, for the same reason as liv-nav-slide-in above:
   core flips these from display:none in the same frame it adds .is-menu-open, and a
   transition on a just-displayed element does not run.

   Delays start at 140ms so the items trail the panel edge instead of racing it. */
@keyframes liv-nav-item-in {
	from { opacity: 0; transform: translateX(-12px); }
	to   { opacity: 1; transform: translateX(0); }
}
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item {
	animation: liv-nav-item-in 420ms var(--liv-reveal-ease) both;
}
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:nth-child(1) { animation-delay: 140ms; }
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:nth-child(2) { animation-delay: 200ms; }
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:nth-child(3) { animation-delay: 260ms; }
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:nth-child(4) { animation-delay: 320ms; }
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:nth-child(5) { animation-delay: 380ms; }
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:nth-child(6) { animation-delay: 440ms; }
.liv-nav .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:nth-child(n+7) { animation-delay: 500ms; }
/* WHY the submenu CONTENT animates but the accordion BOX does not: the open/close toggle
   above is a `display: none` swap. Animating the box would mean converting it to the
   grid-template-rows 0fr->1fr trick, which collides with the display:flex + gap + padding
   layout the nav gates measure (34/34 currently pass). Fading the links in as the box
   appears softens the snap for none of that risk. Same convention as the "CLOSING IS NOT
   ANIMATED" note on the panel above — flag if the box itself is wanted. */
@keyframes liv-nav-sub-in {
	from { opacity: 0; transform: translateY(-6px); }
	to   { opacity: 1; transform: translateY(0); }
}
.liv-nav .is-menu-open .wp-block-navigation__submenu-container > .wp-block-navigation-item {
	animation: liv-nav-sub-in 300ms var(--liv-reveal-ease) both;
}
.liv-nav .is-menu-open .wp-block-navigation__submenu-container > .wp-block-navigation-item:nth-child(2) { animation-delay: 45ms; }
.liv-nav .is-menu-open .wp-block-navigation__submenu-container > .wp-block-navigation-item:nth-child(3) { animation-delay: 90ms; }
.liv-nav .is-menu-open .wp-block-navigation__submenu-container > .wp-block-navigation-item:nth-child(4) { animation-delay: 135ms; }
.liv-nav .is-menu-open .wp-block-navigation__submenu-container > .wp-block-navigation-item:nth-child(5) { animation-delay: 180ms; }
.liv-nav .is-menu-open .wp-block-navigation__submenu-container > .wp-block-navigation-item:nth-child(n+6) { animation-delay: 225ms; }
/* Caret eases through its flip instead of snapping. The rotate is restated rather than
   relied on: core rotates the icon on [aria-expanded=true], but this build re-declares the
   icon to survive the modal reset, so pinning both here keeps the two in sync if core's
   selector ever moves. */
.liv-nav .is-menu-open li.wp-block-navigation-submenu > button.wp-block-navigation__submenu-icon svg {
	transition: transform 260ms var(--liv-reveal-ease);
}
.liv-nav .is-menu-open li.wp-block-navigation-submenu > button.wp-block-navigation__submenu-icon[aria-expanded="true"] svg {
	transform: rotate(180deg);
}
/* WHY a hover state exists at all now: flyout links had NONE — nothing to transition
   smoothly. theme-03 is the panel's existing accent (close X, hero dots), so this
   introduces no new colour. NOTE: this is a NEW interaction state, not a Figma-derived one —
   33186:10175 does not spec a link hover. Flag to the designer. */
.liv-nav .is-menu-open .wp-block-navigation-item__content {
	transition: color 200ms var(--liv-reveal-ease);
}
.liv-nav .is-menu-open .wp-block-navigation-item:not(.liv-nav-pill) > .wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--theme-03);
}
/* the mobile RAP pill already owns hover/active/focus — just ease them */
.liv-nav .is-menu-open .liv-nav-pill .wp-block-navigation-item__content {
	transition: background-color 200ms var(--liv-reveal-ease), color 200ms var(--liv-reveal-ease);
}

/* ── Performance & Insights index — added 2026-08-06, Figma 33260:1793
   (INTERNAL_LIVunLtd wDcFRJVW9opHrC3i5AaoXu). Client review pin 14/19 destination.
   WHY a new block rather than reusing .liv-jobs or .liv-tcards: this is the first
   POST-driven grid on the build (core `post` + `category`), so the card is a Query Loop
   post-template, not hand-authored markup — the chip has to sit in flow inside a
   post-excerpt sibling rather than being absolutely placed in a reserved band.
   NOTE: desktop-only artboard, like every inner page here. Mobile is an inference
   (single column), NOT a Figma measurement — flag it if the client reviews on mobile. */
.liv-pi { padding: 40px 20px; }
/* WHY 1320px: Figma cards are 644 + 32 gap + 644 inside the 1440 frame at 60px side
   margins. Pinning the measure here keeps the grid honest at any wider viewport. */
.liv-pi .liv-pi-query { max-width: 1320px; margin-inline: auto; }

/* Filter pills. Figma 33260:1906 — row 1145x52 centred in the 1440 frame (=147.5 inset),
   five `simple button` instances at a uniform 16px gap. They are real links to the
   category archives so they work with JS off; liv-ui.js intercepts for in-page filtering. */
.liv-pi-filters { gap: 16px; justify-content: center; flex-wrap: wrap; }
.liv-pi-filter .wp-block-button__link {
	min-height: 52px;
	display: inline-flex;
	align-items: center;
	text-transform: uppercase;
	white-space: nowrap;
	transition: background-color 200ms var(--liv-reveal-ease), color 200ms var(--liv-reveal-ease);
}
/* WHY the active state is a class and not :focus/:target — the filter is a client-side
   view state that must survive losing focus, and more than one pill can never be active. */
.liv-pi-filter.is-active .wp-block-button__link {
	background-color: var(--wp--preset--color--theme-03);
	border-color: var(--wp--preset--color--theme-03);
	color: var(--wp--preset--color--theme-01);
}

/* Cards. Figma 33260:2058 — 644x599: image 644x429 (=3/2), body inset 24, 24px gap under
   the image, 24px bottom padding. */
.liv-pi-grid { gap: 32px; }
.liv-pi-card { overflow: hidden; height: 100%; display: flex; flex-direction: column; }
.liv-pi-media { margin: 0; }
.liv-pi-media img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block; }
/* WHY the body is a positioning context: the chip is the last child in flow but Figma puts
   it bottom-RIGHT beside the text column (33260:2070 at x563 of the 596 body), so it is
   pulled out of the stack rather than given its own row. */
.liv-pi-body { position: relative; padding: 24px; padding-right: 81px; flex: 1; }
.liv-pi-eyebrow { letter-spacing: 0.02em; }
.liv-pi-eyebrow a { text-decoration: none; color: inherit; }
/* WHY 28px/700: that is an existing pair in the design system — the services manifest
   carries Cormorant w700@28 for the same card-title role. */
.liv-pi-title { font-size: 28px; font-weight: 700; line-height: 1.2; margin: 0; }
.liv-pi-title a { text-decoration: none; color: inherit; }
.liv-pi-excerpt { margin: 0; }
.liv-pi-card figure.liv-chip { position: absolute; right: 24px; bottom: 24px; margin: 0; }
.liv-pi-empty { padding: 40px 0; }

@media (min-width: 1024px) {
	/* WHY 54px: the Figma band is 803 tall = 54 top + 52 pills + 44 + 599 cards + 54 bottom. */
	.liv-pi { padding: 54px 60px; }
	/* WHY 44px: gap between the pill row (ends y106) and the card grid (starts y150). */
	.liv-pi .liv-pi-query { margin-top: 44px; }
	.liv-pi-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ── Blog single (wp_template 205 `single`) — added 2026-08-06.
   Derived from the Performance & Insights card (Figma 33260:2058), which has no single-post
   frame of its own: the card's eyebrow -> title order becomes category -> H1 in the hero,
   and its 3:2 image becomes the featured image. Body reuses .liv-prose wholesale so an
   article reads on the same 800px measure and 24px rhythm as Terms of Use.
   NOTE: inferred, NOT a designed frame. Flag for the designer alongside pin 19. */
.liv-post-cats a { color: inherit; text-decoration: none; }
.liv-post-cats a:hover,
.liv-post-cats a:focus-visible { text-decoration: underline; }
/* WHY 0.7: the date is a footnote under the title, same call as .liv-prose-meta */
.liv-post-date { opacity: 0.7; }
.liv-post-media-band { padding: 0 20px; }
/* WHY :has() — post-featured-image renders NOTHING when the post has no thumbnail, which
   would otherwise leave an empty padded band between the hero and the body. */
.liv-post-media-band:not(:has(img)) { display: none; }
/* WHY 3/2: the card image is 644x429 in Figma; keeping the ratio means an editor's upload
   is cropped the same way in the grid and on the article.
   WHY the max-height: at the 1440 wide measure a true 3:2 is 960px tall, which pushes the
   whole article below the fold on a laptop. Capping keeps the card's crop feel without
   letting the image dominate. INFERRED — there is no single-post frame in Figma. */
.liv-post-media img {
	width: 100%;
	aspect-ratio: 3 / 2;
	max-height: 560px;
	object-fit: cover;
	display: block;
}
/* WHY pulled up: the image band and the body band share theme-08, so the image should read
   as the top of the article, not as a third stacked band. */
.liv-post-body { padding-top: 40px; }
/* WHY these and not blockGap: on the prose PAGES the rhythm is a blockGap attribute on
   .liv-prose-body, but an article's copy lives inside core/post-content, and blockGap does
   not cross that boundary — the editor's blocks are children of post-content, not of the
   group. Targeting the tag rather than a class matters too: someone writing a post in the
   editor inserts a plain Heading, never a .liv-prose-h. */
.liv-post-body .wp-block-post-content > * + * { margin-top: 24px; }
.liv-post-body .wp-block-post-content > :is(h2, h3, h4) { margin-top: 40px; }
.liv-post-body .wp-block-post-content > :first-child { margin-top: 0; }
/* match .liv-prose-h so an article heading reads like a prose-page heading */
.liv-post-body .wp-block-post-content > :is(h2, h3, h4) {
	font-size: 1.5625rem;
	font-weight: 700;
	letter-spacing: -0.03em;
	line-height: 1.2;
	color: var(--wp--preset--color--theme-02);
}
/* WHY: the rule above was written when no article nested headings, so it sizes h2-h4 alike.
   The migrated posts (Teamwork #46453203) put an expert take under each trend heading, and
   at one size the two levels read as one list. */
.liv-post-body .wp-block-post-content > :is(h3, h4) { font-size: 1.25rem; margin-top: 32px; }
.liv-post-back { margin-top: 40px; }
.liv-post-back a { color: var(--wp--preset--color--theme-03); text-decoration: none; }
.liv-post-back a:hover,
.liv-post-back a:focus-visible { text-decoration: underline; }
@media (min-width: 1024px) {
	.liv-post-media-band { padding: 0 60px; }
	.liv-post-body { padding-top: 56px; }
	.liv-post-back { margin-top: 56px; }
	/* mirrors .liv-prose-h at the desktop breakpoint */
	.liv-post-body .wp-block-post-content > :is(h2, h3, h4) {
		margin-top: 56px;
		font-size: var(--wp--preset--font-size--x-large);
		font-weight: 500;
	}
	.liv-post-body .wp-block-post-content > :is(h3, h4) {
		margin-top: 40px;
		font-size: var(--wp--preset--font-size--large);
	}
}

/* ── Flyout secondary nav — added 2026-08-06, client review pin 19.
   Ask: "add a line (in this case our branded line) below Request For Proposal and add
   our secondary navigation: CAREERS | GET IN TOUCH / PERFORMANCE & INSIGHTS", modelled
   on hotelbethlehem.com.

   WHY the three links STACK rather than reading "CAREERS | GET IN TOUCH" on one line as
   the comment draws it: core/navigation only accepts navigation-link/submenu children, so
   there is no wrapper to make a row from — the items are plain siblings of the primary
   links. Getting two of them onto one line means re-flowing the flyout's own <ul>, which
   is a flex COLUMN whose layout the surrounding rules deliberately out-specificity against
   core's modal reset. That was tried and it collapsed the whole primary stack onto one
   line, so it was reverted: a cosmetic pipe is not worth destabilising the menu.
   OPEN WITH DESIGNER: confirm the stacked treatment, or supply a Figma frame for the
   flyout secondary nav so it can be built as a proper region.

   WHY smaller + tracked: this is a tertiary tier under the primary serif stack — the same
   treatment the footer link column already uses (700 / 0.02em / uppercase). */
.liv-nav .is-menu-open .liv-nav-secondary .wp-block-navigation-item__content {
	/* font-family + line-height added 2026-08-18 for client pins 133 (desktop) / 131 (mobile):
	   "can CAREERS, GET IN TOUCH, and PERFORMANCE & INSIGHTS be the same styling as the
	   secondaries under Markets". Size/weight/tracking/case already matched the Markets
	   dropdown rule below; the ONLY difference was that these items inherited the Cormorant
	   serif from the shared .wp-block-navigation-item__content rule, which never restates the
	   family. These two declarations are the whole of that ask. Keep the two rules in sync. */
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 16px;
	font-weight: 700;
	letter-spacing: 0.02em;
	line-height: 1.5;
	text-transform: uppercase;
}

/* Markets / Services dropdown items — client 2026-08-05 pin 23: "The dropdowns for Markets
   and Services don't quite look right. What if we tried a different font type? Thinking what
   we used for SERVING CLIENTS ACROSS THE UNITED STATES AND AMERICA", then "if that doesn't
   look right, i'm open to suggestions".
   That reference is .liv-hero-eyebrow — Proxima Nova 700, uppercase, 16px. This is the
   literal reading of the ask, built so the client can judge the real thing rather than a
   description. It replaces 24px Cormorant.
   WHY font-family has to be restated: the serif comes from the shared
   .wp-block-navigation-item__content rule above, which also matches these items.
   IF THE CLIENT REJECTS IT: the likely complaint is that 16px uppercase reads as a tertiary
   tier under 40px primaries and flattens the hierarchy. The next thing to try is this same
   family at 18-20px with sentence case, NOT a return to the serif — the serif at 24px is
   what he was objecting to. */
.liv-nav .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 16px;
	font-weight: 700;
	letter-spacing: 0.02em;
	line-height: 1.5;
	text-transform: uppercase;
}
/* The branded line above the group. Same 3-layer dot-line-dot mask as .liv-rule, drawn as
   a ::before on the first secondary item and pulled up into its own margin — it cannot be
   a real element for the same reason as above (no non-link children allowed). */
/* The branded rule is centred in the space above this item, NOT hung at a fixed offset.
   WHY: client 2026-08-06 — "can we make the spacing consistent above and below the
   separator?" With the old `top: -24px` the rule sat 48px below "Request A Proposal" but
   only 17px above "CAREERS" (measured) — an obvious 3:1 imbalance.
   The space it has to centre in is the <ul>'s row-gap PLUS this item's own margin-top, and
   the offset is derived from those two values rather than hard-coded, so the rule stays
   centred if either is ever retuned. --liv-nav-row-gap must track the container's row-gap
   (24px at every breakpoint — verified 390/768/1024/1512). */
.liv-nav .is-menu-open .liv-nav-secondary-first {
	--liv-nav-row-gap: 24px;
	--liv-sec-space: 48px;
	--liv-sec-rule-h: 7px;
	position: relative;
	margin-top: var(--liv-sec-space);
}
.liv-nav .is-menu-open .liv-nav-secondary-first::before {
	content: "";
	position: absolute;
	/* half of (gap + margin + rule height) above this item's top edge = equal air both sides */
	top: calc(-1 * ((var(--liv-nav-row-gap) + var(--liv-sec-space) + var(--liv-sec-rule-h)) / 2));
	left: 0;
	width: 112px;
	height: var(--liv-sec-rule-h);
	background-color: var(--wp--preset--color--theme-03);
	-webkit-mask:
		radial-gradient(circle closest-side, #000 98%, #0000) left center / 7px 7px no-repeat,
		radial-gradient(circle closest-side, #000 98%, #0000) right center / 7px 7px no-repeat,
		linear-gradient(#000 0 0) center center / 100% 1.5px no-repeat;
	mask:
		radial-gradient(circle closest-side, #000 98%, #0000) left center / 7px 7px no-repeat,
		radial-gradient(circle closest-side, #000 98%, #0000) right center / 7px 7px no-repeat,
		linear-gradient(#000 0 0) center center / 100% 1.5px no-repeat;
}

/* ── Flyout secondary nav, two-line layout — client pins 127 (desktop) + 132 (mobile), 2026-08-18.
   "Can we stack the secondary nav so it reads: CAREERS | GET IN TOUCH / PERFORMANCE & INSIGHTS".
   SUPERSEDES the "WHY the three links STACK" note above: that was written when the layout was
   reverted after pin 19. The client has now re-asked twice, once per device board, so it is built.

   WHY `display: block !important` on the <ul>, and why the first attempt "collapsed the whole
   primary stack onto one line": core's modal reset —
   .wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay))
   .wp-block-navigation__responsive-container-content .wp-block-navigation__container — sets
   display:flex at (0,4,0), one class MORE than this theme's own container rule near the top of
   the flyout section. Without !important the ul stays a flex COLUMN no matter what we declare,
   flex-direction:row is silently dropped, and any flex-wrap:wrap then wraps the items into
   COLUMNS — which is exactly the sideways collapse that got the earlier attempt reverted.
   It was never a wrapper-element problem; it was a specificity problem.
   Block layout gives the one-per-line stack for free. `gap` does not apply in block layout, so
   the ul's 24px row rhythm is restored as margin-bottom on the items.

   WHY only the two secondaries get a display override, never `> li` as a whole: forcing display
   on every child un-hides the .liv-nav-pill duplicate "Request A Proposal", which is
   deliberately display:none at the desktop breakpoint (it is the mobile-only button).

   WHY a border-right instead of a "|" pseudo-element: the <a> inside these items fills the
   item's width, so an ::after/::before added as a flex item wraps onto a second line and the
   glyph renders UNDER "CAREERS" rather than beside it. A border cannot wrap, and it picks up
   theme-03 — the same colour as the branded rule above the group. */
.liv-nav .is-menu-open ul.wp-block-navigation__container {
	display: block !important;
}
.liv-nav .is-menu-open ul.wp-block-navigation__container > li {
	margin-bottom: var(--wp--preset--spacing--30); /* replaces the flex `gap` lost to block layout */
}
.liv-nav .is-menu-open ul.wp-block-navigation__container > li:last-child {
	margin-bottom: 0;
}
/* CAREERS and GET IN TOUCH share a line; PERFORMANCE & INSIGHTS stays a block and drops below. */
.liv-nav .is-menu-open ul.wp-block-navigation__container > li.liv-nav-secondary-first,
.liv-nav .is-menu-open ul.wp-block-navigation__container > li.liv-nav-secondary:not(.liv-nav-secondary-first):not(.liv-nav-secondary-break) {
	display: inline-flex !important;
	width: auto;
	vertical-align: baseline;
	margin-bottom: 0;
}
.liv-nav .is-menu-open ul.wp-block-navigation__container > li.liv-nav-secondary-first {
	/* WHY 10px both sides: client pin 174 (2026-08-31) — "divider should be equidistant
	   between Careers and Get In Touch, and spacing slightly tighter" (was 14/14, but the
	   GET IN TOUCH anchor carries its own left padding that made the right gap read wider —
	   the padding kill below is part of the same fix). */
	border-right: 1.5px solid var(--wp--preset--color--theme-03);
	padding-right: 10px;
	margin-right: 3px; /* 3px + the ~8px inline whitespace between the inline-flex <li>s = the 11px on the padding side (measured 2026-08-31) */
}
.liv-nav .is-menu-open ul.wp-block-navigation__container > li.liv-nav-secondary:not(.liv-nav-secondary-first):not(.liv-nav-secondary-break) .wp-block-navigation-item__content {
	padding-left: 0; /* pin 174: any core left padding on the GET IN TOUCH anchor unbalances the divider */
}
.liv-nav .is-menu-open ul.wp-block-navigation__container > li.liv-nav-secondary-break {
	margin-top: var(--wp--preset--spacing--30);
}
/* ---- /team/ — leadership + development services (Teamwork #46332661) ----
   Figma 33352:1176 (section + cards) and 33362:1626 (bio pop-up), client hand-off
   2026-08-19. These supersede the ticket's opening "same format as
   amenitycollective.com/team/" line — the artboards are a different design, and the
   only thing kept from the sibling site is the click-a-card-open-a-bio behaviour.

   Everything here is responsive geometry the spacing presets cannot express (a 5-up
   row that steps down to 2, the card's split photo/navy-footer proportions, the
   two-column pop-up), which is what this file is for. Markup: inc/team-grid-block.php.
   Wiring: initTeamModals() in assets/js/liv-ui.js. */

/* ---- the band ----
   WHY the gradient rather than a flat fill: Figma 33352:1176 paints theme-04 fading in
   at 11.74deg over a theme-05 base, so the band reads light blue at the bottom-right
   and beige at the top-left. The angle and stops are the designer's numbers.
   WHY the pattern opacity is calc()'d off --liv-line-pattern-fade-blue rather than the
   artboard's flat 3%: the client has twice asked for a GLOBAL reduction on this texture
   (round 3 pin 2, then again 2026-08-07), and those requests are carried in the two
   fade multipliers. Hard-coding 3% here would quietly opt this band out of the next
   one. Blue multiplier because the band reads as one of the light-blue bands. */
.liv-team-section {
	position: relative;
	padding: 48px 20px;
	background-color: var(--wp--preset--color--theme-05);
	background-image: linear-gradient(
		11.74deg,
		rgba(208, 222, 223, 0) 1.72%,
		rgba(208, 222, 223, 1) 43.13%
	);
}

.liv-team-section::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--liv-line-pattern) center / var(--liv-line-pattern-size) repeat;
	opacity: calc(0.12 * var(--liv-line-pattern-fade-blue));
	pointer-events: none;
}

.liv-team-section > * { position: relative; }

/* The artboard has no rule under the heading — unlike every other section on the site,
   which is why .liv-sec-head-center is used without a .liv-sec-rule sibling. */
.liv-team-section > .liv-sec-head { margin-bottom: 32px; }

/* ---- grid ----
   WHY flex-wrap + justify-content:center and not a grid: the groups are 8 and 4 against
   a 5-up row, so both end short (5/3 and 4). A grid left-aligns that remainder and the
   row reads as though it lost a card; centring it makes an odd headcount look
   deliberate. The basis calculation pins the cards to the width a grid would have given
   them. Card is 256px wide at the 8px gap in the artboard; below the desktop
   breakpoint it drops to two per row, which is the only way a 256px card and its
   24px-padded footer stay legible on a phone. */
.liv-team { --liv-team-cols: 5; --liv-team-gap: 8px; }

.liv-team-grid {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--liv-team-gap);
}

.liv-team-card {
	flex: 0 0 calc((100% - var(--liv-team-gap)) / 2);
	min-width: 0;
}

/* WHY align-items is pinned to stretch: Chrome's UA stylesheet sets `align-items:
   center` on <button>, so the photo and footer shrink-wrap their content instead of
   filling the card. Cards with a real headshot got away with it — `width:100%` on an
   <img> inside a shrink-to-fit box resolves against the image's intrinsic 980px and
   then clamps to the card — but the lettered placeholder collapsed to the width of the
   two initials, about 56px. Stretch makes both cases deterministic. */
.liv-team-trigger {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 16px;
	width: 100%;
	height: 100%;
	padding: 0 0 10px; /* WHY 10 (was 16): client pin 148 (2026-08-31) — tighten the air between the job title and the bottom of the navy card footer */
	border: none;
	border-radius: 16px;
	background: var(--wp--preset--color--theme-02);
	font: inherit;
	color: var(--wp--preset--color--theme-01);
	text-align: left;
	cursor: pointer;
	overflow: hidden;
}

.liv-team-photo {
	position: relative; /* positioning context for the hover frame + View Bio tab */
	display: block;
	overflow: hidden;
	border-radius: 16px 16px 4px 4px; /* Figma: 16px top corners, 4px bottom */
}

/* WHY aspect-ratio and not a fixed 256px height: the artboard's photo slot is square
   (256x256) and every headshot the client sent is a different shape (350x350 through
   2700x4050). A square box with object-fit gives one consistent card whatever lands in
   the media library later; object-position:top keeps heads in frame when a portrait
   source is cropped.
   WHY greyscale in CSS rather than baked into the upload: the sources arrive with
   wildly different backgrounds (studio grey, cream, a wood wall, an outdoor treeline)
   and greyscale is what pulls them into one row. It stays a one-line change if the
   client wants colour, and the media library keeps the originals. */
.liv-team-photo img,
.liv-team-placeholder {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
	object-position: top center;
	filter: grayscale(100%);
}

/* Figma 33362:1707 — the empty photo slot is a flat fill inside a theme-03 border.
   Used for the three people whose headshots the client has not sent yet. */
.liv-team-placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	border: 2px solid var(--wp--preset--color--theme-03);
	border-radius: 16px 16px 4px 4px;
	background: #6d6d80;
	color: var(--wp--preset--color--theme-01);
	font-family: var(--wp--preset--font-family--cormorant-garamond);
	font-size: 3rem;
	line-height: 1;
	letter-spacing: 0.02em;
	filter: none; /* already neutral; greyscale would only mute the border */
}

.liv-team-meta {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 0 24px;
}

/* Figma 33358:1387 — Cormorant Garamond Bold 24/1.2, -0.48px tracking, capitalised. */
.liv-team-name {
	font-family: var(--wp--preset--font-family--cormorant-garamond);
	font-size: 1.5rem;
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: 1.2;
	text-transform: capitalize;
}

/* Figma 33358:1388 — body font 16/1.5. Inter on the artboard is the placeholder for
   this build's Proxima Nova. */
.liv-team-role {
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 1rem;
	font-weight: 400;
	line-height: 1.5;
}

/* WHY a block span per line instead of letting the title wrap: client pins 197–206
   (2026-09-02) each specify "Line 1: <rank> / Line 2: <department>", i.e. the break is
   fixed at the comma rather than wherever the 256px card happens to run out. PHP splits
   the title (role_lines() in inc/team-member-block.php); this only makes each half its
   own line. Single-line titles (CEO, COO, CFO) render one span and are unaffected. */
.liv-team-role-line {
	display: block;
}

.liv-team-trigger:focus-visible {
	outline: 2px solid var(--wp--preset--color--theme-03);
	outline-offset: 3px;
}

/* ---- bio pop-up (Figma 33362:1626) ----
   WHY a native <dialog>: focus trap, Esc-to-close, background inert and top-layer
   stacking all come for free, and every one of those is easy to get subtly wrong in a
   hand-rolled overlay. liv-ui.js only calls showModal()/close(). Same construction the
   core-values pop-up above already uses. */
.liv-team-dialog {
	width: min(92vw, 968px);
	max-height: 88vh;
	padding: 0;
	border: none;
	border-radius: 16px;
	background: var(--wp--preset--color--theme-08);
	color: var(--wp--preset--color--theme-06);
	filter: drop-shadow(0 4px 4px rgba(16, 24, 40, 0.1)) drop-shadow(0 2px 2px rgba(16, 24, 40, 0.06));
	overflow: visible;
}

.liv-team-dialog::backdrop { background: rgba(0, 0, 0, 0.72); }

.liv-team-dialog-body {
	display: flex;
	flex-direction: column;
	gap: 24px;
	max-height: 88vh;
	padding: 56px 24px 32px;
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* Figma 33362:1570 — the close glyph is theme-03 at 36px, top right. 44px box so the
   tap target clears the minimum even though the glyph itself is smaller. */
.liv-team-close {
	position: absolute;
	top: 4px;
	right: 8px;
	z-index: 1;
	width: 44px;
	height: 44px;
	padding: 0;
	border: none;
	background: none;
	color: var(--wp--preset--color--theme-03);
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 2.25rem;
	font-weight: 400;
	line-height: 1;
	cursor: pointer;
}

.liv-team-close:focus-visible {
	outline: 2px solid var(--wp--preset--color--theme-03);
	outline-offset: 2px;
}

/* Figma 33358:1546 — 298x337 slot, 16px radius, its own shadow. The mobile cap keeps
   the person's NAME on the first screen: at full dialog width a square headshot is
   ~330px tall on a 430px phone and pushes everything below the fold. */
.liv-team-dialog-photo img,
.liv-team-dialog-photo .liv-team-placeholder {
	display: block;
	width: 100%;
	max-width: 240px;
	margin: 0 auto;
	aspect-ratio: 298 / 337;
	border-radius: 16px;
	object-fit: cover;
	object-position: top center;
	box-shadow: 0 4px 8px rgba(16, 24, 40, 0.1), 0 2px 4px rgba(16, 24, 40, 0.06);
	filter: grayscale(100%);
}

.liv-team-dialog-photo .liv-team-placeholder { filter: none; }

.liv-team-dialog-copy {
	display: flex;
	flex-direction: column;
	gap: 16px;
	font-family: var(--wp--preset--font-family--proxima-nova);
}

/* Name + job title on the left, badge + LinkedIn on the right.
   WHY the aside is pushed right rather than sitting at the artboard's fixed x=642:
   "Full Name" is two short words on the artboard and "Denise Gordon-Mohamud" is not.
   A fixed offset collides on the real names; right-aligning to the copy column holds
   the same reading order and the same visual weight at every name length. */
.liv-team-dialog-head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 24px;
}

.liv-team-dialog-titles {
	display: flex;
	flex-direction: column;
	gap: 4px;
	min-width: 0;
}

.liv-team-dialog-aside {
	display: flex;
	align-items: flex-start;
	flex-shrink: 0;
	gap: 20px;
}

/* Figma 33358:1554 — Cormorant Garamond 500 at step-3 (33px), -0.99px tracking. */
.liv-team-dialog-name {
	margin: 0;
	color: var(--wp--preset--color--theme-02);
	font-family: var(--wp--preset--font-family--cormorant-garamond);
	font-size: 1.75rem;
	font-weight: 500;
	letter-spacing: -0.03em;
	line-height: 1.2;
}

/* Figma 33358:1555 — body font Bold 18/1.75, +0.36px tracking, theme-02. */
.liv-team-dialog-role {
	margin: 0;
	color: var(--wp--preset--color--theme-02);
	font-size: 1.125rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	line-height: 1.75;
}

/* Figma 33360:1559 said 16/1.75; client pin 149 (2026-08-31) supersedes — "tighten up line
   spacing and take the font size down a touch on the bio copy, it's running a little long". */
.liv-team-bio p {
	margin: 0 0 0.875em;
	color: var(--wp--preset--color--theme-06);
	font-size: 0.9375rem;
	line-height: 1.55;
	letter-spacing: 0.02em;
}

.liv-team-bio p:last-child { margin-bottom: 0; }

/* ---- years-in-service badge (Figma 33362:1560/1565) ---- */
.liv-team-badge {
	flex-shrink: 0;
	width: 88px; /* was 98 — client pin 147 (2026-08-31): tighten the badge toward the TAC treatment */
}

.liv-team-badge svg {
	display: block;
	width: 100%;
	height: auto;
	overflow: visible;
}

.liv-team-badge-disc { fill: var(--wp--preset--color--theme-02); }

.liv-team-badge-num {
	fill: var(--wp--preset--color--theme-01);
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 22px; /* pin 147: number reads more like TAC's */
	font-weight: 700;
	letter-spacing: 0.4px;
}

.liv-team-badge-arc {
	fill: var(--wp--preset--color--theme-06);
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 13px; /* was 10 — designer re-spec 2026-08-31: arc text reads bigger + more spread, per Figma */
	font-weight: 700;
	letter-spacing: 0.02em; /* Figma tracking is 2% of font size (designer, 2026-08-31) — em keeps that ratio */
	text-anchor: middle;
}

/* ---- LinkedIn tile (Figma 33362:1567) ----
   The exported vector is one even-odd path — the rounded tile with the wordmark
   knocked out of it — so the fill colour IS the tile and the glyph is the hole. */
.liv-team-linkedin {
	display: block;
	flex-shrink: 0;
	width: 42px;
	color: var(--wp--preset--color--theme-03);
	transition: color 200ms ease-in-out;
}

.liv-team-linkedin:hover,
.liv-team-linkedin:focus-visible { color: var(--wp--preset--color--theme-07); }

.liv-team-linkedin svg { display: block; width: 100%; height: auto; fill: currentColor; }

/* WHY defined here: this theme has no .screen-reader-text rule of its own — a classic
   -theme convention block themes drop — and the LinkedIn tile needs an accessible name. */
.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.liv-team-empty {
	padding: 24px;
	color: var(--wp--preset--color--theme-07);
	font-style: italic;
	text-align: center;
}

/* ---- the About Us copy of the band ----
   WHY a flat theme-04 variant instead of reusing the /team/ gradient: on /about-us/ this
   section sits directly under Core Values (.liv-values), which is flat theme-04 carrying
   this same blue texture at this same opacity. Dropping the gradient band there would put
   a blue-to-beige fade against a flat blue band and read as a hard seam.

   Going flat is also what the build already does at that join. Client round-3 pin 9 —
   "Our Purpose quad should be the same background as Core Values with the pattern
   extending up here" — moved About Purpose (wp_block 80) to theme-04 and onto the shared
   texture rule for exactly this reason, so Purpose / Core Values / Team now read as one
   continuous blue run rather than three stacked bands. */
.liv-team-section-flat {
	/* WHY theme-04 with NO texture (was theme-05 + texture, and theme-04 + gradient before
	   that): client pin 196 (2026-09-02) — "Let's make this background the greener color, but
	   no pattern (what you're using above, but remove the pattern)". Pin 136 (2026-08-31) had
	   asked for the opposite direction ("share a different background color... it reads like
	   an extension of culture"); pin 195 answers that instead by moving Core Values to beige,
	   so the two bands still differ and the team band gets the greener base back.

	   The band is still the ONLY untextured one in this run, which is the point — it is what
	   separates it from Core Values now that they no longer differ by base alone. */
	background-color: var(--wp--preset--color--theme-04);
	background-image: none;
}

/* Kill the inherited texture rather than overriding its opacity to 0: the ::before is also the
   stacking context .liv-team-section > * relies on, so it has to stop painting without the
   pseudo-element disappearing from the box model of anything else. `content: none` removes the
   pseudo-element itself, and nothing else in the team section positions against it. */
.liv-team-section-flat::before {
	content: none;
}

@media (min-width: 1024px) {
	/* Figma 33352:1176 — 95px/60px section padding, 54px between heading and grid. */
	.liv-team-section { padding: 95px 60px; }
	.liv-team-section > .liv-sec-head { margin-bottom: 54px; }

	.liv-team-card {
		flex: 0 0 calc(
			(100% - (var(--liv-team-cols) - 1) * var(--liv-team-gap)) / var(--liv-team-cols)
		);
		max-width: 256px; /* the artboard's card width — stops a short row stretching */
	}

	/* WHY cap the GRID, not just the card: the basis above is a share of the row, but
	   `max-width: 256px` then lets more cards than --liv-team-cols fit the 1320px content
	   column, so a 4-column group still laid out 5 + 3. Client pin 194 (2026-09-02) —
	   "Let's make this 4 on top and 4 on the bottom". Bounding the track to exactly
	   cols × 256 + gaps makes the block's `columns` attribute authoritative at every
	   viewport ≥1024; centring keeps the short last row deliberate (see the flex-wrap
	   WHY above). 5 cols resolves to 1312px — the width the 5-up rows already had. */
	.liv-team-grid {
		max-width: calc(
			var(--liv-team-cols) * 256px + (var(--liv-team-cols) - 1) *
				var(--liv-team-gap)
		);
		margin-inline: auto;
	}

	.liv-team-dialog-body {
		display: grid;
		grid-template-columns: 298px minmax(0, 1fr);
		gap: 56px;
		padding: 64px 45px 48px;
	}

	.liv-team-dialog-photo img,
	.liv-team-dialog-photo .liv-team-placeholder { max-width: none; }

	.liv-team-dialog-name { font-size: 2.0625rem; }
}

/* ---- hover: framed photo + a "View Bio" tab that slides out of the left edge ----
   Client request 2026-08-19: "create the hover effect similar to the TAC site with the
   view bio button popping out". Measured on amenitycollective.com/team/ the same day —
   `.overlay-team` is a full-bleed layer over the photo at opacity 0 carrying an 8px
   solid frame in their foreground colour and, absolutely positioned bottom-left, a pill
   whose RIGHT side alone is rounded (`0 70px 70px 0`) so it reads as a tab rather than a
   button. On hover the layer fades to 1.

   Three deliberate departures:

   1. theme-03, not navy. TAC frames in their near-black foreground against a pale blue
      card. This card is already theme-02 navy, so a navy frame would disappear into it.
      theme-03 is this build's established accent for card chips (`figure.liv-chip` rests
      at theme-03) and is the colour that actually pops here.
   2. 5px frame, not 8px. TAC's card is 466px wide, so 8px is 1.7% of it; this card is the
      artboard's 256px, where 8px reads as a heavy blocky border. 5px matches the ratio.
   3. The tab SLIDES rather than only fading. The client described it as "popping out",
      which is what the shape implies but not what TAC actually animates. `.liv-team-photo`
      already clips (`overflow: hidden`), so parking the tab at translateX(-100%) hides it
      completely off the left edge and it genuinely emerges from there.

   This replaces the photo zoom the first cut borrowed from `.liv-card-img`. Two hover
   treatments on one card fight each other, and this is the one that was asked for. */
.liv-team-hover {
	position: absolute;
	inset: 0;
	border: 5px solid var(--wp--preset--color--theme-03);
	border-radius: inherit;
	opacity: 0;
	pointer-events: none;
	transition: opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

.liv-team-viewbio {
	position: absolute;
	left: 0;
	bottom: 20px;
	display: inline-block;
	padding: 10px 18px;
	border-radius: 0 999px 999px 0; /* right side only — the tab shape */
	background: var(--wp--preset--color--theme-03);
	color: var(--wp--preset--color--theme-01);
	font-family: var(--wp--preset--font-family--proxima-nova);
	font-size: 0.8125rem;
	font-weight: 700;
	letter-spacing: 0.09em;
	line-height: 1;
	text-transform: uppercase;
	white-space: nowrap;
	transform: translateX(-100%);
	transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* WHY gated behind (hover: hover): on a touch device there is no hover, so the tab
   would either sit permanently over every photo or eat the first tap on a state the
   user never sees. Touch users get the whole card as the tap target, which is what the
   artboard assumes. :focus-visible is included so a keyboard user gets the same
   affordance a mouse user does. */
@media (hover: hover) {
	.liv-team-trigger:hover .liv-team-hover,
	.liv-team-trigger:focus-visible .liv-team-hover { opacity: 1; }

	.liv-team-trigger:hover .liv-team-viewbio,
	.liv-team-trigger:focus-visible .liv-team-viewbio { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
	.liv-team-hover,
	.liv-team-viewbio { transition: none; }
}
/* @kindling:keep:end */

/* @kindling:keep:start */
/* ---- Cormorant Garamond: one tracking value site-wide ---- */
/* WHY: client 2026-09-02, restated — "he wants the kerning applied to any text using
   Cormorant Garamond." The 9/02 intro-quad round opened body copy to 0.01em; this extends the
   SAME value to every Cormorant element on the site. It was carrying six different values —
   -0.06em (79px section/hero titles, 66 instances), -0.05em (64px split titles, 56px value
   names), -0.03em (33/28px quotes + dialog names, 25px card titles, 140 instances), -0.02em
   (24px team names), 0 and +0.01em — which is exactly the inconsistency being called out.

   READ THIS BEFORE "FIXING" A HEADING THAT LOOKS LOOSE: the negative tracking removed here was
   the Figma display spec (33186:*, display preset -0.06em at 79px). Opening it to +0.01em is a
   0.07em swing on the largest type — deliberate, client-directed, and a known departure from
   the artboards. Do not read a gate diff on heading tracking as a regression. Revert = delete
   this block; every original per-element value is still declared above, untouched.

   WHY the selector list rather than a font-family match: CSS cannot select on computed family.
   Cormorant reaches text exactly two ways on this build — the theme.json heading element style
   (h1-h6) and the `has-cormorant-garamond-font-family` preset class — plus five elements that
   name the family directly in this file. That list was derived by walking every element on all
   22 EN pages and diffing computed font-family against this selector: 0 non-Cormorant elements
   caught; ONE Cormorant element missed (.liv-faq-item > summary, found 2026-09-14, appended below). Anchors inside headings inherit and need no entry.

   WHY !important: the values being overridden live on more specific selectors (.liv-home-hero
   h1, .liv-split .liv-sec-title, .liv-sec-title.liv-split-title-md). A single flat selector
   list cannot out-specify all of them, and inflating each one would scatter this decision back
   across the file — which is the thing that produced six values in the first place. */
h1, h2, h3, h4, h5, h6,
.has-cormorant-garamond-font-family,
.liv-nav .is-menu-open .wp-block-navigation-item__content,
.liv-value-modal__body p,
.liv-team-name,
.liv-team-placeholder,
.liv-faq-item > summary {
	letter-spacing: 0.01em !important;
}
/* WHY .liv-faq-item > summary joined the list (client 2026-09-14 — "adjust the FAQ question line letter spacing so it's
   the same as the other areas with that Cormorant font"): the FAQ question is a <summary>, not a heading, and names
   Cormorant directly in its own rule (font-size large / 700 / -0.03em, above). The 22-page walk that built this list
   missed it, so the FAQ question was the ONE Cormorant element on the site still tracked -0.03em (-0.75px at 25px)
   while every other Cormorant run rendered +0.01em (measured on BLD /services/consulting-development/ at 1440 and
   390: sec-title, intro-text, card-title, wide-quote, engage-sub all 0.01em; summary -0.03em). Its per-element value
   stays declared in the FAQ block for the same revert reason as the rest. */

/* WHY the home hero H1 is exempt from the Cormorant tracking above: client 2026-09-02 —
   "undo the h1-break, that didn't need to change." Opening this heading to 0.01em re-broke it
   from "Performance-Driven / Solutions" to "Performance- / Driven Solutions", splitting the
   hyphenated compound. That break is NOT independently fixable: measured at 79px, the string
   "Performance-Driven" needs 643px at 0.01em, 586px at -0.03em and 558px at -0.05em, against a
   hero copy measure of 560px inside a 653px track at 1440. Nothing but tighter tracking puts it
   back on one line — widening the column past ~645px does not fit at 1440 either, and would
   move the centred-column geometry the client signed off in pin 3 (2026-08-05).
   So this one heading keeps its Figma display values (-0.05em mobile / -0.06em desktop) and is
   the single documented exception to "kerning on any text using Cormorant Garamond". It is the
   most prominent heading on the site, so if the client ever notices it tracking tighter than the
   rest, that is this trade — the alternative is the hyphen break, not a third option.
   Scoped to .liv-home-hero h1 alone: every other h1/h2/h3 keeps 0.01em. */
.liv-home-hero h1 { letter-spacing: -0.05em !important; }
@media (min-width: 1024px) {
	.liv-home-hero h1 { letter-spacing: -0.06em !important; }
}
/* ---- FES Advantage bar (US Equipment Sales only, post 24) ---- */
/* WHY (markup.io pin 328, 2026-09-23): "create a new quad between intro and what we deliver for
   this page only ... a narrow, horizontal bar that includes the white Advantage logo aligned to
   the left, and copy on the right side of it. The background of this quad will be brown." No
   Figma frame exists, so the geometry comes from the neighbours (see the left-edge WHY below) and vertical padding
   well under the 80px sections either side so it reads as a band, not a section. The logo moved
   here OUT of the hero (.liv-svc-hero-marks) so it does not show twice within 100px. Brown is
   theme-07 (#7A6049), not theme-03: white copy on theme-03 is 3.9:1 and fails WCAG AA at the
   19px phone end of the large preset; theme-07 is 6.2:1. Phone stacks logo over copy (a 200px
   logo beside copy would leave a ~100px text column at 390). */
.liv-adv-bar { padding-block: var(--wp--preset--spacing--50); padding-inline: 20px; }
/* WHY (Conor, 2026-09-23): "bump it a bit more to the left to line up with that intro text".
   The logo's left edge tracks the hero intro copy directly above, not the 1320px contentSize
   measure. Phone/tablet: the hero copy sits on a 20px gutter. Desktop: the hero is a 653fr/712fr
   grid with 75px left padding and its copy centred in the first track at a 653px measure with a
   32px floor (.liv-svc-hero-content, pin 289), so the same formula is repeated here. Padding goes
   on the INNER group because % padding on the bar itself resolves against post-content's
   padded box (global padding) and drifts 15px at 1920. */
.liv-adv-bar > .liv-adv-bar-inner { max-width: none; margin-left: 0 !important; margin-right: 0 !important; }
.liv-adv-bar-inner { flex-direction: column; align-items: flex-start !important; gap: var(--wp--preset--spacing--30); }
.liv-adv-bar-logo { margin: 0; flex: 0 0 auto; }
.liv-adv-bar-logo img { width: 225px; height: auto; display: block; } /* WHY 225 (was 200): pin 332, +12.5% */
/* WHY (Conor, 2026-09-23): "get the text on two lines ... decrease the text size slightly too. It's
   kind of overpowering the intro text since that's a lighter weighted font." The block carries the
   `large` preset (25px desktop), the same px as the Cormorant intro above, but Proxima's x-height
   and stroke read far heavier at equal size. No preset sits between medium (16) and large (25), so
   a custom fluid 17px phone -> 20px desktop. !important because core's .has-large-font-size is
   !important. Two lines at >=1280 comes from the 720px cap below + text-wrap: balance (even
   halves, no orphan); 1024-1279 runs three lines because the logo column leaves ~510px. */
.liv-adv-bar .liv-adv-bar-copy { margin: 0; font-size: clamp(1.0625rem, 0.95rem + 0.4vw, 1.25rem) !important; line-height: 1.45; text-wrap: balance; }
@media (min-width: 768px) {
	/* WHY the divider (Conor, pin 331, 2026-09-24): "This should be our regularly used brand divider,
	   just vertical" — replaces the 1px white-40% hairline. Same dot-line-dot mask as .liv-rule
	   (7px dots, 1.5px line) rotated to run top-to-bottom beside the logo. White (theme-01), not the
	   usual theme-03: tan #9B7B5E on the theme-07 #7A6049 bar is ~1.3:1 and the dots disappear; white
	   matches the bar's copy. */
	.liv-adv-bar-inner { flex-direction: row; align-items: center !important; gap: var(--wp--preset--spacing--60); }
	.liv-adv-bar-logo { position: relative; padding-right: var(--wp--preset--spacing--60); }
	.liv-adv-bar-logo::after {
		content: "";
		position: absolute;
		top: 0;
		right: 0;
		bottom: 0;
		width: 7px;
		background-color: var(--wp--preset--color--theme-01);
		-webkit-mask:
			radial-gradient(circle closest-side, #000 98%, #0000) center top / 7px 7px no-repeat,
			radial-gradient(circle closest-side, #000 98%, #0000) center bottom / 7px 7px no-repeat,
			linear-gradient(#000 0 0) center center / 1.5px 100% no-repeat;
		mask:
			radial-gradient(circle closest-side, #000 98%, #0000) center top / 7px 7px no-repeat,
			radial-gradient(circle closest-side, #000 98%, #0000) center bottom / 7px 7px no-repeat,
			linear-gradient(#000 0 0) center center / 1.5px 100% no-repeat;
	}
	/* WHY 250 (was 220): pin 332 "Logo should be 10-15% larger" — +13.6%, inside the asked range. */
	.liv-adv-bar-logo img { width: 250px; }
	.liv-adv-bar-copy { flex: 1 1 0; max-width: 720px; }
}
@media (min-width: 1024px) {
	.liv-adv-bar { padding-inline: 0; }
	.liv-adv-bar > .liv-adv-bar-inner { padding-inline: calc(75px + max(32px, ((100% - 75px) * 653 / 1365 - 653px) / 2)); }
}

/* @kindling:keep:end */
