/**
 * CHS Video Hero — layout & layers.
 * Loads on both the front end and inside the editor canvas.
 *
 * Stacking order (low -> high):
 *   poster  (0)  static fallback image / first paint
 *   video   (1)  crossfading background clips
 *   tint    (2)  editor-controlled brand color overlay
 *   scrim   (3)  fixed gradient for text contrast (not editor-controlled)
 *   content (4)  the editable foreground (heading, buttons, image)
 *
 * Sequence mode (see "Sequence homepage mode" below) inserts the swapping
 * photos between the video and the tint, so a photo gets exactly the same
 * treatment the footage does and white text keeps its contrast either way:
 *   poster (0) / video (1) / seq-photo (2) / tint (3) / scrim (4) / seq (6)
 *
 * Cinematic mode (PARKED — see render.php) adds:
 *   wipe    (5)  full-bleed still, revealed bottom-to-top by scroll
 *   scene1  (6)  letter-by-letter headline + scroll cue
 *   panel   (7)  slide-up card carrying the InnerBlocks content
 */

.chs-video-hero {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	display: flex;
	align-items: center;
	min-height: clamp(480px, 70vh, 720px);
}

/* Sit flush against the header above and the next section below — neutralizes
   WordPress's root flow-layout block-gap (the faint band around the hero). */
.chs-video-hero {
	margin-block-start: 0;
	margin-block-end: 0;
}

.chs-video-hero + * {
	margin-block-start: 0;
}

/* Screen-reader-only: keeps a real H1 for SEO / assistive tech without
   showing it. Used by the hero headline. */
.chs-sr-only {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.chs-video-hero__media {
	position: absolute;
	inset: 0;
	z-index: 0;
}

.chs-video-hero__poster,
.chs-video-hero__video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
}

.chs-video-hero__poster {
	z-index: 0;
}

.chs-video-hero__video {
	z-index: 1;
	opacity: 0;
	will-change: opacity;
}

.chs-video-hero__video.is-active {
	opacity: 1;
}

.chs-video-hero__tint {
	position: absolute;
	inset: 0;
	z-index: 2;
	pointer-events: none;
}

/* Content-side scrim — guarantees white-text contrast regardless of the
   frame on screen, while the brand tint above can stay light/"mild". */
.chs-video-hero__scrim {
	position: absolute;
	inset: 0;
	z-index: 3;
	pointer-events: none;
	background: linear-gradient(
		90deg,
		rgba(1, 30, 48, 0.6) 0%,
		rgba(1, 30, 48, 0.3) 40%,
		rgba(1, 30, 48, 0) 72%
	);
}

.chs-video-hero__content {
	position: relative;
	z-index: 4;
	width: 100%;
}

/* Framed featured image floating over the video. */
.chs-video-hero .chs-hero-photo img {
	box-shadow: 0 22px 48px rgba(1, 30, 48, 0.45);
}

/* On narrow screens the columns stack, so shift the scrim to a vertical
   gradient (darker toward the bottom where text/buttons land). */
@media (max-width: 781px) {
	.chs-video-hero__scrim {
		background: linear-gradient(
			180deg,
			rgba(1, 30, 48, 0.25) 0%,
			rgba(1, 30, 48, 0.35) 40%,
			rgba(1, 30, 48, 0.65) 100%
		);
	}
}

/* Defense in depth: never animate background video for reduced-motion users
   even if the script path is bypassed. */
@media (prefers-reduced-motion: reduce) {
	.chs-video-hero__video {
		display: none !important;
	}
}

/* Editor canvas: the foreground content shouldn't be vertically centered
   while editing (it makes block insertion awkward), and we give a little
   breathing room so the toolbar isn't clipped. */
.editor-styles-wrapper .chs-video-hero--editor {
	align-items: stretch;
}

.editor-styles-wrapper .chs-video-hero--editor .chs-video-hero__content {
	padding-block: var(--wp--preset--spacing--70, 4rem);
}

