/**
 * GENE Motion — Scroll Hero (front + base).
 *
 * States:
 *   1. Base (no JS / reduced motion / hostile theme) → a clean full-screen hero:
 *      background + heading(s), everything visible. never-break.
 *   2. `.gene-hero--live` → pinned; a video background scrubs with scroll.
 *   3. `.gene-hero--story` (Pro, 2+ headings) → the headings show one at a time.
 */

.gene-hero {
	position: relative;
}
.gene-hero__pin {
	position: relative;
}

/* ---- Background (image or muted video) --------------------------------- */
.gene-hero__bg {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	border-radius: inherit;

	img,
	video {
		display: block;
		width: 100%;
		height: 100%;
		object-fit: cover;
	}
}
.gene-hero__scrim {
	position: absolute;
	inset: 0;
	background: rgba( 6, 8, 12, var( --dim, 0.1 ) );
}

/* Over a background, default the type to white — but only until the user
   picks a text color. `:not(.has-text-color)` lets the block's color support
   win with either a custom hex (inline) or a theme palette color (a
   .has-*-color class, which would otherwise lose to this selector). */
.gene-hero[ data-has-bg='1' ]:not( .has-text-color ) {
	color: #fff;
}

/* Front-end hero framing: full-viewport, heading centred. (Editor keeps its
   natural height — see editor.scss.) */
.gene-hero[ data-has-bg='1' ]:not( .gene-hero--editor ) .gene-hero__pin {
	box-sizing: border-box;
	min-height: 100vh;
	min-height: 100dvh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: clamp( 2rem, 6vh, 5rem ) clamp( 1.25rem, 6vw, 6rem );
}

.gene-hero__beats {
	position: relative;
	width: min( 900px, 82vw );
	text-align: center;
	display: flex;
	flex-direction: column;
	gap: clamp( 2rem, 6vh, 4rem );
}

.gene-hero__eyebrow {
	margin: 0 0 1rem;
	font-size: calc( 0.72rem * var( --gene-hero-beat-scale, 1 ) );
	letter-spacing: 0.28em;
	text-transform: uppercase;
	font-weight: 600;
	opacity: 0.72;
}
.gene-hero__head {
	margin: 0;
	/* Per-beat size scale (timeline free placement sets --gene-hero-beat-scale
	   inline on the beat). Default 1 → identical size everywhere else. */
	font-size: calc( clamp( 2.2rem, 6vw, 5rem ) * var( --gene-hero-beat-scale, 1 ) );
	line-height: 0.98;
	font-weight: 800;
	letter-spacing: -0.02em;
	/* No forced case: the heading shows exactly what the author typed, so what
	   you write on the canvas is what ships. */
	text-wrap: balance;
	overflow-wrap: break-word;
	/* Author-picked heading color (free tier). Unset → inherit, as before. */
	color: var( --gene-hero-head-c, inherit );
}
.gene-hero__sub {
	/* auto/auto = centered (default). A timeline beat can set --gene-hero-sub-ml
	   / -mr to 0 inline to left/right-align its sub block. */
	margin: 1.1rem var( --gene-hero-sub-mr, auto ) 0 var( --gene-hero-sub-ml, auto );
	font-size: calc( clamp( 0.95rem, 1.5vw, 1.2rem ) * var( --gene-hero-beat-scale, 1 ) );
	line-height: 1.6;
	opacity: 0.85;
	max-width: 52ch;
	overflow-wrap: break-word;
}
.gene-hero__hint {
	margin: 0;
	opacity: 0.7;
}

/* ---- CTA buttons under a heading -------------------------------------- */
/* Rendered inside a beat, after the sub-line. Clickable only where the heading
   is actually shown — the pointer-events gating below (per mode) makes hidden
   headings' buttons inert so they never catch a stray click. */
.gene-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin-top: clamp( 1.2rem, 3vh, 2rem );
}
.gene-hero[ data-pos='center' ] .gene-hero__actions {
	justify-content: center;
}
.gene-hero__btn {
	display: inline-block;
	padding: 0.72em 1.6em;
	border-radius: 999px;
	font-size: clamp( 0.9rem, 1.1vw, 1.02rem );
	font-weight: 600;
	line-height: 1.1;
	letter-spacing: 0.01em;
	text-decoration: none;
	transition: transform 0.15s ease, opacity 0.15s ease;
}
.gene-hero__btn:hover {
	transform: translateY( -1px );
}
/* Author-picked button colors (free tier). Unset → the defaults below, as
   before. A solid button takes the button color as its fill; an outline
   (ghost) button takes it as its border + label. */
