/*
Theme Name: RDV Robotics 2026
Description: Custom FSE block theme for RDV Robotics
Theme URI: https://localwebhub.com
Version: 1.0.45
Author: Dmitriy Agadzhanov
Author URI: https://localwebhub.com
*/

/* 
add font family to reset.min.css
*/

:root {
	/* scroll-margin for in-page anchors: the fixed header's height + 8px
	   (mobile: 16px inset + 81px bar; desktop: the 103px bar) */
	--theme-menu-height: 105px;
	/* Header/footer red (Figma "RDV Updates", 2026-10-05) — current nav item,
	   underline, CTA stroke, sign-up button; the deep red ends the footer
	   gradient. Not in the theme.json palette yet: the sitewide button/type
	   update in the same Figma may settle the editor colors. */
	--rdv-red: #bf4042;
	--rdv-red-deep: #6b2021;
	--theme-content-padding: 15px;
	--theme-bullet-text: #444444; /* palette Charcoal — copy on the "Bullets" cream pills */
	--rdv-columns-gap-mobile: 80px; /* vertical gap between STACKED core/columns (client, 2026-07-29) */

	/* Chamfered corners — the design's replacement for rounded ones (client,
	   2026-09-25). The shape is spelled out once so every block offering the
	   "Chamfered" style cuts the same corner; the percentages resolve against
	   whichever box USES it. var() inside a custom property is substituted
	   where it is declared, so the size is global: overriding --rdv-chamfer
	   on one element does not reshape it.

	   Two sizes, both 20px from 992 up (the 992 :root block below). Phone
	   values are from the Figma "RDV Updates" iPhone frame 2:1090: cards cut
	   15px (the news cards), pictures 5px (the photos measure 4.5-5). */
	--rdv-chamfer: 15px;       /* cards: core/group + core/column, footer sign-up box */
	--rdv-chamfer-photo: 5px;  /* pictures: core/image, acf/media, acf/media-slideshow, acf/section */
	--rdv-chamfer-line: 1px; /* outline width on bordered chamfered cards */
	--rdv-chamfer-shape: polygon(
		var(--rdv-chamfer) 0, calc(100% - var(--rdv-chamfer)) 0,
		100% var(--rdv-chamfer), 100% calc(100% - var(--rdv-chamfer)),
		calc(100% - var(--rdv-chamfer)) 100%, var(--rdv-chamfer) 100%,
		0 calc(100% - var(--rdv-chamfer)), 0 var(--rdv-chamfer)
	);
	--rdv-chamfer-photo-shape: polygon(
		var(--rdv-chamfer-photo) 0, calc(100% - var(--rdv-chamfer-photo)) 0,
		100% var(--rdv-chamfer-photo), 100% calc(100% - var(--rdv-chamfer-photo)),
		calc(100% - var(--rdv-chamfer-photo)) 100%, var(--rdv-chamfer-photo) 100%,
		0 calc(100% - var(--rdv-chamfer-photo)), 0 var(--rdv-chamfer-photo)
	);

	/* Scroll reveal — one move, shared by everything that enters, so the type
	   and the units around it stay in step (see "Scroll reveal" below). The
	   duration, curve and rise are measured from Dapper's mock-up video
	   "RDV Type animation" (2026-10-07). */
	--rdv-snap-ms: 500ms;
	--rdv-snap-ease: cubic-bezier(0.2, 0.1, 0.75, 0.35); /* accelerates the whole way, lands at full speed */
	--rdv-stagger: 150ms; /* between pieces of one module (reveal.js reads it) */
	--rdv-rise: clamp(48px, 7vw, 100px); /* how far type rises: 100px at 1440, as in the mock */

	/* Responsive spacing - override WordPress preset spacing */
	--wp--preset--spacing--small: 15px;
	--wp--preset--spacing--medium: 30px;
	--wp--preset--spacing--large: 60px;
	--wp--preset--spacing--x-large: 90px;
}