/* ============================================================================
   Sequence homepage mode (.chs-video-hero--sequence)

   An auto-playing, one-pass word swap. NOTHING intercepts scrolling — the
   page scrolls normally from first paint onward.

   The STATIC layout is the default: the finished sentence over the tinted
   poster/video. That's what phones, 782–1279 screens, reduced-motion visitors
   and no-JS visitors get, so the sentence is always readable.

   view.js adds `.is-sequence` (>=1280px + motion OK only), which switches on:
   - the lead line + the swapping phrase slot (`.is-intro` starts the letters)
   - the crossfading full-bleed photos (`.is-active` per photo)
   - the finale: `.is-lead-out` retires the lead line, `.is-final` lands the
     complete sentence over the resumed footage
   - `.is-instant` skips every transition (mid-page arrival)
   ========================================================================== */

.chs-video-hero--sequence {
	display: block;
	align-items: initial;
	min-height: 0;
	overflow: hidden;
}

.chs-video-hero--sequence .chs-video-hero__stage {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	min-height: clamp(480px, 70vh, 720px);
	padding: var(--wp--preset--spacing--60, 4rem) var(--wp--preset--spacing--30, 1.5rem);
}

/* Desktop height is the SAME whether or not JS has switched the sequence on,
   so the handoff never resizes the hero (view.js loads in the footer). It is
   deliberately short of a full viewport: the copy strip and its CTAs sit
   directly below the hero and have to stay above the fold. */
@media (min-width: 1280px) {
	.chs-video-hero--sequence .chs-video-hero__stage {
		min-height: clamp(440px, 60svh, 680px);
	}
}

/* --------------------------- swapping photos --------------------------- */

.chs-video-hero--sequence .chs-video-hero__seq-photos {
	position: absolute;
	inset: 0;
	z-index: 2;
}

.chs-video-hero--sequence .chs-video-hero__seq-photo {
	position: absolute;
	inset: 0;
	/* --seq-img / --seq-img-m are set inline by render.php. Only the
	   property the cascade resolves to is fetched, so phones never pull the
	   1920x800 file and desktops never pull the portrait one. */
	background-image: var(--seq-img);
	background-size: cover;
	background-repeat: no-repeat;
	opacity: 0;
	transition: opacity 900ms ease-in-out;
	will-change: opacity;
}

.chs-video-hero--sequence .chs-video-hero__seq-photo.is-active {
	opacity: 1;
}

/* Lift the tint and scrim above the photos (see the stacking note up top). */
.chs-video-hero--sequence .chs-video-hero__tint {
	z-index: 3;
}

.chs-video-hero--sequence .chs-video-hero__scrim {
	z-index: 4;
	/* Centered text: the classic left-biased gradient reads wrong here. */
	background: linear-gradient(
		180deg,
		rgba(1, 30, 48, 0.34) 0%,
		rgba(1, 30, 48, 0.2) 45%,
		rgba(1, 30, 48, 0.5) 100%
	);
}

/* Client feedback (Aug 21 2026): copy must never sit over a face. While the
   sequence is running, the words are anchored to the BOTTOM of the stage and
   the four sequence photos are cropped with faces in their upper half (the
   photos use `focus: center top` so wide screens crop the bottom, never the
   heads). The scrim gets a heavier foot so the lowered copy keeps contrast. */
.chs-video-hero--sequence.is-sequence .chs-video-hero__stage {
	justify-content: flex-end;
	padding-bottom: clamp(2rem, 4.5vh, 3rem);
}

.chs-video-hero--sequence.is-sequence .chs-video-hero__scrim {
	background: linear-gradient(
		180deg,
		rgba(1, 30, 48, 0.22) 0%,
		rgba(1, 30, 48, 0.08) 40%,
		rgba(1, 30, 48, 0.45) 72%,
		rgba(1, 30, 48, 0.72) 100%
	);
}

/* ------------------------------ the words ------------------------------ */

.chs-video-hero--sequence .chs-video-hero__seq {
	position: relative;
	z-index: 6;
	width: 100%;
	max-width: min(1100px, 86vw);
	margin-inline: auto;
	text-align: center;
	color: #fff;
}