.gene-hero__btn--solid {
	background: var( --gene-hero-btn-bg, #fff );
	color: var( --gene-hero-btn-c, #0b0d12 );
}
.gene-hero__btn--ghost {
	border: 1px solid var( --gene-hero-btn-bg, currentColor );
	color: var( --gene-hero-btn-bg, inherit );
}

/* ---- Font preset (Pro) -------------------------------------------------- */
/* System font stacks only — nothing loads from outside (the plugin's rule).
   Unset (default) → the theme's own font, exactly as before. JP fallbacks
   included so 明朝/ゴシック read correctly on Japanese sites. */
.gene-hero[ data-font='sans' ] {
	font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
		'Hiragino Kaku Gothic ProN', 'Yu Gothic', 'Helvetica Neue', Arial, sans-serif;
}
.gene-hero[ data-font='serif' ] {
	font-family: Georgia, 'Iowan Old Style', 'Hiragino Mincho ProN', 'Yu Mincho',
		'Times New Roman', serif;
}
.gene-hero[ data-font='mono' ] {
	font-family: ui-monospace, 'Cascadia Code', Consolas, Menlo, 'Courier New', monospace;
}

/* ---- Button shape (Pro) ------------------------------------------------- */
/* Default is the pill (999px above); only the non-defaults are ever saved. */
.gene-hero[ data-btn-shape='rounded' ] .gene-hero__btn {
	border-radius: 10px;
}
.gene-hero[ data-btn-shape='square' ] .gene-hero__btn {
	border-radius: 0;
}

/* ---- Live: pinned; video scrubs -------------------------------------- */
.gene-hero--live {
	height: calc( var( --screens, 4 ) * 100vh );
}
.gene-hero--live .gene-hero__pin {
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100dvh;
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: clamp( 2rem, 6vh, 5rem ) clamp( 1.25rem, 6vw, 6rem );
}

/* ---- Story (Pro): 2+ headings, one at a time ------------------------- */
.gene-hero--story .gene-hero__beats {
	min-height: 46vh;
	display: block;
}
.gene-hero--story .gene-hero__beat {
	position: absolute;
	left: 0;
	right: 0;
	top: 50%;
	opacity: 0;
	transform: translateY( calc( -50% + 30px ) );
	transition: opacity 0.5s ease, transform 0.55s cubic-bezier( 0.2, 0.8, 0.2, 1 );
	pointer-events: none; /* only the shown heading's buttons are clickable */
}
.gene-hero--story .gene-hero__beat.is-on {
	opacity: 1;
	transform: translateY( -50% );
	pointer-events: auto;
}
.gene-hero--story .gene-hero__beat.is-past {
	opacity: 0;
	transform: translateY( calc( -50% - 30px ) );
}

@media ( prefers-reduced-motion: reduce ) {
	.gene-hero--story .gene-hero__beat {
		transition: none;
	}
}

/* ---- Headline placement: bottom-left (default) ----------------------- */
/* The heading column is anchored bottom-left over the background instead of
   centred. Front only — the editor keeps its calm centred preview. Pro can
   switch back to centred by saving data-pos="center". */
.gene-hero[ data-pos='bottom-left' ]:not( .gene-hero--editor ) .gene-hero__pin {
	align-items: flex-end;
	justify-content: flex-start;
}
.gene-hero[ data-pos='bottom-left' ] .gene-hero__beats {
	width: min( 620px, 90vw );
	text-align: left;
}
/* Front only: reserve the same column height whether there's one heading
   (free) or a story (Pro), so the headline sits at the same level either way.
   (The editor keeps its short, calm preview.) */
.gene-hero[ data-pos='bottom-left' ]:not( .gene-hero--editor ) .gene-hero__beats {
	min-height: 46vh;
	justify-content: center;
}
.gene-hero[ data-pos='bottom-left' ] .gene-hero__sub {
	margin-left: 0;
	margin-right: auto;
}

/* ---- Free-placement timeline (Pro) ------------------------------------ */
/* When engaged, the headings are absolutely placed over the pinned hero at a
   center-anchored (x%, y%); view.js drives each one's transform/opacity/clip by
   scroll position. Off / no-JS / reduced-motion / broken pin → the classic
   stacked hero above shows instead (never-break). */
.gene-hero--live.gene-hero--timeline .gene-hero__beats {
	position: absolute;
	inset: 0;
	width: auto;
	min-height: 0;
	display: block;
}
.gene-hero--live.gene-hero--timeline .gene-hero__beat {
	position: absolute;
	margin: 0;
	width: min( 560px, 84vw );
	text-align: center;
	/* Center anchor: JS composes the animation offset after this. Kept here so
	   the beat is centered on its point even before the first rAF tick. */
	transform: translate( -50%, -50% );
	/* Driven from 0 on the first tick; avoids a flash of all headings at once. */
	opacity: 0;
	will-change: transform, opacity;
	pointer-events: none; /* view.js re-enables a beat's buttons once it's fully shown */
}
.gene-hero--live.gene-hero--timeline .gene-hero__sub {
	/* Vars let a beat left/right-align its sub inline (default centered). */
	margin-left: var( --gene-hero-sub-ml, auto );
	margin-right: var( --gene-hero-sub-mr, auto );
}
/* Free placement can land on a bright frame — give the type a soft backing so
   it stays readable anywhere without dimming the whole video. */
.gene-hero--timeline .gene-hero__eyebrow,
.gene-hero--timeline .gene-hero__head,
.gene-hero--timeline .gene-hero__sub {
	text-shadow: 0 1px 20px rgba( 0, 0, 0, 0.45 ), 0 1px 3px rgba( 0, 0, 0, 0.5 );
}

/* ---- Multi-scene (chapters, Pro) -------------------------------------- */
/* A sequence of chapters stacked in the pin. view.js drives each scene's
   opacity so one hands off to the next as you scroll. Base / no-JS /
   reduced-motion / broken pin / touch → only the first chapter shows: a clean
   looping hero (never-break). Later chapters ship with data-src and never load
   until reached. */
.gene-hero--multi:not( .has-text-color ) {
	color: #fff;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__pin {
	box-sizing: border-box;
	min-height: 100vh;
	min-height: 100dvh;
}
.gene-hero--multi .gene-hero__scene {
	position: absolute;
	inset: 0;
	pointer-events: none;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: clamp( 2rem, 6vh, 5rem ) clamp( 1.25rem, 6vw, 6rem );
}
.gene-hero--multi .gene-hero__scene .gene-hero__beats {
	position: relative;
	width: min( 900px, 82vw );
	text-align: center;
	min-height: 0;
}
/* Base: show only the first chapter. Live: JS sets opacity inline (wins). */
.gene-hero--multi:not( .gene-hero--multi-live ) .gene-hero__scene {
	opacity: 0;
}
.gene-hero--multi:not( .gene-hero--multi-live ) .gene-hero__scene[ data-i='0' ] {
	opacity: 1;
}
.gene-hero--multi.gene-hero--live {
	height: calc( var( --screens, 4 ) * var( --scenes, 1 ) * 100vh );
}
/* Give the type a soft backing (chapters can land on a bright frame). */
.gene-hero--multi .gene-hero__eyebrow,
.gene-hero--multi .gene-hero__head,
.gene-hero--multi .gene-hero__sub {
	text-shadow: 0 1px 20px rgba( 0, 0, 0, 0.45 ), 0 1px 3px rgba( 0, 0, 0, 0.5 );
}
.gene-hero--multi[ data-pos='bottom-left' ]:not( .gene-hero--editor ) .gene-hero__scene {
	align-items: flex-end;
	justify-content: flex-start;
}
.gene-hero--multi[ data-pos='bottom-left' ] .gene-hero__scene .gene-hero__beats {
	width: min( 620px, 90vw );
	text-align: left;
}

/* ---- Per-chapter headline placement (Pro) ------------------------------ */
/* A scene's own data-pos overrides the hero's placement for that chapter
   only (unset → the root's data-pos applies, exactly as before). Kept after
   the root rules above so, at equal specificity, the scene's choice wins.
   Front only — the editor keeps its calm centred preview. */
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='bottom-left' ] {
	align-items: flex-end;
	justify-content: flex-start;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='bottom-left' ] .gene-hero__beats {
	width: min( 620px, 90vw );
	text-align: left;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='center' ] {
	align-items: center;
	justify-content: center;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='center' ] .gene-hero__beats {
	width: min( 900px, 82vw );
	text-align: center;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='bottom-right' ] {
	align-items: flex-end;
	justify-content: flex-end;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='bottom-right' ] .gene-hero__beats {
	width: min( 620px, 90vw );
	text-align: right;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='bottom-right' ] .gene-hero__sub {
	margin-left: auto;
	margin-right: 0;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='bottom-right' ] .gene-hero__actions {
	justify-content: flex-end;
}
.gene-hero--multi:not( .gene-hero--editor ) .gene-hero__scene[ data-pos='center' ] .gene-hero__actions {
	justify-content: center;
}
/* A chapter with more than one heading swaps them one at a time as it scrubs
   (like the single hero's story mode). Only when the sequence is engaged
   (`--multi-live`): base / no-JS / reduced-motion keep the headings stacked and
   readable (never-break). */
.gene-hero--multi-live .gene-hero__beats--story {
	position: relative;
	min-height: 46vh;
}
.gene-hero--multi-live .gene-hero__beats--story .gene-hero__beat {
	position: absolute;
	left: 0;
	right: 0;
	top: 50%;
	opacity: 0;
	transform: translateY( calc( -50% + 30px ) );
	transition: opacity 0.5s ease, transform 0.55s cubic-bezier( 0.2, 0.8, 0.2, 1 );
	pointer-events: none;
}
.gene-hero--multi-live .gene-hero__beats--story .gene-hero__beat.is-on {
	opacity: 1;
	transform: translateY( -50% );
	pointer-events: auto;
}
.gene-hero--multi-live .gene-hero__beats--story .gene-hero__beat.is-past {
	opacity: 0;
	transform: translateY( calc( -50% - 30px ) );
}
@media ( prefers-reduced-motion: reduce ) {
	.gene-hero--multi-live .gene-hero__beats--story .gene-hero__beat {
		transition: none;
	}
}

/* ---- Free placement inside chapters (Pro) ------------------------------ */
/* The single hero's timeline, per chapter: when the sequence is engaged AND
   free placement is on, each chapter's headings are absolutely pinned at their
   center-anchored (x%, y%) and view.js drives them by that chapter's scroll.
   Base / no-JS / reduced-motion / broken pin → the stacked chapter-1 headings
   above stay readable (never-break). The [data-timeline] hook lifts these past
   the per-chapter data-pos rules (which free placement replaces). */
.gene-hero--multi-live.gene-hero--timeline[ data-timeline='1' ] .gene-hero__scene .gene-hero__beats {
	position: absolute;
	inset: 0;
	width: auto;
	text-align: center;
	min-height: 0;
}
.gene-hero--multi-live.gene-hero--timeline[ data-timeline='1' ] .gene-hero__scene .gene-hero__beat {
	position: absolute;
	margin: 0;
	width: min( 560px, 84vw );
	text-align: center;
	/* Center anchor: JS composes the animation offset after this. */
	transform: translate( -50%, -50% );
	/* Driven from 0 on the first tick; avoids a flash of all headings at once. */
	opacity: 0;
	will-change: transform, opacity;
	pointer-events: none; /* view.js re-enables a beat's buttons once fully shown */
}
.gene-hero--multi-live.gene-hero--timeline[ data-timeline='1' ] .gene-hero__scene .gene-hero__sub {
	margin-left: var( --gene-hero-sub-ml, auto );
	margin-right: var( --gene-hero-sub-mr, auto );
}
.gene-hero--multi-live.gene-hero--timeline[ data-timeline='1' ] .gene-hero__scene .gene-hero__actions {
	justify-content: var( --gene-hero-actions-justify, center );
}

/* Timeline buttons sit on their placed point, following the beat's alignment
   (default centered — the single hero was missing the centering the chapters
   already had; the beat sets --gene-hero-actions-justify inline for left/right). */
.gene-hero--live.gene-hero--timeline .gene-hero__actions {
	justify-content: var( --gene-hero-actions-justify, center );
}
/* A button item is just its pill(s): the frame hugs the content, so the
   placed point is the button itself. */
.gene-hero--live.gene-hero--timeline .gene-hero__beat--btn,
.gene-hero--multi-live.gene-hero--timeline[ data-timeline='1' ] .gene-hero__scene .gene-hero__beat--btn {
	width: max-content;
	max-width: 84vw;
}
.gene-hero__beat--btn .gene-hero__actions {
	margin-top: 0;
}

/* ---- End-of-scroll shatter -------------------------------------------- */
/* view.js builds `.gene-hero__shatter` inside the background from the frozen
   last frame and flies the shards apart with the scroll. Built only when the
   frame captures; JS-off / capture-fail leaves the plain video (never-break). */
.gene-hero__shatter {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	/* Depth for the glass burst: shards fly toward / away from the camera. */
	perspective: 1100px;
	/* Hidden until the hero is actually shattering; otherwise the live
	   (scrubbing) video shows and a scroll-back never leaves stale shards. */
	opacity: 0;
}
.gene-hero__bg.is-shattering .gene-hero__shatter {
	opacity: 1;
}
.gene-hero__shard {
	/* Each shard is sized to its own piece (left/top/width/height + aligned
	   background set inline by view.js) and paints from the ONE captured frame
	   held in --gene-shatter-img on the layer — phone-safe: total layer area is
	   ~one frame however many pieces there are, and the base64 frame exists
	   once instead of once per shard. */
	position: absolute;
	background-image: var( --gene-shatter-img );
	background-repeat: no-repeat;
	will-change: transform, opacity;
	backface-visibility: hidden;
}
/* While shattering, hide the live video + scrim so the shards (and the hero
   background/heading beneath) are what shows. */
.gene-hero__bg.is-shattering > img,
.gene-hero__bg.is-shattering > video,
.gene-hero__bg.is-shattering > .gene-hero__scrim {
	opacity: 0;
}
