/**
 * css/components/hero.css — Website 2.0 shared component library (#122/#123)
 *
 * Full-bleed image hero: large art anchored bottom-right, absolutely
 * positioned UNDER the content, a legibility scrim over the lower-left
 * text, eyebrow + <h1> (rust, italic run switches to ink) + lede + a
 * two-link footer row. Reference: media.html `.hero`/`.hero-media`/
 * `.hero-scrim`/`.hero-body`/`.hero h1`/`.hero .lede`/`.hero-links`.
 *
 * `--content-edge` (140px, tokens.css) is the hero's one deliberate
 * exception to the centered `--frame`/`--pad-x` rhythm every `.cg-band`
 * uses (docs/Common Good website 2.0/CLAUDE.md "Hero is the one
 * exception"); the reference derives it as
 * `clamp(24px,5vw,84px) + clamp(0px,3vw,56px)` (.hero padding-inline +
 * .hero-body padding-left) which equals 140px at the desktop widths the
 * static token already commits to (same simplification stats.css made).
 *
 * Tokens only for colour/semantic values — no raw hex, no @layer, no
 * !important. Spacing/type values are copied exact (clamp() literals)
 * from the reference build, matching every other component file's
 * convention (see accordion.css/giant-word.css).
 */

.cg-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	min-height: clamp( 600px, 64vh, 880px );
	/* Horizontal gutter uses --pad-x (the centered 1314px content frame) so the
	   hero CONTENT stays inside the same frame as the bands and the astronaut
	   hero on wide viewports — the flat clamp(…,84px) let it spill past the
	   frame. The full-bleed art/video (.cg-hero__media, absolute inset:0) is
	   unaffected. */
	padding: clamp( 150px, 20vh, 210px ) var( --pad-x ) clamp( 40px, 6vh, 72px );
	background: var( --surface );
	color: var( --text );
}