.chs-video-hero--sequence .chs-video-hero__seq-line,
.chs-video-hero--sequence .chs-video-hero__seq-final {
	margin: 0;
	font-family: var(--wp--preset--font-family--heading, Georgia, serif);
	font-weight: 700;
	line-height: 1.2;
	color: #fff;
	/* Tight drop shadow for edge contrast + a wide soft glow for separation. */
	text-shadow:
		0 2px 6px rgba(1, 30, 48, 0.55),
		0 2px 28px rgba(1, 30, 48, 0.45);
	text-wrap: balance;
}

.chs-video-hero--sequence .chs-video-hero__seq-lead {
	display: block;
}

/* Split units (created by view.js). Words stay whole so lines never break
   mid-word; the intact sentence is available to assistive tech via the
   sr-only copy that render.php ships alongside. */
.chs-video-hero--sequence .chs-vh-word {
	display: inline-block;
	white-space: nowrap;
}

.chs-video-hero--sequence .chs-vh-ch {
	display: inline-block;
}

.chs-video-hero--sequence .chs-video-hero__seq-slot {
	position: relative;
	display: block;
	height: 1.2em;
}

.chs-video-hero--sequence .chs-video-hero__seq-phrase {
	position: absolute;
	left: 50%;
	top: 0;
	white-space: nowrap;
	opacity: 0;
	transform: translate(-50%, 0.35em);
	filter: blur(8px);
	transition:
		opacity 0.7s ease,
		transform 0.7s cubic-bezier(0.22, 1, 0.36, 1),
		filter 0.7s ease;
}

.chs-video-hero--sequence .chs-video-hero__seq-phrase.is-in {
	opacity: 1;
	transform: translate(-50%, 0);
	filter: none;
}

.chs-video-hero--sequence .chs-video-hero__seq-phrase.is-out {
	opacity: 0;
	transform: translate(-50%, -0.4em);
	filter: blur(6px);
	transition-duration: 0.5s;
}

/* The lead line retires as one piece just before the finale lands. */
.chs-video-hero--sequence .chs-video-hero__seq-line {
	transition:
		opacity 0.6s ease,
		transform 0.6s ease,
		filter 0.6s ease;
}

.chs-video-hero--sequence.is-lead-out .chs-video-hero__seq-line {
	opacity: 0;
	transform: translateY(-0.35em);
	filter: blur(6px);
	pointer-events: none;
}

.chs-video-hero--sequence .chs-video-hero__content--seq {
	position: relative;
	z-index: 6;
	width: 100%;
}

/* ------------------------- Static fallback layout ------------------------ */
/* Applies until/unless JS switches the sequence on. */

.chs-video-hero--sequence:not(.is-sequence) .chs-video-hero__seq-line {
	display: none;
}

.chs-video-hero--sequence:not(.is-sequence) .chs-video-hero__seq-final {
	font-size: clamp(1.6rem, 5vw, 2.6rem);
}

/* ----------------------- TranslatePress editor mode ---------------------- */
/* view.js adds .is-trp-editor inside the TP visual editor's preview iframe
   (?trp-edit-translation=preview) and never starts the sequence there. Every
   string — the lead, each phrase, the finished sentence — is laid out static,
   visible, and unsplit so translators can click each one. The !importants
   override the ">=1280px + motion OK" pre-intro hidden states, which apply
   from first paint regardless of JS. */

.chs-video-hero--sequence.is-trp-editor .chs-video-hero__seq-line {
	display: block !important;
	opacity: 1 !important;
	transform: none !important;
	filter: none !important;
	pointer-events: auto !important;
}

.chs-video-hero--sequence.is-trp-editor .chs-video-hero__seq-lead {
	opacity: 1 !important;
}

.chs-video-hero--sequence.is-trp-editor .chs-video-hero__seq-slot {
	height: auto;
}

.chs-video-hero--sequence.is-trp-editor .chs-video-hero__seq-phrase {
	position: static;
	display: block;
	opacity: 1 !important;
	transform: none !important;
	filter: none !important;
	white-space: normal;
	font-size: 0.72em;
	line-height: 1.35;
}