@media (min-width: 992px) {
	:root {
		--theme-content-padding: 30px;
		
		/* Desktop spacing - override WordPress preset spacing */
		--wp--preset--spacing--small: 30px;
		--wp--preset--spacing--medium: 60px;
		--wp--preset--spacing--large: 90px;
		--wp--preset--spacing--x-large: 120px;

		--theme-menu-height: 111px;

		--rdv-chamfer: 20px;
		--rdv-chamfer-photo: 20px;
	}
}

html {
	scroll-behavior: smooth;
}

/* ---------------------------------------------------------------------------
   Typography — RDV Robotics type scale
   Figma "RDV Updates" (rV6qH4Bg6mEgUuRh1VNSIa), "Type Hierarchy" specimen,
   Chris Yates 2026-10-21: "We're using Oxanium rather than Titillium."
     Oxanium  → H1–H6   (400 everywhere except H5, which is 600 in title case)
     Roboto   → H7, Subhead, Body, Caption
   The specimen still sets H3–H5 in Titillium; per Chris's note they are
   Oxanium here at the specimen's sizes, weights and spacing. It gives desktop
   sizes only; the phone end of each fluid preset (theme.json) is ours.
   Figma states tracking in percent, so its -6 on H1 is -0.06em here.
   Sizes reference the theme.json fluid presets; these classes mirror
   styles.elements.h1–h6 + base Body so the type styles are usable both on
   native heading tags (via theme.json) and as utility classes on any element.
   H7 and Caption exist ONLY here and as font-size presets — theme.json has no
   styles.elements slot for them (there is no <h7>), so a class is the only way
   to apply them.
   The .has-*-font-size preset classes (added when an editor picks a size in
   the UI) are paired in too — WP only generates their font-size, so without
   this they'd keep the body line-height/tracking, far too loose at H1 scale.
--------------------------------------------------------------------------- */

.acf-block-preview,
body:not(.wp-admin) {
	font-family: var(--wp--preset--font-family--roboto, "Roboto", sans-serif);
	font-size: var(--wp--preset--font-size--body, 18px);
	font-weight: 400;
	line-height: 1.28;
	letter-spacing: 0.03em;
}

.h1,
.h2,
.h3,
.h4,
.h5,
.h6,
.h7,
.subhead,
.caption {
	margin: 0;
}

.h1,
.has-h-1-font-size {
	font-family: var(--wp--preset--font-family--oxanium, "Oxanium", sans-serif);
	font-size: var(--wp--preset--font-size--h-1, 92px);
	font-weight: 400;
	line-height: 0.935;
	letter-spacing: -0.06em;
}

.h2,
.has-h-2-font-size {
	font-family: var(--wp--preset--font-family--oxanium, "Oxanium", sans-serif);
	font-size: var(--wp--preset--font-size--h-2, 70px);
	font-weight: 400;
	line-height: 1.043;
	letter-spacing: -0.06em;
}

.h3,
.has-h-3-font-size {
	font-family: var(--wp--preset--font-family--oxanium, "Oxanium", sans-serif);
	font-size: var(--wp--preset--font-size--h-3, 58px);
	font-weight: 400;
	line-height: 1;
	letter-spacing: 0.01em;
}

.h4,
.has-h-4-font-size {
	font-family: var(--wp--preset--font-family--oxanium, "Oxanium", sans-serif);
	font-size: var(--wp--preset--font-size--h-4, 42px);
	font-weight: 400;
	line-height: 1.071;
	letter-spacing: 0.01em;
}

.h5,
.has-h-5-font-size {
	font-family: var(--wp--preset--font-family--oxanium, "Oxanium", sans-serif);
	font-size: var(--wp--preset--font-size--h-5, 38px);
	font-weight: 600;
	line-height: 1.079;
	letter-spacing: 0.01em;
	text-transform: capitalize;
}

.h6,
.has-h-6-font-size {
	font-family: var(--wp--preset--font-family--oxanium, "Oxanium", sans-serif);
	font-size: var(--wp--preset--font-size--h-6, 28px);
	font-weight: 400;
	line-height: 1.214;
	letter-spacing: 0.01em;
}