.cg-hero__media {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

.cg-hero--megaphone .cg-hero__media img {
	position: absolute;
	right: clamp( -70px, -2.5vw, -10px );
	bottom: 0;
	display: block;
	width: auto;
	height: 100%;
	object-fit: contain;
}

.cg-hero__scrim {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient( 100deg, var( --cg-cream ) 20%, var( --cg-cream-0 ) 46% );
}

/* hammer variant (Services, #125) — starburst + hammer anchored top-right
   instead of bottom-right, its own scrim stop-points. Reference:
   services.html `.hero-media .burst`/`.hero-media .hammer`/`.hero-scrim`. */
.cg-hero--hammer .cg-hero__burst {
	position: absolute;
	top: clamp( 70px, 11vw, 215px );
	right: clamp( 48px, 8vw, 152px );
	width: clamp( 220px, 25vw, 480px );
	height: auto;
}

.cg-hero--hammer .cg-hero__hammer {
	position: absolute;
	top: clamp( 30px, 8.4vw, 161px );
	right: clamp( 64px, 11vw, 214px );
	width: clamp( 320px, 39vw, 751px );
	height: auto;
}

.cg-hero--hammer .cg-hero__scrim {
	background: linear-gradient( 100deg, var( --cg-cream ) 30%, var( --cg-cream-0 ) 58% );
}

/* rocket_cloud variant (Approach, #136) — no scrim needed (the art sits
   clear of the text column), rocket clipped at the band edge by the
   hero's own `overflow:hidden`, sized by hero HEIGHT so it stays
   proportional at every width. Reference: approach.html `.rocket`/`.cloud`. */
.cg-hero--rocket .cg-hero__scrim {
	display: none;
}

.cg-hero--rocket .cg-hero__rocket {
	position: absolute;
	z-index: 1;
	top: 20%;
	right: clamp( -150px, -6vw, -55px );
	height: 130%;
	width: auto;
	pointer-events: none;
	transform: rotate( 34deg );
	transform-origin: center;
}

.cg-hero--rocket .cg-hero__cloud {
	position: absolute;
	z-index: 0;
	height: auto;
	pointer-events: none;
}

.cg-hero--rocket .cg-hero__cloud--one {
	top: clamp( 80px, 11vw, 150px );
	right: clamp( 40px, 9vw, 190px );
	width: clamp( 300px, 33vw, 600px );
}

.cg-hero--rocket .cg-hero__cloud--two {
	top: clamp( 200px, 26vw, 380px );
	right: clamp( -120px, -6vw, -40px );
	width: clamp( 280px, 32vw, 560px );
	transform: scaleX( -1 );
}

.cg-hero__body {
	position: relative;
	z-index: 2;
	margin-top: auto;
	padding-left: clamp( 0px, 3vw, 56px );
}

/* #330: hero eyebrows are ink, not rust.
 *
 * The CD's note was "it looks dumb with an orange eyebrow and then an orange
 * headline" — true, and it only got worse once #328 turned every in-scope
 * headline rust, so the eyebrow and the H1 became the same colour stacked on
 * top of each other.
 *
 * Scoped to the hero eyebrow classes rather than changed on `.cg-eyebrow`
 * itself. The CD expected this to repaint every eyebrow sitewide and accepted
 * that, but it does not have to: the Media artboard keeps its *section*
 * eyebrows rust ("The Category Problem", "Built for CPG", "Why Our Media
 * Works" are all #e3581d) and only the hero eyebrow is #0e0e0c. So the
 * narrow change is also the one that matches the design — the global one
 * would have contradicted it on every band below the fold.
 *
 * `.cg-hero--video .cg-hero__eyebrow` (:488) stays cream at (0,2,0) and is
 * unaffected, which it must be — the homepage eyebrow sits on dark footage.
 */
.cg-hero__eyebrow,
.cg-case-hero__eyebrow {
	color: var( --cg-ink );
}

.cg-hero__eyebrow {
	margin: 0 0 30px;
}

/* #303: Tungsten Narrow Bold replaces Noe Text at 400. A condensed display
   face reads narrower/optically smaller than the serif at the same
   settings, so size is raised, tracking is pulled toward 0 (negative
   tracking on a condensed face closes the counters), and line-height is
   nudged up slightly to keep the taller cap-height from crowding a second
   line. Re-tuned against the pre-#303 rendering at 1440/390px -- see PR
   screenshots.

   max-width dropped from the pre-#303 `min(1010px,58%)` to `min(700px,44%)`
   -- NOT a like-for-like carry-over, and this comment previously
   misattributed why (adversarial review, 2nd pass, corrected it): with the
   wider box, the megaphone-variant heading ("Brand advertising creates
   demand. Shopper converts it. We connect both.") collides with the
   design-fixed art at 768px specifically (measured ~18% of the second
   line's box area sat on the art -- unreadable there), NOT at 1024-1920px,
   where the old box measured ZERO art intrusion. The narrower box clears
   768px cleanly. Line count is NOT restored to a universal 4-line match
   with pre-#303 main at every width -- it still renders 3 lines (not 4)
   at 1024/1280/1366/1440 with the new box; that is an accepted, documented
   consequence of the condensed face fitting more characters per line, not
   a defect, and is called out with before/after screenshots in the PR
   rather than claimed as a like-for-like restoration. Below 680px this is
   moot -- the `@media(max-width:680px)` rule further down releases
   max-width to `none` regardless. */
.cg-hero__title {
	max-width: min( 700px, 44% );
	margin: 0;
	font-family: var( --h1-font-family );
	font-weight: 700;
	font-size: clamp( 46px, 5.6vw, 102px );
	line-height: 1.02;
	letter-spacing: -0.5px;
	color: var( --accent );
	/* #303 (devils-advocate fix, 2nd pass): Tungsten Narrow ships no
	   italic file (css/fonts.css has 600/700 normal only), so `i` runs
	   render as a browser-synthesized oblique whose right-side ink
	   overhang (measured ~14px at this scale) is WIDER than the font's
	   own word-space advance (~13px) -- fully consuming the gap to the
	   next word (reproduced: home hero rendered "HappinessAgency").
	   `margin-right` on the `i` element itself does NOT survive
	   js/cg-motion.js's buildLines(): it destroys the original `i` and
	   rebuilds each word as a plain, classless `<span style="font-style:
	   italic">`, copying only font-style/color -- so any CSS keyed to the
	   `i` selector or its class stops matching the instant the reveal
	   animation runs (confirmed: computed margin-right was back to 0px
	   after load). word-spacing on this ancestor rule survives instead,
	   because it's inherited and applies to the literal space *character*
	   between the rebuilt word-spans, not to the destroyed `i` element.
	   0.12em was tuned empirically (0.08-0.2em all close the gap; this is
	   the smallest value with visible safety margin) to avoid loosening
	   the rest of the title's tracking more than necessary -- it applies
	   to every word gap, not just the italic one, since there's no
	   surviving hook to target only that junction post-reveal. */
	word-spacing: 0.12em;
}

/* #303 (devils-advocate fix): the scroll-reveal mask's right inset
   (`.anim-linetxt`, css/components/motion.css) sits exactly at each
   line's own box edge once revealed -- clipping the same Tungsten Narrow
   synthesized-oblique overhang the italic-run fix above describes.
   Reproduced as a clipped "connec[t]" on /media/ at 768px and 1536px.
   Widened here, scoped to hero titles only (not motion.css's sitewide
   default, which every other `.anim-mask` element also relies on) --
   specificity has to beat the shared `.anim-mask.in .anim-linetxt` rule,
   which is why this compounds all three classes onto one selector rather
   than nesting. Same "clears the worst case with room to spare" reasoning
   motion.css's own docblock already uses for its vertical insets. */
.cg-hero__title.anim-mask.in .anim-linetxt {
	clip-path: inset( -0.25em -0.2em -0.25em 0 );
}

/* #322: the `<i>` run renders upright, not italic.
 *
 * Hero headings carry an italic phrase in ACF content — the homepage's
 * `<i>The Health &<br>Happiness</i> Agency` and /media/'s `<i>We connect
 * both.</i>`. That was a real face while H1 was Noe Text (fonts.css ships
 * NoeText-RegularItalic). #303 moved H1 to Tungsten Narrow Bold, which
 * ships **no italic file** — so `font-style: italic` made the browser
 * synthesize an oblique by shearing the upright glyphs. The CD reported it
 * as "half of the H1 is in italics, which is not something I asked for".
 *
 * Dropping the declaration (rather than editing the two headings) keeps the
 * `<i>` markup available for a future treatment and fixes every environment
 * at once — the same call #306 made when it retired the colour overrides on
 * these runs and left their `<span class="ink">` markup in place.
 *
 * Consequence for the CD, stated plainly: with neither italic (here) nor a
 * colour override (#306), the `<i>` phrase no longer reads as emphasis at
 * all — the H1 is now one uniform Tungsten Narrow Bold, which is the
 * literal reading of "H1 = Tungsten Narrow Bold" plus "headlines are a
 * single solid colour".
 */
.cg-hero__title i {
	font-style: normal;
}

/* #306: `.ink` (Approach's two-line H1 second line, `<span class="ink">`)
   used to recolour this run to ink against the base rust title, producing
   a two-tone heading. Removed per the CD's "single solid colour"
   direction — the run now simply inherits `.cg-hero__title`'s own rust.
   The markup (`<span class="ink">`) is left in ACF content untouched;
   only this now-empty rule is gone. */

/* hammer variant (Services, #125) — base heading is ink; the `<em>` run
   is not italic. Was the inverse colour pattern of the other two
   variants (base ink, `<em>` run rust) until #306 (single-solid-colour
   headlines) dropped the run's colour override -- it now simply
   inherits the title's own ink, same as the rest of the text.
   Reference: services.html `.hero h1`/`.hero h1 em`. */
/* #303: retuned font-size for Tungsten Narrow (was clamp(40px,5vw,88px) for
   Noe Text) -- weight/line-height/letter-spacing come from the base rule
   above. max-width is unchanged; the narrower condensed face fits more
   characters in the same 60%-of-hero column, so this was re-checked for
   line-count drift against pre-#303 main (see PR screenshots). */
/* #328: the ink override is gone, so this falls through to the base
   `.cg-hero__title` rule's `color: var( --accent )` — Services' H1 is rust,
   per the CD (2026-08-05). Deleting the declaration rather than restating
   rust keeps one source of truth for the hero H1 colour. */
.cg-hero--hammer .cg-hero__title {
	max-width: min( 760px, 60% );
	font-size: clamp( 46px, 5.4vw, 96px );
}

.cg-hero--hammer .cg-hero__title em {
	font-style: normal;
}

.cg-hero--hammer {
	min-height: clamp( 600px, 64vh, 820px );
}

.cg-hero--hammer .cg-hero__lede {
	max-width: 454px;
	font-weight: 400;
	line-height: 1.7;
}

.cg-hero--hammer .cg-hero__links {
	margin-top: 44px;
}

/* rocket_cloud variant (Approach) — its own min-height/padding rhythm
   (shorter band, asymmetric inset: --content-edge left / --pad-x right,
   set directly on the outer element — approach.html's `.hero` has no
   nested body wrapper, unlike Media's composed content-edge). Reference:
   approach.html `.hero`. */
.cg-hero--rocket {
	min-height: clamp( 560px, 60vh, 760px );
	padding: clamp( 150px, 20vh, 232px ) var( --pad-x ) clamp( 40px, 5vh, 72px ) var( --content-edge );
}

.cg-hero--rocket .cg-hero__body {
	padding-left: 0;
}

/* rocket_cloud variant — no 58%-width clamp (short two-line heading).
   Reference: approach.html `.hero h1`. #303: was `font-weight: 300` for
   the lighter-weight serif; Tungsten Narrow ships only 600/700 physical
   files (css/fonts.css), so 300 would resolve to a browser-matched/
   synthesized face instead of a real one -- set to 700 like every other
   variant rather than leave an unexamined mismatch. */
/* #399 note: this variant rule is NOT where the 20% reduction lives. On
   every page that renders `--rocket` the (0,3,0) `.cg-hero__top
   .cg-hero__body .cg-hero__title` rule further down wins, so setting a
   value here would be dead code. Left at `none`. */
.cg-hero--rocket .cg-hero__title {
	max-width: none;
	font-weight: 700;
}

/* #330 phase 2: `.cg-case-hero__lede` shares this treatment. Adding a
   selector to an existing rule cannot change what the original selector
   matches, so the four phase-1 hero pages are untouched by it — and the
   14px/1.6 sans measure the CD signed off on lives in ONE place rather than
   being replicated into template-single-work.css, where it would drift.
   The case-study aside re-declares only what genuinely differs (weight and
   line-height), see `.cg-case-hero__lede` there. */
.cg-hero__lede,
.cg-case-hero__lede {
	max-width: 460px;
	margin: 34px 0 0;
	font-family: var( --font-sans );
	font-weight: 700;
	/* 16px, not 14px (#398). Reviewer rule, John Gilbert 2026-08-18 on the
	   Awards PDF: "All hero header copy on the right side of the page is 16px
	   across all headers across every template." Sizing all of these from ONE
	   rule is deliberate — see the header comment in blocks/cg/page-header.php.
	   `.cg-hero--video .cg-hero__lede` (:666) keeps its own 17px: the home hero
	   is a different lockup with its own font stack and carried no comment. */
	font-size: 16px;
	line-height: 1.6;
	letter-spacing: 0;
	color: var( --cg-ink );
}

.cg-hero__lede p,
.cg-case-hero__lede p {
	margin: 0 0 1.2em;
}

.cg-hero__lede p:last-child,
.cg-case-hero__lede p:last-child {
	margin-bottom: 0;
}

/* megaphone (Media) never got its own override, unlike every other hero
   variant below (hammer/rocket/video/astronaut all set 400) — left at the
   base 700 it reads heavier than the rest of the site's body copy (#cg-body
   is 400). CD review 2026-08-03: "match font weight here to the rest of
   the site, this looks heavier." */
.cg-hero--megaphone .cg-hero__lede {
	font-weight: 400;
}

/* rocket_cloud variant — two-paragraph lede, regular weight.
   Reference: approach.html `.hero .lede`. #207 (designer 2026-07-22):
   narrower measure — the body-copy box was too wide at 775px. */
.cg-hero--rocket .cg-hero__lede {
	max-width: 620px;
	margin-top: 40px;
	font-weight: 400;
	line-height: 1.7;
}

/* #330 phase 2 — placeholder copy announces itself (see
   inc/cg-components.php cg_is_placeholder_copy()). Applied to any hero lede
   whose text is Lorem Ipsum boilerplate; it disappears by itself the moment
   real copy replaces the placeholder, so there is nothing to switch off later
   and no cleanup task that can be forgotten.

   Every colour here is a RAW HEX ON PURPOSE, not a token. This must not be
   mistakable for a brand colour or a design decision, and it must not inherit
   a future palette change that could make it subtle. If a token ever made
   this blend in, the marker would have failed at its one job.

   Not gated to non-production either: hiding it on Live would make Live the
   only environment where placeholder copy looks like finished copy. */
.cg-placeholder {
	background: #fff3a3;
	outline: 2px dashed #a8801a;
	outline-offset: 4px;
}

.cg-placeholder::before {
	content: "⚠ PLACEHOLDER COPY — NOT FOR LIVE";
	display: block;
	margin-bottom: 8px;
	font-family: var( --font-sans );
	font-weight: 700;
	font-size: 10px;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #7a5c00;
}

/* #330 phase 2: the link row is identical on both hero families — same flex
   row, same 1px divider, same 10px letterspaced cue. Shared by selector for
   the same reason as `.cg-hero__lede` above. */
.cg-hero__links,
.cg-case-hero__links {
	display: flex;
	align-items: center;
	gap: 34px;
	margin-top: 48px;
}

.cg-hero__divider,
.cg-case-hero__divider {
	width: 1px;
	height: 18px;
	background: var( --cg-border );
}

.cg-hero__scroll,
.cg-case-hero__scroll {
	font-family: var( --font-sans );
	font-weight: 700;
	font-size: 10px;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var( --cg-ink );
}

@media ( max-width: 1024px ) {
	.cg-hero--rocket .cg-hero__rocket {
		width: clamp( 280px, 50vw, 460px );
		height: auto;
		right: -8vw;
		top: 6vh;
	}

	.cg-hero--hammer .cg-hero__title {
		max-width: none;
	}

	.cg-hero--hammer .cg-hero__hammer {
		opacity: 0.5;
	}
}

@media ( max-width: 680px ) {
	.cg-hero__title {
		max-width: none;
	}

	.cg-hero--megaphone .cg-hero__media img {
		top: 5vh;
		right: -14vw;
		width: auto;
		height: 58vh;
	}

	.cg-hero__scrim {
		background: linear-gradient( 122deg, var( --cg-cream ) 30%, var( --cg-cream-0 ) 66% ),
			linear-gradient( 0deg, var( --cg-cream ) 6%, var( --cg-cream-0 ) 42% );
	}

	.cg-hero--rocket .cg-hero__rocket {
		opacity: 0.5;
		right: -16vw;
		top: 8vh;
	}

	/* hammer variant (Services, #125) — its own mobile scrim stop-points.
	   Reference: services.html `@media(max-width:680px) .hero-scrim`. */
	.cg-hero--hammer .cg-hero__scrim {
		background: linear-gradient( 122deg, var( --cg-cream ) 34%, var( --cg-cream-0 ) 72% ),
			linear-gradient( 0deg, var( --cg-cream ) 6%, var( --cg-cream-0 ) 42% );
	}
}

/* ------------------------------------------------------------------ *
 * video variant (Home, #65) — full-bleed dark ink band, background
 * video (or gradient fallback) under a legibility scrim, cream text
 * with a rust italic emphasis word, a lede+link "hero-foot" row and a
 * vertical "Scroll" cue. Reference: home.html `.hero`/`.hero-media`/
 * `.hero-scrim`/`.hero-body`/`.hero h1`/`.hero-foot`/`.scroll`.
 * ------------------------------------------------------------------ */

/* The reference's `min-height:clamp(640px,92vh,1010px)` assumes home.html's
   `.hnav` — absolutely positioned OVER the hero — so 92vh reaches the fold.
   This theme's header is a normal in-flow bar (header.css), so the band sits
   `--h-header` lower, and above a ~1098px-tall viewport the 1010px cap stops
   it growing at all: on a 2560x1440 display the video ended 329px short of
   the fold with the stats band showing under it. `max()` keeps the reference
   value wherever it still fills (it wins up to ~1100px of viewport height —
   laptops and 1080p are byte-identical) and takes over only on the taller
   displays the cap was never sized for. */
.cg-hero--video {
	min-height: max( clamp( 640px, 92vh, 1010px ), calc( 100svh - var( --h-header ) ) );
	padding-bottom: clamp( 48px, 7vh, 96px );
	background: #0B0B0A;
	color: var( --cg-cream );
}

.cg-hero--video .cg-hero__media {
	background: radial-gradient( 135% 105% at 72% 6%, var( --cg-hero-video-fallback-1 ) 0%, var( --cg-hero-video-fallback-2 ) 34%, var( --cg-hero-video-fallback-3 ) 66% );
}

.cg-hero--video .cg-hero__media .bg-video {
	width: 100%;
	height: 100%;
}

/* Poster — the first-paint layer. Sits under the player (DOM order) and
   covers the band identically, so the hand-off when the video's first frame
   decodes is invisible. #383 lifted the mobile floor — below 767px the same
   player now autoplays inline instead of the poster replacing it outright —
   see the two media queries below for how the poster stays the Low Power
   Mode / blocked-autoplay fallback once that happens. */
.cg-hero--video .cg-hero__poster {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

@media ( max-width: 767px ) {
	/* Stack the poster ABOVE the player by default. DOM order alone would
	   let the later `.bg-video` win (painting order: z-index:auto siblings
	   paint in DOM order — the player is placed after the poster in
	   blocks/cg/hero.php), which is correct once playing but wrong before
	   it, including when autoplay never starts at all. Unconditional on
	   motion preference: the poster must stay on top under reduced motion
	   too, not just avoid being hidden by the rule below. */
	.cg-hero--video .cg-hero__poster {
		z-index: 1;
	}
}

@media ( max-width: 767px ) {
	/* The reveal — hide the poster once BgVideo confirms real playback
	   (`playingClass`, mirrored onto `.cg-hero__media` in jquery.main.js).
	   DEFAULT is reveal, not gated on `no-preference`, so a UA that does
	   not support the `prefers-reduced-motion` media feature at all fails
	   SAFE: an unsupported feature query evaluates to false in every
	   branch, so gating the reveal on `no-preference` would leave it
	   permanently false there too — the poster would never hide even
	   though (on that same UA) `js/jquery.main.js`'s own `matchMedia` check
	   also reads as "not reduced" and constructs the player, so it plays
	   and downloads in full behind an opaque poster forever. The override
	   below is what actually keeps reduced motion winning.

	   `.video-has-frame` AS WELL AS `.playing` (#384 F2). `.playing` rides the
	   html5 `play` event, which fires when play() is CALLED — readyState 0,
	   no frame decoded — so on its own it drops the poster and reveals the
	   bare gradient for the entire buffer: ~9s on 4G, the full window on slow
	   3G (scripts/visual-qa/probe14.mjs). `.video-has-frame` lands on
	   `loadeddata`, i.e. once a frame actually exists to show. Both are
	   required, so the poster now covers the buffer it was added to cover.
	   Not `video-loaded` — `progress` raises that at readyState 0 too. */
	.cg-hero--video .cg-hero__media.playing.video-has-frame .cg-hero__poster {
		opacity: 0;
	}
}

@media ( max-width: 767px ) and ( prefers-reduced-motion: reduce ) {
	/* The override. `js/jquery.main.js` skips constructing the player at
	   all below 768 when reduced motion is on (#383 FIX 2), so `.playing`
	   should never actually land here — this exists as the CSS-only
	   backstop in case JS's `matchMedia` and this media query ever
	   disagree, so the poster still wins on its own if they do.

	   Carries `.video-has-frame` to match the reveal's specificity exactly
	   (#384 F2); with both equal, source order decides and this rule is
	   later, so the override still wins. Dropping the class here would make
	   this LESS specific than the reveal and silently stop overriding. */
	.cg-hero--video .cg-hero__media.playing.video-has-frame .cg-hero__poster {
		opacity: 1;
	}
}

/* Cover geometry belongs to CSS, not to a JS measure pass.
   `fluidWidth:true` (hero.php) stops BgVideo running resizeVideo(), so it
   writes no inline width/height/margin and adds `.fluid-video` instead —
   style.css then pins the player to inset:0 / 100% x 100%. All that is
   missing there is the fit: a <video> defaults to object-fit:contain, which
   letterboxes inside that box. `cover` completes it, and the result is
   correct at first layout and at every window size, with no resize handler.

   This replaces the previous JS-driven sizing, which was wrong in two ways:
   the player rendered at its 300x150 default until JS measured it (~560ms
   after load), and the oversize width the JS set to crop-to-fill was clipped
   by style.css's `video, iframe, object, embed { max-width:100% }` while its
   compensating negative margin stayed — leaving the player shifted rather
   than oversized, with the fallback gradient showing 16px down the right
   edge at 1440x900, 34px at 1728 and 488px at 820. */
.cg-hero--video .cg-hero__media .bg-video video,
.cg-hero--video .cg-hero__media .bg-video iframe {
	object-fit: cover;
}

.cg-hero--video .cg-hero__scrim {
	background: linear-gradient( 180deg, rgba( 11, 11, 10, 0.55 ) 0%, rgba( 11, 11, 10, 0.12 ) 34%, rgba( 11, 11, 10, 0.66 ) 100% );
}

.cg-hero--video .cg-hero__body {
	padding-right: clamp( 60px, 7vw, 120px );
}

.cg-hero--video .cg-hero__eyebrow {
	color: var( --cg-cream );
	opacity: 0.85;
}

/* #303 addition (not in the issue's line-numbered table, found in-file):
   this variant re-declares font-size/line-height/letter-spacing/weight
   over the base .cg-hero__title rule above, the same pattern the issue
   calls out for --rocket and --hammer. Left unchanged, the Home hero H1
   would keep `font-weight: 400` -- Tungsten Narrow ships no 400 file
   (css/fonts.css has only 600/700), same "no real file" problem the issue
   requires fixing for --rocket's old 300 -- and the tight
   `letter-spacing: -0.02em` (~-2.5px at this size) mushes the condensed
   face's counters the same way the issue describes for the other
   variants' old -2.2px. Retuned on the same rationale: family/weight from
   the base rule are already correct here (not overridden), so only size/
   line-height/letter-spacing/weight needed re-tuning. */
.cg-hero--video .cg-hero__title {
	max-width: none;
	font-size: clamp( 54px, 8.2vw, 132px );
	line-height: 0.98;
	letter-spacing: -0.5px;
	font-weight: 700;
	color: var( --cg-cream );
}

/* #322: upright, not italic — this is the homepage H1 (`<i>The Health &<br>
   Happiness</i> Agency`), the instance the CD reported. This variant rule
   is more specific than the base `.cg-hero__title i`, so it has to repeat
   the fix or it would keep synthesizing the oblique on its own. See the
   base rule for the full rationale. */
.cg-hero--video .cg-hero__title i {
	font-style: normal;
	/* #306: colour dropped -- single-solid-colour headlines. Base title
	   colour is cream (:403), so this run now reads cream like the rest
	   of the title instead of a rust accent. */
	/* The base .cg-hero__title rule's word-spacing fix (#303, devils-
	   advocate 2nd pass) is inherited here -- this variant doesn't
	   override word-spacing, so no separate fix is needed. The
	   "HappinessAgency" defect that fix addressed came from this variant's
	   italic run; the run is upright as of #322, but the word-spacing fix
	   stays — it is what keeps the words apart, independent of slant. */
}

.cg-hero__foot {
	display: flex;
	align-items: flex-end;
	flex-wrap: wrap;
	gap: clamp( 48px, 6vw, 96px );
	margin-top: clamp( 36px, 5vh, 56px );
}

.cg-hero--video .cg-hero__lede {
	max-width: 340px;
	margin: 0;
	font-family: var( --font-body );
	font-weight: 400;
	font-size: 17px;
	line-height: 1.5;
	letter-spacing: 0;
	color: var( --cg-cream );
	opacity: 0.86;
}

.cg-hero__acq {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	min-width: 230px;
	padding-bottom: 16px;
	border-bottom: var( --hairline ) solid rgba( 245, 245, 245, 0.55 );
	font-family: var( --font-sans );
	font-weight: 700;
	font-size: 11px;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var( --cg-cream );
	text-decoration: none;
	transition: border-color var( --fade-out ) var( --fade-ease );
}

.cg-hero__acq:hover {
	border-color: var( --cg-cream );
}

.cg-hero__scroll-cue {
	position: absolute;
	z-index: 2;
	right: clamp( 20px, 4vw, 64px );
	bottom: clamp( 40px, 6vh, 72px );
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 18px;
}

.cg-hero__scroll-line {
	width: var( --hairline );
	height: 56px;
	background: rgba( 245, 245, 245, 0.5 );
}

.cg-hero__scroll-cue span {
	writing-mode: vertical-rl;
	transform: rotate( 180deg );
	font-family: var( --font-sans );
	font-weight: 700;
	font-size: 10px;
	letter-spacing: 0.34em;
	text-transform: uppercase;
	color: var( --cg-cream );
	opacity: 0.75;
}

@media ( max-width: 680px ) {
	.cg-hero__foot {
		gap: 26px;
	}

	.cg-hero__scroll-cue {
		display: none;
	}
}

/* ------------------------------------------------------------------ *
 * astronaut variant (Tech & AI, #124) — two-column "hero-top" row
 * (copy left, design-fixed art inline right, NOT full-bleed/absolute),
 * then a full-bleed hairline + optional 3-up footer strip. Base heading
 * colour is ink. Was ink with a rust `.cg-hero__rustword` run (inverse
 * pattern, same as `hammer`) until #306 (single-solid-colour headlines)
 * dropped the run's colour override -- see the removed-rule comment
 * below. Reference: tech-ai.html `.hero`/`.hero-top`/`.heroimg`/
 * `.herostrip`/`.hs`.
 * ------------------------------------------------------------------ */

.cg-hero--astronaut {
	min-height: 0;
	padding: clamp( 150px, 20vh, 210px ) var( --pad-x ) 0;
}

/* #330: without art these bands are content-driven, like `--astronaut`
 * already was. The base `.cg-hero` min-height of clamp(600px, 64vh, 880px)
 * — and `--hammer`'s 820px / `--rocket`'s 760px variants — existed to give
 * the full-bleed graphic a band to fill. With the graphic gone they would
 * hold open several hundred px of empty cream below the copy.
 *
 * Placed after those three rules on purpose: all four selectors are (0,1,0),
 * so source order decides and this has to come last. Video keeps the base
 * min-height untouched — its band IS the film.
 */
.cg-hero--megaphone,
.cg-hero--hammer,
.cg-hero--rocket {
	min-height: 0;
}

/* #330: the two-column hero row — headline left, sub-copy + links right.
 *
 * Was astronaut-only (text left, astronaut.png right). Now every non-video
 * hero uses it, because the CD's redesign drops the art from all of them and
 * gives the vacated column to the sub-copy. Reusing this grid rather than
 * writing a second one is why the PHP was restructured to match the
 * astronaut variant instead of the other way round.
 *
 * Column ratio 1.35:1 is measured off the Media artboard: the headline
 * column is 858px and the aside 636px within a 1640px content width
 * (858 / 636 = 1.349). The 82px max gap is the artboard's own
 * 1080 - (140 + 858).
 *
 * align-items goes center -> start: the astronaut image was taller than the
 * text and wanted centring, but two text columns must share a top edge or
 * the sub-copy floats away from the headline it belongs to. The
 * `--astronaut .cg-hero__body { align-self: start }` rule below existed to
 * work around exactly that and is now redundant, kept only because it is
 * harmless and its docblock records the 100px eyebrow alignment it fixed.
 */
.cg-hero__top {
	display: grid;
	grid-template-columns: minmax( 0, 1.35fr ) minmax( 0, 1fr );
	align-items: start;
	gap: clamp( 32px, 5vw, 82px );
	padding-bottom: clamp( 48px, 6vw, 88px );
}

/* #330: the right-hand column. The hairline above it is the artboard's rule
   at y=298 — drawn there as a 563px line starting 12px left of the copy,
   which reads as Figma slop rather than intent, so it becomes a clean top
   border on the column itself.

   `.cg-hero__lede`'s own `margin: 34px 0 0` and `max-width: 460px` were for
   stacking under the headline; in a column of its own the margin would push
   it away from the rule and the max-width would fight the grid track, so
   both are reset here rather than changed at source — the video hero still
   stacks its lede and still needs them. */
/* The offset drops the rule below the headline's first line rather than
   levelling it with the eyebrow. On the artboard the eyebrow sits at y=231
   and the rule at y=298 — 67px lower — which is what stops the right column
   reading as a second, competing header. 3.5vw hits 67px at the artboard's
   own 1920 and scales down with the type; the 28px floor keeps a sensible
   gap once the grid collapses to one column at <=1024px, where 3.5vw would
   otherwise shrink to ~14px. */
.cg-hero__aside {
	margin-top: clamp( 28px, 3.5vw, 67px );
	border-top: var( --hairline ) solid var( --cg-border );
	padding-top: 42px;
}

/* #330: three single-column assumptions that break inside the grid, all
 * scoped to `.cg-hero__top` so the video hero keeps them.
 *
 * 1. `.cg-hero__body`'s `margin-top: auto` pushed the copy to the bottom of
 *    a tall art-filled flex band. In a grid row it fights `align-items:
 *    start` and dropped Approach's headline 73px below its own sub-copy.
 * 2. Its `padding-left: clamp(0, 3vw, 56px)` indented the copy away from the
 *    art; with no art it just eats into the headline column.
 * 3. `.cg-hero__title`'s `max-width: min(700px, 44%)` was 44% of a
 *    full-width body (~560px). Inside a 689px column it resolves to ~303px
 *    and wrapped the Media headline into 7 lines 658px tall. The headline
 *    now has a column of its own, so the track is the constraint and the
 *    max-width is not just wrong but actively harmful.
 *
 * The title selector compounds three classes (0,3,0) on purpose: the
 * per-variant `max-width` overrides for --hammer (min(760px,60%)) and
 * --astronaut (16ch) are both (0,2,0), and --astronaut's sits *later* in this
 * file, so matching their specificity would leave Technology squeezed
 * depending on source order. Winning on specificity is order-independent.
 */
.cg-hero__top .cg-hero__body {
	margin-top: 0;
	padding-left: 0;
}

/*
 * #399 — "reduce the right side of the headline text box by 20% of the
 * total width of the headline text box", applied globally.
 *
 * This is the rule that carries it, not the per-variant ones. It is (0,3,0)
 * and deliberately beats --hammer (0,2,0) and --astronaut (0,2,0) — see the
 * docblock above — so on every `__top` hero it is the winning declaration
 * and the only place the reduction can take effect. `--rocket` was the
 * obvious-looking candidate and is the wrong one: all four --rocket pages
 * are `__top` pages, so a value there never applies.
 *
 * A PERCENTAGE, not px. Measured, the box scales with the viewport —
 * 689px at 1440 to 708px at 1920 here, 712px to 924px on the work heroes —
 * so a fixed px would be right at one width and wrong at every other.
 * 80% is "minus 20%" of whatever the column gives it, at any width.
 *
 * There IS a width to take 20% off, which the issue originally doubted: the
 * headline fills its grid column exactly on every affected page (rendered
 * width == parent width across all 20 measurements). The box was expressed
 * by the grid rather than by a max-width.
 */
.cg-hero__top .cg-hero__body .cg-hero__title {
	max-width: 80%;

	/*
	 * Narrowing the box by 20% left two headlines ending on a stranded
	 * word — /media/ at 1920 ("both.", 145px of 566) and /services/ at
	 * 1440 ("good.", 115px of 551). #399's own acceptance criterion
	 * forbids an orphaned last line, so this is part of the fix, not a
	 * flourish. `balance` redistributes the rag WITHOUT changing the line
	 * count (measured: media stays 5 lines, services stays 3; last line
	 * goes 26% -> 70% and 21% -> 67% of the box). Same property already
	 * used on `.cg-quote__text`.
	 */
	text-wrap: balance;
}

/*
 * Released at the point the hero stops being a two-column layout, NOT at
 * the phone breakpoint. `.cg-hero__top` goes `grid-template-columns: 1fr`
 * at max-width:1024px (further down this file), and once the headline has
 * the full row to itself there is no "right side" to reduce: 80% just
 * leaves a ~184px dead gutter while the rule and body copy beside it still
 * run full width. Measured at 1024 the box jumps from 591px (at 1280) to
 * ~891px, so the reduction gets visually louder exactly where it stops
 * making sense.
 *
 * The specificity must match the (0,3,0) rule above. The generic
 * `@media (max-width:680px) .cg-hero__title` release is only (0,1,0) and
 * would lose to it, leaving headlines narrowed on phones — which #399
 * explicitly rules out. That was invisible before #399 only because both
 * resolved to `none`.
 *
 * Side effect worth knowing: this makes the existing
 * `@media (max-width:1024px) { .cg-hero--hammer .cg-hero__title { max-width:
 * none } }` redundant rather than contradicted — both now say `none` from
 * 1024 down. Left in place; it is pre-existing and harmless.
 */
@media ( max-width: 1024px ) {
	.cg-hero__top .cg-hero__body .cg-hero__title {
		max-width: none;
	}
}

.cg-hero__aside .cg-hero__lede {
	max-width: none;
	margin-top: 0;
}

.cg-hero--astronaut .cg-hero__body {
	position: static;
	z-index: auto;
	margin-top: 0;
	padding-left: 0;
	/* #330 phase 2 follow-up: `max-width: 640px` removed. It was the art-era
	   cap that held Technology's copy clear of the inline astronaut.png, and
	   #330 deleted that image — so it survived as a 640px lid on a 708px grid
	   track, leaving 68px of dead space inside the headline column and wrapping
	   this H1 earlier than Media/Services/Approach, which all fill their track.
	   Measured at 1920: body 640px vs track 708px, the only one of the four
	   with a gap. Same category of leftover as the `align-self` note below.
	   NOT a grid bug — the tracks were always correct (708/524, 1.35:1, 82px
	   gap, identical to the other three); the lid was inside the column. */
	/* #202 follow-up: the two-col hero-top is align-items:center, which
	   vertically centres this text column against the taller astronaut image
	   and pushed the eyebrow ~4px below the 100px lockup line. Top-align just
	   the body so the eyebrow sits at exactly 100px like every other hero;
	   the image keeps its centred grid placement. */
	align-self: start;
}

.cg-hero__sideimg {
	justify-self: end;
	width: 100%;
}

.cg-hero__sideimg img {
	display: block;
	width: 100%;
	height: auto;
}

/* #303 addition (not in the issue's line-numbered table, found in-file):
   font-weight/line-height/letter-spacing are NOT overridden here, so this
   variant already inherits the retuned base values above. Its own
   font-size clamp is retuned the same as --hammer/.cg-work-hero__title
   (was clamp(40px,5vw,88px) for Noe Text).

   Investigated and ruled out: at a 390x1400 test viewport this re-wraps
   "Most agencies have an AI slide. We have an AI backbone." from 3 lines
   to 2, and the new second line's closing period lands under the
   sitewide fixed CONTACT tab (gff-contact plugin). This comment
   previously cited the plugin's own default position (`position:fixed;
   right:0; top:25%`) as the live rule -- corrected (adversarial review,
   2nd pass): css/components/contact-flyout.css OVERRIDES that to
   `top:50%; transform: translateY(-50%) rotate(90deg)`, with its own
   documented reason (the plugin's `top:25%` drifted with window width).
   That looked like a real collision until checked against actual device
   heights at 390px width (650/700/750/800/844/900/950/1000 -- the
   realistic range for phones): no overlap at any of them -- the tab
   renders well above the heading in every real case, and the review
   independently re-confirmed this across 6 phone widths x 13 heights.
   1400px tall at 390px wide is a ~3.6:1 aspect ratio no shipping phone
   has; the earlier finding was a test-viewport artifact, not a rendering
   defect, so the floor here matches the other variants. */
/* #328: ink override deleted — Technology's H1 is rust now, inherited from
   the base `.cg-hero__title` rule. Same reasoning as `--hammer` above. */
.cg-hero--astronaut .cg-hero__title {
	max-width: 16ch;
	font-size: clamp( 46px, 5.4vw, 96px );
}

/* .cg-hero--astronaut .cg-hero__title .cg-hero__rustword rule removed (#306,
   single-solid-colour headlines) -- its only declaration was `color: var(
   --accent )`. The `.cg-hero__rustword` span still exists in the markup;
   it now simply inherits the title's own ink colour like the rest of the
   text, same treatment as `.cg-hero__title .ink` above. */

.cg-hero--astronaut .cg-hero__lede {
	max-width: 560px;
	font-weight: 400;
	line-height: 1.7;
	color: var( --cg-ink );
}

.cg-hero--astronaut .cg-hero__links {
	margin-top: 44px;
}

.cg-hero__fbline {
	height: 0;
	border-top: var( --hairline ) solid var( --cg-grey );
	margin-inline: calc( -1 * var( --pad-x ) );
}

.cg-hero__strip {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 0;
}

/*
 * The strip reads as the same system as the `cardbox` cards on /services/
 * ("One connected system. One outcome: velocity."), per the CD's 2026-08-07
 * review: rule mark, serif title, grey body, on the bordered-box inset.
 *
 * Matched by REUSING `.cg-rule` and `.cg-h3` in the markup, so the only
 * things set here are the ones a shared class cannot know — the box inset
 * and this strip's own dividers. The type ramp is not restated; one copy.
 */
.cg-hero__stripitem {
	padding: var( --box-pad ) clamp( 24px, 2.4vw, var( --box-pad ) ) var( --box-pad );
	border-left: var( --hairline ) solid var( --cg-border );
	transition: background-color var( --fade-out ) var( --fade-ease );
}

.cg-hero__stripitem:first-child {
	border-left: 0;
	padding-left: 0;
}

.cg-hero__stripitem:last-child {
	padding-right: 0;
}

.cg-hero__stripitem:hover {
	background-color: var( --box-hover-cream );
}

/*
 * Face, size and leading now come from `.cg-h3` on the element itself (see
 * blocks/cg/hero.php). Only `display` and the colour are set here: `.cg-h3`
 * is authored for headings, which are block-level already, and this is a
 * <span> deliberately — see the markup note on why it is not promoted.
 */
.cg-hero__striplbl {
	display: block;
	color: var( --cg-ink );
}

/* Matched to `.cg-card__text` (css/components/cardbox.css) — same 22px gap
   under the title, same 14px/1.62 body — so the two sections read as one
   system rather than nearly the same. Was 15px/1.66 with no top margin,
   which is the kind of near-miss that looks like a mistake next to the real
   thing. `/technology/` is the only page carrying `strip_items` (verified,
   2026-08-07), so this restyle reaches exactly the section under review. */
.cg-hero__stripitem p {
	margin: 22px 0 0;
	font-family: var( --font-body );
	font-size: 14px;
	line-height: 1.62;
	color: var( --cg-muted );
}

@media ( max-width: 1024px ) {
	.cg-hero__top {
		grid-template-columns: 1fr;
		gap: 44px;
	}

	.cg-hero__sideimg {
		justify-self: center;
		max-width: 400px;
		order: -1;
	}

	.cg-hero__strip {
		grid-template-columns: 1fr;
	}

	/* 10px bottom, not 0 (#483). Stacked, the item's own bottom edge is
	   where the NEXT item's border-top paints, and the last <p> carries
	   margin-bottom:0 — so a zero bottom padding put the copy directly on
	   the divider (measured on Dev at 390px: paragraph bottom == item
	   bottom, 0px gap). 10px is the Creative Director's own number
	   (#480, 2026-09-03). `.cg-worklist-slider__tc` had the identical
	   `32px 0 0` and is fixed in the same change — same defect, and the CD
	   reported both. */
	.cg-hero__stripitem {
		border-left: 0;
		border-top: var( --hairline ) solid var( --cg-border );
		padding: 32px 0 10px;
	}

	.cg-hero__stripitem:first-child {
		border-top: 0;
	}
}

@media ( max-width: 680px ) {
	.cg-hero--astronaut .cg-hero__title {
		max-width: none;
	}
}