.chs-video-hero--sequence.is-trp-editor .chs-video-hero__seq-final {
	opacity: 1 !important;
	transform: none !important;
	filter: none !important;
	margin-top: 0.6em;
	font-size: clamp(1.6rem, 5vw, 2.6rem);
}

/* --------------------- Active sequence (desktop + JS) -------------------- */

.chs-video-hero--sequence.is-sequence .chs-video-hero__seq {
	display: grid;
}

/* The lead line and the finished sentence occupy the SAME grid cell, so the
   crossfade between them never shifts anything and the block's height is set
   once by the taller of the two. */
.chs-video-hero--sequence.is-sequence .chs-video-hero__seq-line,
.chs-video-hero--sequence.is-sequence .chs-video-hero__seq-final {
	grid-area: 1 / 1;
	align-self: center;
	/* 2.8vw (was 3.6vw): on 1280–1440 laptops the copy was two 50px lines
	   climbing into the faces (Joe, Aug 26 2026). */
	font-size: clamp(2rem, 2.8vw, 3.4rem);
}

.chs-video-hero--sequence.is-sequence .chs-video-hero__seq-line {
	display: block;
}

/* Mid-page arrival: land on the finale with no animation at all. */
.chs-video-hero--sequence.is-instant .chs-video-hero__seq-line,
.chs-video-hero--sequence.is-instant .chs-video-hero__seq-final,
.chs-video-hero--sequence.is-instant .chs-video-hero__seq-phrase,
.chs-video-hero--sequence.is-instant .chs-video-hero__seq-photo,
.chs-video-hero--sequence.is-instant .chs-vh-ch {
	transition: none !important;
}

/* ------------------------- Phone mode (<= 781px) ------------------------- */
/* Aug 27 2026 (Joe): phones run the SAME word/photo sequence, but with the
   video off (poster only) and ~70 KB portrait photos. The stage is taller
   than wide, the photos keep faces in their top 40%, and the copy is pinned
   to the bottom third. Tablets (782-1279px) still get video + static copy. */
@media (max-width: 781px) {
	.chs-video-hero--sequence .chs-video-hero__seq-photo {
		background-image: var(--seq-img-m, var(--seq-img));
		background-position: center top !important;
	}

	.chs-video-hero--sequence.is-sequence .chs-video-hero__stage {
		min-height: clamp(440px, 78svh, 620px);
		padding-bottom: 1.5rem;
	}

	.chs-video-hero--sequence.is-sequence .chs-video-hero__seq {
		max-width: 92vw;
	}

	.chs-video-hero--sequence.is-sequence .chs-video-hero__seq-line,
	.chs-video-hero--sequence.is-sequence .chs-video-hero__seq-final {
		font-size: clamp(1.5rem, 6.4vw, 2rem);
		line-height: 1.15;
	}

	/* Phrases can be two lines on a 360px phone ("dads and partners"). */
	.chs-video-hero--sequence.is-sequence .chs-video-hero__seq-slot {
		height: 2.3em;
	}

	.chs-video-hero--sequence.is-sequence .chs-video-hero__seq-phrase {
		white-space: normal;
		width: 100%;
	}

	.chs-video-hero--sequence.is-sequence .chs-video-hero__scrim {
		background: linear-gradient(
			180deg,
			rgba(1, 30, 48, 0.18) 0%,
			rgba(1, 30, 48, 0.06) 35%,
			rgba(1, 30, 48, 0.5) 65%,
			rgba(1, 30, 48, 0.8) 100%
		);
	}
}

/* --------------------------- Letter/word intro --------------------------- */
/* Per the hero FOUC rule: every pre-intro hidden state lives in the media
   query, NOT behind the JS-added class, because view.js loads in the footer
   and the static fallback paints first. render.php carries a <noscript>
   override so no-JS desktop visitors still get the finished sentence. */

/* Phones (<=781px) and desktops (>=1280px) run the sequence; tablets in
   between do not, so their copy must never start hidden. */