/* H7 — Roboto at 25px (Titillium 21px until 2026-10-21) */
.h7,
.has-h-7-font-size {
	font-family: var(--wp--preset--font-family--roboto, "Roboto", sans-serif);
	font-size: var(--wp--preset--font-size--h-7, 25px);
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: 0.03em;
}

/* Subhead — Roboto at 21px (not in the 2026-10-21 specimen; unchanged) */
.subhead,
.has-subhead-font-size {
	font-family: var(--wp--preset--font-family--roboto, "Roboto", sans-serif);
	font-size: var(--wp--preset--font-size--subhead, 21px);
	font-weight: 400;
	line-height: 1.33;
	letter-spacing: 0.03em;
}

/* Body-size preset picked on a heading: restore body metrics too */
.has-body-font-size {
	font-family: var(--wp--preset--font-family--roboto, "Roboto", sans-serif);
	font-weight: 400;
	line-height: 1.28;
	letter-spacing: 0.03em;
	text-transform: none;
}

/* Caption — 16px with a little more tracking than Body (measured 3.6%) */
.caption,
.has-caption-font-size {
	font-family: var(--wp--preset--font-family--roboto, "Roboto", sans-serif);
	font-size: var(--wp--preset--font-size--caption, 16px);
	font-weight: 400;
	line-height: 1.25;
	letter-spacing: 0.036em;
}

/* Label paragraph style (plus icon + short label) */
p.is-style-label {
	display: flex;
	align-items: center;
	gap: 6px;
	font-size: 15px;
	line-height: 1.15;
	letter-spacing: 0.038em;
}
p.is-style-label::before {
	content: "";
	flex: none;
	width: 21px;
	height: 21px;
	background: url(images/plus-icon.svg) no-repeat center / contain;
}

/* Quote (core/quote). Set in from the text column with no rule down the
   left (Figma "RDV Updates" Frame 7: 79px at 1728; Dapper's "Add indent text
   option for pull quote"), so that is every quote's default and core's
   theme.css border goes. Core's own "Plain" style is the option for a quote
   that sits flush. The quoted words carry their own italics in the content,
   leaving the attribution ("said Dr. Ariel Ekblaw") upright. */
body .wp-block-quote {
	border-left: 0;
	padding-left: clamp(24px, 4.57vw, 79px);
}

body .wp-block-quote.is-style-plain {
	padding-left: 0;
}

body:not(.wp-admin) [id] {
	scroll-margin-top: var(--theme-menu-height);
}

/* Section-level ACF blocks own their vertical spacing — cancel the blockGap
   margin that constrained layouts (post-content) add between top-level
   siblings. :root matches core's `:root :where(.is-layout-constrained) > *`
   specificity floor, then the class outranks it. */