@media (min-width: 1280px) and (prefers-reduced-motion: no-preference), (max-width: 781px) and (prefers-reduced-motion: no-preference) {
	/* Unsplit lead: hidden from first paint on exactly the screens that will
	   run the intro. splitText() sets data-vh-split, which hands control over
	   to the per-letter rules below. */
	.chs-video-hero--sequence .chs-video-hero__seq-lead:not([data-vh-split]) {
		opacity: 0;
	}

	/* The finished sentence stays out of sight until the finale — including
	   during the pre-JS beat, so it never flashes over the opening frame. */
	.chs-video-hero--sequence:not(.is-final) .chs-video-hero__seq-final {
		opacity: 0;
	}

	.chs-video-hero--sequence .chs-video-hero__seq-lead .chs-vh-ch {
		opacity: 0;
		transform: translateY(0.35em);
		filter: blur(8px);
		transition:
			opacity 1.05s ease,
			transform 1.05s cubic-bezier(0.22, 1, 0.36, 1),
			filter 1.05s ease;
		transition-delay: calc(var(--i, 0) * 26ms);
	}

	.chs-video-hero--sequence.is-intro .chs-video-hero__seq-lead .chs-vh-ch {
		opacity: 1;
		transform: none;
		filter: none;
	}

	.chs-video-hero--sequence .chs-video-hero__seq-final .chs-vh-ch {
		opacity: 0;
		transform: translateY(0.3em);
		filter: blur(8px);
		transition:
			opacity 0.9s ease,
			transform 0.9s cubic-bezier(0.22, 1, 0.36, 1),
			filter 0.9s ease;
		transition-delay: calc(var(--i, 0) * 45ms);
	}

	.chs-video-hero--sequence.is-final .chs-video-hero__seq-final .chs-vh-ch {
		opacity: 1;
		transform: none;
		filter: none;
	}
}

/* Belt and braces: if reduced-motion flips on mid-session, freeze everything
   and fall back to the finished sentence before JS has a chance to react. */
@media (prefers-reduced-motion: reduce) {
	.chs-video-hero--sequence .chs-vh-ch,
	.chs-video-hero--sequence .chs-video-hero__seq-phrase,
	.chs-video-hero--sequence .chs-video-hero__seq-photo,
	.chs-video-hero--sequence .chs-video-hero__seq-line {
		transition: none !important;
	}

	.chs-video-hero--sequence .chs-video-hero__seq-line {
		display: none !important;
	}

	.chs-video-hero--sequence .chs-video-hero__seq-final,
	.chs-video-hero--sequence .chs-video-hero__seq-final .chs-vh-ch {
		opacity: 1 !important;
		transform: none !important;
		filter: none !important;
	}

	.chs-video-hero--sequence .chs-video-hero__seq-photo {
		opacity: 0 !important;
	}
}

/* ============================================================================
   Cinematic homepage mode (.chs-video-hero--cinematic) — PARKED

   Rejected by the client on Aug 14 2026 in favor of the sequence mode above
   (the scroll gate hid the content below the hero). Kept intact until Karl
   signs off, then delete this whole block along with the cinematic branch in
   render.php and initCinematic() in view.js.

   The STATIC layout is the default: headline, then the content panel, stacked
   over the tinted poster/video. That's what phones, reduced-motion visitors,
   and no-JS visitors get, and it keeps the CTAs reachable no matter what.

   view.js adds `.is-cinematic` (desktop + motion OK only), which switches on:
   - a full-viewport stage; the first downward gesture plays a one-shot timed
     transition (view.js holds the page still while it runs), then the page
     scrolls normally and the hero rests in its finished state (`.is-done`)
   - letter-by-letter headline intro (`.is-intro`) and scroll cue (`.is-cue`)
   - animation-driven custom properties set by JS:
       --p     virtual progress 0..1 (timed, not scroll-scrubbed)
       --wipe  soft bottom-to-top wipe reveal of the still image
       --exit  headline/cue fade-out
       --panel slide-up of the content card
   ========================================================================== */

.chs-video-hero--cinematic {
	display: block;
	align-items: initial;
	min-height: 0;
	/* The sticky stage must track window scroll — an overflow-hidden wrapper
	   would become its (non-scrolling) scrollport and kill the pin. */
	overflow: visible;
}

.chs-video-hero--cinematic .chs-video-hero__stage {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}

/* Centered-text scrim (the classic left-biased gradient reads wrong here). */
.chs-video-hero--cinematic .chs-video-hero__scrim {
	background: linear-gradient(
		180deg,
		rgba(1, 30, 48, 0.32) 0%,
		rgba(1, 30, 48, 0.18) 45%,
		rgba(1, 30, 48, 0.45) 100%
	);
}

.chs-video-hero--cinematic .chs-video-hero__wipe {
	position: absolute;
	inset: 0;
	z-index: 5;
	background-size: cover;
	background-position: center;
}

.chs-video-hero--cinematic .chs-video-hero__scene1 {
	position: relative;
	z-index: 6;
}

.chs-video-hero--cinematic .chs-video-hero__headline {
	margin: 0;
	font-family: var(--wp--preset--font-family--heading, Georgia, serif);
	font-size: clamp(2.66rem, 4.8vw, 4.5rem);
	font-weight: 700;
	line-height: 1.18;
	color: #fff;
	text-align: center;
	/* Tight drop shadow for edge contrast + a wide soft glow for separation. */
	text-shadow:
		0 2px 6px rgba(1, 30, 48, 0.55),
		0 2px 28px rgba(1, 30, 48, 0.45);
	text-wrap: balance;
}

.chs-video-hero--cinematic .chs-video-hero__cue {
	color: #fff;
}