:root .wp-block-acf-section,
:root .wp-block-acf-hero,
:root .wp-block-acf-copy,
:root .wp-block-acf-spacer,
:root .wp-block-acf-toggle,
:root .wp-block-acf-accordion,
:root .wp-block-acf-marquee,
:root .wp-block-acf-slider,
:root .wp-block-acf-news {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* Stacked core/columns get a wider vertical gap on mobile (client: 80px).
   The gap normally comes from global styles' `:root :where(.is-layout-flex)
   {gap:24px}` (0,1,0) — do NOT override .is-layout-flex itself, that class is
   on every flex group site-wide (header pill, nav, groups). `.wp-block-columns
   :not(.is-not-stacked-on-mobile)` is (0,2,0), so it wins on specificity
   regardless of load order (no !important).
   Breakpoint is CORE's 781px stacking boundary, not the theme's 756px — at
   756–781px columns are already stacked and would otherwise keep 24px.
   row-gap only: once stacked each column is flex-basis:100%, so column-gap is
   moot and stays on the 24px blockGap for the wrap boundary.
   Tune per context by re-setting the var on a wrapper (see .is-style-stat-row).
   An EMPTY column is a desktop spacer (e.g. the blank half beside Home's
   "Build Spacecraft" copy). Stacked, it is nothing but one more 80px gap
   under the real content, so it is dropped. In the editor it still holds its
   "+" appender, so it is not :empty there and stays clickable. */
@media (max-width: 781.98px) {
	.wp-block-columns:not(.is-not-stacked-on-mobile) {
		row-gap: var(--rdv-columns-gap-mobile);
	}
	.wp-block-columns:not(.is-not-stacked-on-mobile) > .wp-block-column:empty {
		display: none;
	}
}

/* 4+ column core/columns rows keep STACKING until 992px (client, 2026-08-10).
   Core flips its columns block straight from fully stacked to all-across at
   exactly 782px — `@media (min-width:782px){.wp-block-columns{flex-wrap:nowrap
   !important}}` plus `flex-basis:0;flex-grow:1` on the columns. Current core
   has NO intermediate 2-up step (older versions did), so 782px is the only
   boundary there is. Fine for 2 or 3 columns; a 4-column stat row lands at
   163px per column at 850px (measured on Home's "380K SF" row), so the
   boundary moves to 992px for rows of 4+ only. Client picked the full stack
   over a 2×2 for this band (2026-08-10).
   `:has(> .wp-block-column:nth-child(4))` IS the column count — unlike a Grid
   group, whose N core hides inside a generated container class, a columns
   block's children are literally its columns, so plain CSS can count them and
   the editor canvas gets it for free.
   `!important` is required to beat core's own `!important` (sanctioned vendor
   override). row-gap keeps the 80px stacked spacing continuous across the
   782px line instead of dropping back to blockGap's 24px mid-stack. */
@media (min-width: 782px) and (max-width: 991.98px) {
	.wp-block-columns:not(.is-not-stacked-on-mobile):has(> .wp-block-column:nth-child(4)) {
		flex-wrap: wrap !important;
		row-gap: var(--rdv-columns-gap-mobile);
	}
	.wp-block-columns:not(.is-not-stacked-on-mobile):has(> .wp-block-column:nth-child(4)) > .wp-block-column {
		flex-basis: 100% !important;
	}
	.wp-block-columns:not(.is-not-stacked-on-mobile):has(> .wp-block-column:nth-child(4)) > .wp-block-column:empty {
		display: none;
	}
}

/* "Stat Row" block style for core/columns (client, 2026-08-10) — the 80px
   stacked gap is right for content columns but far too airy between short
   stats ("380K SF / Total Space", "1 Block"), so those rows opt down to
   blockGap (24px).
   NOTE this deliberately does NOT try to out-specify the two rules above, and
   nothing here needs to match their long `:has()` selectors: the gap travels
   through a CUSTOM PROPERTY, so the winner is whoever sets `--rdv-columns-gap-
   mobile` on (or above) the element, and a single class does that at (0,2,0).
   That is also why a direct `row-gap: 24px` override is the hard way round —
   it has to beat (0,5,0) inside the right media query, twice. Set the var
   instead and both bands follow automatically.
   Registered in functions.php so editors click it in the Styles panel rather
   than typing a CSS class; the whole knob is the one value below. */
.wp-block-columns.is-style-stat-row {
	--rdv-columns-gap-mobile: 24px;
}

/* ---------------------------------------------------------------------------
   "Chamfered" block style (client, 2026-09-25) — 45° corner cuts in place of
   rounded corners: 20px from 992 up; on phones 15px on cards and 5px on
   pictures (sizes in :root). Registered in functions.php; the core blocks are
   styled here, acf/section / acf/media / acf/media-slideshow in their own
   block CSS.

   clip-path rather than border-radius: `corner-shape: bevel` is the native
   answer but is Chromium-only as of 2026, well short of the 95% bar. The
   price is that nothing survives outside the polygon — box-shadows, focus
   outlines, anything that deliberately overhangs the box. None of the blocks
   that offer the style draw outside themselves, bar one (see section.css).
   A border-radius from the Border panel needs no reset: any radius up to the
   chamfer size falls entirely inside the cut-away corner.

   core/image is cut on the <img>, not the <figure>, so a caption under the
   picture keeps its square box. --------------------------------------------- */
.wp-block-group.is-style-chamfered,
.wp-block-column.is-style-chamfered {
	clip-path: var(--rdv-chamfer-shape);
}
.wp-block-image.is-style-chamfered img {
	clip-path: var(--rdv-chamfer-photo-shape);
}

/* Bordered cards. clip-path shears a border off at the corners without
   drawing the diagonal, so a hairline card would read as four loose lines.
   So the box keeps its border for layout but stops painting it — a
   transparent border-image replaces the paint and leaves the computed
   border-color intact — and ::after redraws the whole outline as one ring:
   a frame as deep as the chamfer, colored `inherit` (whatever the editor
   picked in the Border panel), cut down to a hairline by an evenodd polygon
   tracing the chamfer outline and then the same outline one line-width in.
   The line width is the fixed --rdv-chamfer-line: CSS cannot read a border
   width into calc(), and every card on this site is a 1px hairline. */
.wp-block-group.is-style-chamfered:is(.has-border-color, [style*="border-width"]),
.wp-block-column.is-style-chamfered:is(.has-border-color, [style*="border-width"]) {
	position: relative;
	border-image: linear-gradient(transparent, transparent) 1;
}
.wp-block-group.is-style-chamfered:is(.has-border-color, [style*="border-width"])::after,
.wp-block-column.is-style-chamfered:is(.has-border-color, [style*="border-width"])::after {
	--c: var(--rdv-chamfer);
	--b: var(--rdv-chamfer-line);
	--k: calc(var(--c) + var(--b) * 0.4142); /* inner cut, c + b(√2 − 1): keeps the diagonal b thick */
	content: "";
	position: absolute;
	inset: calc(-1 * var(--b)); /* padding box → border box */
	border: var(--c) solid;
	border-color: inherit;
	clip-path: polygon(evenodd,
		var(--c) 0, calc(100% - var(--c)) 0,
		100% var(--c), 100% calc(100% - var(--c)),
		calc(100% - var(--c)) 100%, var(--c) 100%,
		0 calc(100% - var(--c)), 0 var(--c),
		var(--c) 0,
		var(--k) var(--b), var(--b) var(--k),
		var(--b) calc(100% - var(--k)), var(--k) calc(100% - var(--b)),
		calc(100% - var(--k)) calc(100% - var(--b)), calc(100% - var(--b)) calc(100% - var(--k)),
		calc(100% - var(--b)) var(--k), calc(100% - var(--k)) var(--b),
		var(--k) var(--b)
	);
	pointer-events: none;
}

.theme-container {
	max-width: var(--wp--style--global--wide-size, 1400px);
	margin-left: auto;
	margin-right: auto;
	padding-left: var(--theme-content-padding);
	padding-right: var(--theme-content-padding);
}

.theme-row {
	display: flex;
	flex-wrap: wrap;
	margin-right: calc(-1 * var(--theme-content-padding));
	margin-left: calc(-1 * var(--theme-content-padding));
}

.theme-row > * {
	flex-shrink: 0;
	width: 100%;
	max-width: 100%;
	padding-right: var(--theme-content-padding);
	padding-left: var(--theme-content-padding);
	gap: var(--theme-content-padding);
}

@media (min-width: 992px) {
	.theme-col-lg {
		flex: 1 0 0%;
	}

	.theme-col-lg-auto {
		flex: 0 0 auto;
		width: auto;
	}

    .theme-lg-two-col {
		flex: 1 1 calc((100% - (calc(var(--theme-content-padding)) * 1)) / 2);
    }

	.theme-lg-three-col {
       flex: 1 1 calc((100% - (calc(var(--theme-content-padding)) * 2)) / 3);
    }

    .theme-lg-four-col {
       flex: 1 1 calc((100% - (calc(var(--theme-content-padding)) * 3)) / 4);
    }
	
}

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

.object-fit-contain > img {
	height: 100%;
	width: 100%;	
	object-fit: contain;
}

.alignleft,
.alignright,
.aligncenter {
	display: block;
	margin: 0 auto 30px auto;
}

@media (min-width:768px) {
	.alignleft {
		margin: 0 20px 20px 0;
		float: left;
	}

	.alignright {
		float: right;
		margin: 0 0 20px 20px;
	}
}

.article img {
	max-width: 100%;
	height: auto;
}

.screen-reader-text {
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: polygon(0px 0px, 0px 0px,0px 0px, 0px 0px);
	position: absolute !important;
	white-space: nowrap;
	height: 1px;
	width: 1px;
	overflow: hidden;
}

@media (max-width: 575px) {
	.sm-ignore-br br {
		display: none;
	}
}

@media (max-width: 767px) {
	.md-ignore-br br {
		display: none;
	}
}

@media (max-width: 991px) {
	.lg-ignore-br br {
		display: none;
	}
}

.acf-block-preview * {
	box-sizing: border-box;
}

.acf-block-preview > section,
.acf-block-preview > div {
	font-size: 12px;
	border: 1px solid #ccc;
	min-height: 50px;
	margin-top: 0 !important;
	margin-bottom: 0 !important;
}

.acf-block-preview > div:before,
.acf-block-preview > section:before {
	content: attr(data-blockname);
	position: absolute;
	top: 0;
	left: 0;
	padding: 2px;
	font-size: .875rem;
	background: #ccc;
	color: #000;
	z-index: 4;
}

.slick-slide img.lazyloading {
	opacity: 1;
}

/* .slick-track{
	display: flex !important;
}

.slick-slide {
	display: flex !important;
	height: auto;
} */

.slick-track {
	display: flex;
}

.slick-initialized .slick-slide {
    display: flex;
	flex-direction: column;
	height: auto;
}

.slick-initialized .slick-slide > div {
	flex-grow: 1;
}

.vimeo--video[data-fill="1"] {
	overflow: hidden;
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;	
}

.vimeo--video[data-fill="1"] iframe {
	position: absolute;
}

.has-fixed-background {
	background-attachment: fixed;
}

@supports (-webkit-overflow-scrolling: touch) {
	.has-fixed-background {
		background-attachment: scroll; 
	}
}

@media (prefers-reduced-motion: reduce) {
	.has-fixed-background {
		background-attachment: scroll; 
	}
}

.grecaptcha-badge{
	visibility: collapse !important;
}

.single-post--content-width > [data-blockname], 
.single-post--content-width > .alignfull {
	margin-left: -15px;
	margin-right: -15px;
}

@media (min-width: 780px) {
	.single-post--content-width > [data-blockname],
	.single-post--content-width > .alignfull {
		margin-left: calc(50% - 50vw);
		margin-right: calc(50% - 50vw);
		margin-left: calc(50% - ((100vw - var(--scrollbar-width)) / 2));
		margin-right: calc(50% - ((100vw - var(--scrollbar-width)) / 2));
	}
}

.main--section > p,
.main--section > .wp-block-heading,
.main--section > .wp-block-list {
	max-width: var(--wp--style--global--content-size, 900px);
	margin: 0 auto 1em;
	padding: 0 30px;
}

.main--section > .wp-block-list {
	padding-left: calc(30px + 1em);
}

/* ---------------------------------------------------------------------------
   Scroll reveal
   The classes are added by js/reveal.js — NOTHING here applies at first paint
   except the page headline's own animation (see "Page headline" below).
   That is deliberate: Chrome excludes opacity:0 elements from LCP, so hiding
   content in CSS and un-hiding it in JS delays LCP at every viewport height.
   reveal.js arms only what is already below the fold, so anything a visitor
   can see on load was never hidden. See the header of that file.

   It also means there are no editor-canvas guards to write (trap 10): the
   front-end script never runs in the block editor, so nothing there is armed.

   No will-change on pieces — a page here carries ~200 of them, and promoting
   that many compositor layers at once costs real mobile memory for no gain;
   opacity and transform already composite without the hint.

   THE MOTION is Dapper's mock-up "RDV Type animation" (2026-10-07), which
   replaced the words that assembled and recoiled ("modules snapping
   together", 2026-10-05): the bounce read as a bounce. Each piece rises from
   below as it fades in, accelerates the whole way and stops dead on its line
   — no overshoot, no settle. Type rises var(--rdv-rise) (100px at 1440, as
   in the mock); a unit (a photo, a card, a whole block) docks 24px on the same
   curve and clock. Opacity is linear and done by 85%, as measured in the mock.
---------------------------------------------------------------------------- */

.is-reveal-armed {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity calc(var(--rdv-snap-ms) * 0.85) linear,
		transform var(--rdv-snap-ms) var(--rdv-snap-ease);
	/* Set inline by reveal.js from the module's stagger queue. */
	transition-delay: var(--reveal-delay, 0ms);
}

.is-reveal-armed.is-reveal-type {
	transform: translateY(var(--rdv-rise));
}

.is-reveal-armed.is-revealed {
	opacity: 1;
	transform: none;
}

/* Page headline. The column (or news hero copy) holding the page's h1 is
   marked .is-hero-cascade by functions.php / inc/news.php, and its children
   rise in on load, one --rdv-stagger apart, in a CSS animation that starts
   from the first frame. An h1 outside such a container rises on its own
   (.is-type-hero). It has to be CSS from the server's markup: reveal.js runs
   after first paint, so arming the headline there would flash it visible,
   then hide it, then bring it back. No JS is needed for it to finish, so a
   failed script still ends with the headline on screen.
   The 100ms lead-in mirrors the mock's opening frames. LCP is safe: the
   pages' LCP is the hero video or photo, which never fades. */
.is-type-hero,
.is-hero-cascade > * {
	animation:
		rdv-rise-move var(--rdv-snap-ms) var(--rdv-snap-ease) both,
		rdv-rise-fade calc(var(--rdv-snap-ms) * 0.85) linear both;
	animation-delay: calc(100ms + var(--rise-i, 0) * var(--rdv-stagger));
}

.is-hero-cascade > :nth-child(2) { --rise-i: 1; }
.is-hero-cascade > :nth-child(3) { --rise-i: 2; }
.is-hero-cascade > :nth-child(4) { --rise-i: 3; }
.is-hero-cascade > :nth-child(n + 5) { --rise-i: 4; }

@keyframes rdv-rise-move {
	from { transform: translateY(var(--rdv-rise)); }
}

@keyframes rdv-rise-fade {
	from { opacity: 0; }
}

/* Boxes: a Section nested one level inside another (Home's "Build
   Spacecraft…", "Proven in Space", "Proudly Built In Colorado", Team's
   "Join Our Team", the news call-to-action). Glydways' motion for its
   full-width cards, which Dapper asked us to match: tied to the scroll, not
   played on a clock, so it runs backwards when scrolling up. reveal.js sets
   --box-p from 0 (the box's top at the bottom of the viewport) to 1 (its top
   half its height from the top). Their numbers: opacity 0.4 → 1, 24px → 0,
   scale 0.9 → 1. The box's copy rides along, as on Glydways.
   will-change is fine here: a page has at most three boxes. */
.is-box-armed {
	opacity: calc(0.4 + 0.6 * var(--box-p, 0));
	transform:
		translateY(calc(24px * (1 - var(--box-p, 0))))
		scale(calc(0.9 + 0.1 * var(--box-p, 0)));
	will-change: transform, opacity;
}

/* reveal.js arms nothing under reduced motion, so the first and last rules
   only matter if the setting is changed after load. The headline's rule is
   the real switch: it runs from CSS whatever the setting. */
@media (prefers-reduced-motion: reduce) {
	.is-reveal-armed,
	.is-reveal-armed.is-reveal-type,
	.is-box-armed {
		opacity: 1;
		transform: none;
		transition: none;
	}

	.is-type-hero,
	.is-hero-cascade > * {
		animation: none;
	}
}