.chs-video-hero--cinematic .chs-video-hero__cue-text {
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.chs-video-hero--cinematic .chs-video-hero__panel {
	position: relative;
	z-index: 7;
}

/* The white card itself is authored in the pattern (group block); the shadow
   lives here so the editor canvas stays flat and calm. A tight drop shadow
   grounds the card's edge; the wide one lifts it off the photo. */
.chs-video-hero--cinematic .chs-hero-panel-card {
	box-shadow:
		0 10px 28px rgba(1, 30, 48, 0.3),
		0 34px 90px rgba(1, 30, 48, 0.42);
}

/* Mobile-only: the family photo returns as a rounded card between the intro
   copy and the body-text card (hidden everywhere else — on desktop that image
   is the scene-2 full-bleed background). */
.chs-video-hero--cinematic .chs-video-hero__mobile-photo {
	display: none;
}

@media (max-width: 1279.98px) {
	.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__mobile-photo {
		display: block;
		/* Positioned so it paints above the absolutely-positioned media stack —
		   a static figure would render underneath the poster/tint layers. */
		position: relative;
		z-index: 6;
		width: min(640px, 100%);
		margin-inline: auto;
		margin-block: 0;
		border-radius: 14px;
		overflow: hidden;
		box-shadow: 0 18px 44px rgba(1, 30, 48, 0.35);
	}

	.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__mobile-photo img {
		display: block;
		width: 100%;
		height: auto;
	}
}

/* ------------------------- Static fallback layout ------------------------- */
/* Applies until/unless JS enables cinematic mode. */

.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__stage {
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: var(--wp--preset--spacing--40, 2rem);
	min-height: clamp(480px, 70vh, 720px);
	padding: var(--wp--preset--spacing--60, 4rem) var(--wp--preset--spacing--30, 1.5rem);
}

.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__wipe,
.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__cue {
	display: none;
}

.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__headline {
	font-size: clamp(1.6rem, 5vw, 2.6rem);
}

.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__panel {
	width: min(640px, 100%);
	margin-inline: auto;
}

/* --------------------- Active cinematic (desktop + JS) -------------------- */

.chs-video-hero--cinematic.is-cinematic {
	/* One viewport, no scrub distance: the second-scene transition is a
	   one-shot timed animation triggered by the first downward gesture
	   (view.js holds the page still while it plays), after which the page
	   scrolls normally and the hero stays in its finished state. */
	height: 100vh;
	height: 100svh;
}

.chs-video-hero--cinematic.is-cinematic .chs-video-hero__stage {
	position: relative;
	height: 100vh;
	height: 100svh;
}

/* Scene 1 headline: occupies the middle third of the space between the bottom
   of the site header and the bottom of the viewport (--chs-header-h is
   measured by view.js). Fades/blurs upward as the wipe takes over. */
.chs-video-hero--cinematic.is-cinematic .chs-video-hero__scene1 {
	position: absolute;
	left: 0;
	right: 0;
	top: calc((100vh - var(--chs-header-h, 72px)) / 3);
	top: calc((100svh - var(--chs-header-h, 72px)) / 3);
	height: calc((100vh - var(--chs-header-h, 72px)) / 3);
	height: calc((100svh - var(--chs-header-h, 72px)) / 3);
	display: flex;
	align-items: center;
	justify-content: center;
	padding-inline: 8vw;
	opacity: calc(1 - var(--exit, 0));
	filter: blur(calc(var(--exit, 0) * 10px));
	transform: translateY(calc(var(--exit, 0) * -4vh));
	pointer-events: none;
}

/* Letter-by-letter intro. The hidden state is applied by the MEDIA QUERY
   (desktop + motion OK), not by .is-cinematic — the view script loads in the
   footer, and gating on the JS-added class caused a flash of fully-visible
   text before the fade began (read as a jitter). With the media query the
   letters are hidden from first paint on exactly the screens that will run
   the intro; render.php carries a <noscript> override so no-JS desktop
   visitors still see the headline. */
.chs-video-hero--cinematic .chs-vh-word {
	display: inline-block;
	white-space: nowrap;
}

.chs-video-hero--cinematic .chs-vh-ch {
	display: inline-block;
}

@media (min-width: 1280px) and (prefers-reduced-motion: no-preference) {
	/* The headline ships as PLAIN TEXT (so TranslatePress can translate it)
	   and view.js splits it into letter spans at init. Hide the raw text on
	   exactly the screens that will run the intro, so neither the unsplit
	   sentence nor a mid-split state ever flashes; render.php carries a
	   <noscript> override for no-JS desktop. */
	.chs-video-hero--cinematic .chs-video-hero__headline-raw {
		opacity: 0;
	}

	/* Pre-JS handoff: view.js loads in the footer, so for a beat the page
	   renders the static fallback. On screens that will run the cinematic
	   intro, make that beat LOOK like scene 1's opening frame — stage at
	   full viewport, scene-2 copy card hidden — so navigating to the
	   homepage never flashes the supplemental copy or a collapsed hero.
	   (<noscript> in render.php restores the card for no-JS visitors.) */
	.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__stage {
		min-height: 100vh;
		min-height: 100svh;
	}

	.chs-video-hero--cinematic:not(.is-cinematic) .chs-video-hero__panel {
		opacity: 0;
	}

	.chs-video-hero--cinematic .chs-vh-ch {
		opacity: 0;
		transform: translateY(0.35em);
		filter: blur(8px);
		transition:
			opacity 1.05s ease,
			transform 1.05s cubic-bezier(0.22, 1, 0.36, 1),
			filter 1.05s ease;
		transition-delay: calc(var(--i, 0) * 26ms);
	}

	.chs-video-hero--cinematic.is-intro .chs-vh-ch {
		opacity: 1;
		transform: none;
		filter: none;
	}
}

/* Soft bottom-to-top wipe: a moving gradient mask with an 18%-tall feathered
   edge. --wipe 0 = fully hidden, 1 = fully revealed. */
.chs-video-hero--cinematic.is-cinematic .chs-video-hero__wipe {
	-webkit-mask-image: linear-gradient(
		to top,
		#000 calc(var(--wipe, 0) * 135% - 18%),
		transparent calc(var(--wipe, 0) * 135%)
	);
	mask-image: linear-gradient(
		to top,
		#000 calc(var(--wipe, 0) * 135% - 18%),
		transparent calc(var(--wipe, 0) * 135%)
	);
}

/* Scroll cue: fades in on a timer (inner), disappears the moment scrolling
   starts (outer, scroll-driven, intentionally untransitioned).
   The stage is viewport-tall but starts below the (soon to scroll away)
   header, so its bottom edge sits below the fold at rest — anchor the cue
   a header-height up so it's visible at the bottom of the *initial* view. */
.chs-video-hero--cinematic.is-cinematic .chs-video-hero__cue {
	position: absolute;
	/* Full-width flex centering — immune to alignfull/scrollbar offsets that
	   can nudge a left:50% + translateX(-50%) anchor off visual center. */
	left: 0;
	right: 0;
	display: flex;
	justify-content: center;
	bottom: calc(var(--chs-header-h, 72px) + 24px);
	z-index: 6;
	opacity: max(0, calc(1 - var(--p, 0) * 10));
	pointer-events: none;
}

/* Logged-in views: the fixed admin bar shifts the page down 32px, which would
   clip the chevron below the fold. Visitors never see this. */
.admin-bar .chs-video-hero--cinematic.is-cinematic .chs-video-hero__cue {
	bottom: calc(var(--chs-header-h, 72px) + 56px);
}

.chs-video-hero--cinematic.is-cinematic .chs-video-hero__cue-inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 7px;
	opacity: 0;
	transition: opacity 1.6s ease;
}

/* 80% resting opacity so the cue defers to the scene-1 headline. */
.chs-video-hero--cinematic.is-cinematic.is-cue .chs-video-hero__cue-inner {
	opacity: 0.8;
}

.chs-video-hero--cinematic.is-cinematic.is-cue .chs-video-hero__cue-chevron {
	animation: chs-cue-bob 2.2s ease-in-out infinite;
}

@keyframes chs-cue-bob {
	0%,
	100% {
		transform: translateY(0);
	}
	50% {
		transform: translateY(6px);
	}
}

/* Slide-up content panel: horizontally centered, anchored in the lower third
   of the viewport (clear of the faces in the photo); --panel scrubs it up
   from below the viewport. */
.chs-video-hero--cinematic.is-cinematic .chs-video-hero__panel {
	position: absolute;
	z-index: 7;
	left: 50%;
	/* At least a 10%-of-viewport margin between the card and the bottom of
	   the VIEWPORT. The stage's own bottom edge sits a header-height below
	   the fold while the page rests at the top, so compensate for it —
	   same geometry as the scroll cue. */
	bottom: calc(4vh + var(--chs-header-h, 72px));
	bottom: calc(4svh + var(--chs-header-h, 72px));
	width: min(480px, 38vw);
	transform: translate3d(-50%, calc((1 - var(--panel, 0)) * 115vh), 0);
	will-change: transform;
}

/* Logged-in views: the fixed admin bar shifts the page down another 32px. */
.admin-bar .chs-video-hero--cinematic.is-cinematic .chs-video-hero__panel {
	bottom: calc(4vh + var(--chs-header-h, 72px) + 32px);
	bottom: calc(4svh + var(--chs-header-h, 72px) + 32px);
}

/* Belt and braces: if reduced-motion flips on mid-session, freeze the
   letter transitions even before JS reacts. */
@media (prefers-reduced-motion: reduce) {
	.chs-video-hero--cinematic .chs-vh-ch {
		transition: none !important;
		opacity: 1 !important;
		transform: none !important;
		filter: none !important;
	}

	.chs-video-hero--cinematic .chs-video-hero__cue-chevron {
		animation: none !important;
	}
}

/* TranslatePress editor mode for the (parked) cinematic path: with the
   animation bailed out, force the headline and panel visible so their
   strings stay selectable. Mirrors the sequence-mode .is-trp-editor block. */
.chs-video-hero--cinematic.is-trp-editor .chs-video-hero__headline-raw,
.chs-video-hero--cinematic.is-trp-editor .chs-video-hero__panel {
	opacity: 1 !important;
}
