/*
 * The Crypto Secret — the home hero (Story 2.1).
 *
 * SOURCE OF TRUTH. design/canvas/Main.dc.html:115-207 for desktop and
 * design/canvas/HomeMobile.dc.html:38-88 for mobile. Where the two disagree,
 * they are not in conflict: mobile is a DESIGNED STATE, not a reflow of the
 * desktop board. It has its own smaller motion vocabulary — the dial and its
 * three placed coins are replaced by two drifting coins, and the scroll cue
 * and the floating chips do not appear at all.
 *
 * THE STAGE (section 4) DEPARTS FROM THE ARTBOARD ON PURPOSE. Main.dc.html's
 * orbit stage was retired on 2026-09-03 after review; the reasoning and the
 * new values are recorded in the stage block of tokens.css.
 *
 * THE ONE THING THIS FILE MUST NOT GET WRONG: THE PRICE PAINTS WITH THE
 * DOCUMENT. Nothing above the fold sits inside a reveal, depends on
 * JavaScript, or starts at opacity 0. That is not a preference — hiding the
 * price until checkout is the single biggest conversion defect on the site
 * this rebuild replaces, and every rule below was written so that no
 * combination of a blocked script, a slow font and a 667px-tall phone can
 * reintroduce it. The reveal in front-page.php covers the headline and the
 * subheadline and stops there.
 *
 * CONSUMES, DOES NOT RE-AUTHOR. The bands come from sections.css; the reveal,
 * the button, the shimmer and the card hover come from motion.css; every value
 * below is a --tcs-* token from tokens.css. There is no literal colour, no
 * literal duration and no literal easing in this file. The nine hero motion
 * values that had no name were added to tokens.css first — see the Story 2.1
 * block there.
 *
 * HARD LIMIT, inherited: only opacity and transform animate. Never width,
 * height, top or left. Every animation has a prefers-reduced-motion state that
 * resolves to its FINAL value, never to invisible and never to zero height —
 * section 8 at the foot of this file.
 */

/* ===========================================================================
 * 1. THE HERO BAND
 *
 * Main.dc.html:115 — `padding: 54px 40px 46px` on a cream ground. The band
 * comes from sections.css; only the padding deviates, and it deviates in both
 * directions, so neither --tight nor --short fits and the hero states its own.
 *
 * `overflow: hidden` is load-bearing, not tidiness: the two aurora blobs are
 * positioned outside the band on three sides (top:-210px, bottom:-300px,
 * left:-160px) and would otherwise scroll the whole document sideways. The
 * I/O matrix forbids exactly that — body.scrollWidth <= innerWidth at 390,
 * 768 and 1440 — so the hero clips its own decoration rather than relying on
 * .tcs-bands upstream to do it.
 * ========================================================================= */

.tcs-hero {
	position: relative;
	overflow: hidden;
	padding-top: 54px;    /* Main.dc.html:115 */
	padding-bottom: 46px; /* Main.dc.html:115 */
	/*
	 * A stacking context of its own. The chips sit at z-index 3 and the book
	 * at 2 INSIDE the hero; without a context here those numbers would
	 * compete with the header's z-index 6 (chrome.css) and a chip could paint
	 * over the nav.
	 */
	isolation: isolate;
}

/*
 * The two-column grid. 1.04fr / .96fr with a 36px gutter (Main.dc.html:131) —
 * the copy column is deliberately the wider of the two so the 72px headline
 * breaks where the artboard breaks it.
 */
.tcs-hero__grid {
	position: relative;
	display: grid;
	grid-template-columns: 1.04fr .96fr;
	gap: 36px;
	align-items: center;
}

.tcs-hero__copy {
	display: flex;
	flex-direction: column;
	gap: 24px; /* Main.dc.html:132 */
	/*
	 * min-width: 0 on a grid item whose content includes a 72px headline with
	 * negative tracking. Without it the column's automatic minimum size is
	 * its longest unbreakable word, which pushes the grid wider than the
	 * band and reintroduces the horizontal scroll the matrix forbids.
	 */
	min-width: 0;
}

/* ===========================================================================
 * 2. DECORATIVE LAYERS  —  Main.dc.html:116-129
 *
 * Four layers, all pointer-events: none, all aria-hidden in markup, none of
 * them ever a hit target and none of them ever containing text. They exist
 * behind the content and are the reason section 1 clips.
 * ========================================================================= */

.tcs-hero__decor {
	position: absolute;
	inset: 0;
	pointer-events: none;
	/*
	 * Behind everything the reader acts on. The grid above establishes no
	 * z-index of its own, so it wins by being later in the document — but
	 * saying so explicitly is what stops a future `position: relative` on a
	 * child from quietly reordering the two.
	 */
	z-index: 0;
}

/* --- 2a. The two aurora blobs (Main.dc.html:117-118) --------------------- */

.tcs-hero__blob {
	position: absolute;
	border-radius: var(--tcs-radius-full);
	pointer-events: none;
}

/*
 * Blob 1 — 700px, top-right, blur 30px, 24s. The gradient is written from
 * --tcs-orange rather than a literal rgba() so the accent stays a single
 * decision; color-mix keeps the alpha stops without hardcoding 247,147,26.
 */
.tcs-hero__blob--1 {
	top: -210px;
	right: 90px;
	width: 700px;
	height: 700px;
	background: radial-gradient(
		circle,
		color-mix(in srgb, var(--tcs-orange) 46%, transparent) 0%,
		color-mix(in srgb, var(--tcs-orange) 0%, transparent) 66%
	);
	filter: blur(var(--tcs-blob-blur));
	animation: tcs-blob var(--tcs-dur-blob-1) ease-in-out infinite;
}

/*
 * Blob 2 — 600px, bottom-left, blur 36px, 30s. The 36px is why
 * --tcs-blob-blur-2 exists: the shipped --tcs-blob-blur is 30px and cannot
 * express both, and rendering this one at 30px "because it is close" is a
 * visible difference from the artboard at the scale this blob is drawn.
 */
.tcs-hero__blob--2 {
	bottom: -300px;
	left: -160px;
	width: 600px;
	height: 600px;
	background: radial-gradient(
		circle,
		color-mix(in srgb, var(--tcs-orange) 24%, transparent) 0%,
		color-mix(in srgb, var(--tcs-orange) 0%, transparent) 68%
	);
	filter: blur(var(--tcs-blob-blur-2));
	animation: tcs-blob-2 var(--tcs-dur-blob-2) ease-in-out infinite;
}

/* _head.html:19-20. Translate and scale only — no width, no height. */
@keyframes tcs-blob {

	0%,
	100% {
		transform: translate(0, 0) scale(1);
	}

	33% {
		transform: translate(70px, -46px) scale(1.18);
	}

	66% {
		transform: translate(-46px, 34px) scale(.9);
	}
}

@keyframes tcs-blob-2 {

	0%,
	100% {
		transform: translate(0, 0) scale(1);
	}

	50% {
		transform: translate(-80px, 56px) scale(1.22);
	}
}

/* --- 2b. The graph-paper grid (Main.dc.html:119) ------------------------- */

/*
 * A 54px lattice masked to an ellipse so it fades out before the band edges.
 * Static — it never animates. The mask is duplicated with the -webkit- prefix
 * because Safari still requires it and an unprefixed-only mask renders the
 * lattice edge-to-edge there, which reads as a rendering bug rather than as
 * texture.
 */
.tcs-hero__grid-paper {
	position: absolute;
	inset: 0;
	background-image:
		linear-gradient(color-mix(in srgb, var(--tcs-black) 5%, transparent) 1px, transparent 1px),
		linear-gradient(90deg, color-mix(in srgb, var(--tcs-black) 5%, transparent) 1px, transparent 1px);
	background-size: 54px 54px;
	-webkit-mask-image: radial-gradient(ellipse 78% 68% at 52% 42%, #000, transparent);
	mask-image: radial-gradient(ellipse 78% 68% at 52% 42%, #000, transparent);
	pointer-events: none;
}

/* --- 2c. The eight twinkling dots (Main.dc.html:121-128) ----------------- */

.tcs-hero__twinkle {
	position: absolute;
	border-radius: var(--tcs-radius-full);
	animation: tcs-twinkle var(--tcs-dur-twinkle) ease-in-out infinite;
	/*
	 * The per-dot position, size, colour and delay are the eight literal
	 * values the artboard draws and are set inline in front-page.php — they
	 * are content-position data, not a design decision this file can name
	 * eight times without becoming a list of one-offs.
	 */
}

/* _head.html:27. Opacity floor is .12, never 0. */
@keyframes tcs-twinkle {

	0%,
	100% {
		opacity: var(--tcs-twinkle-opacity-from);
		transform: scale(var(--tcs-twinkle-scale-from));
	}

	50% {
		opacity: var(--tcs-twinkle-opacity-to);
		transform: scale(1);
	}
}

/* ===========================================================================
 * 3. THE COPY COLUMN
 * ========================================================================= */

/* --- 3a. The social-proof pill (Main.dc.html:133-136) -------------------- */

/*
 * The two figures inside it are LITERAL MARKUP — `1,200+` and `1,300+`, the
 * under-claimed forms of 1,248 orders and 1,303 reviews, both evidenced in
 * verified-claims.md. No script in this theme reads or writes them. A counter
 * that can display 0 is a named defect on the old site and is not something
 * this codebase can express.
 */
.tcs-hero__proof {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	align-self: flex-start;
	padding: 7px 15px;
	border: var(--tcs-border-width) solid color-mix(in srgb, var(--tcs-black) 10%, transparent);
	border-radius: var(--tcs-radius-full);
	background: color-mix(in srgb, var(--tcs-white) 60%, transparent);
	backdrop-filter: blur(6px);
	font-size: 12.5px; /* Main.dc.html:135 */
	font-weight: var(--tcs-fw-semibold);
	letter-spacing: .03em;
	color: var(--tcs-black);
}

.tcs-hero__proof-dot {
	flex: 0 0 auto;
	width: 6px;
	height: 6px;
	border-radius: var(--tcs-radius-full);
	background: var(--tcs-orange);
	animation: tcs-pulse var(--tcs-dur-pulse) ease-in-out infinite;
}

/* _head.html:36. Opacity only — the dot never moves. */
@keyframes tcs-pulse {

	0%,
	100% {
		opacity: var(--tcs-pulse-opacity-from);
	}

	50% {
		opacity: 1;
	}
}

/* --- 3b. The headline (Main.dc.html:138-142) ----------------------------- */

/*
 * The page's ONLY <h1>. Its three lines are <span>s inside it, not three
 * headings — three <h1>s would be three document outlines, and three <div>s
 * inside an <h1> would be invalid. Each span is a block so the lines break
 * where the artboard breaks them rather than where the measure happens to
 * run out.
 */
.tcs-hero__headline {
	margin: 0;
	font-size: var(--tcs-fs-hero);
	line-height: var(--tcs-lh-hero);
	letter-spacing: var(--tcs-ls-hero);
	font-weight: var(--tcs-fw-semibold);
	color: var(--tcs-black);
	text-wrap: pretty;
}

.tcs-hero__line {
	display: block;
}

/*
 * The third line carries the hand-drawn underline, which is absolutely
 * positioned against it.
 */
.tcs-hero__line--underlined {
	position: relative;
}

.tcs-hero__underline {
	position: absolute;
	left: 0;
	bottom: -8px; /* Main.dc.html:141 */
	/*
	 * The SVG is 440 wide against a headline line that is narrower at some
	 * widths. It must never be a hit target and must never widen the line
	 * box, or it becomes the thing that overflows the grid.
	 */
	pointer-events: none;
	max-width: 100%;
}

/*
 * The stroke draws itself once — _head.html:58, `.drw`. 1200 is the shipped
 * --tcs-svg-dash; `forwards` holds the drawn state so it never snaps back to
 * an undrawn line.
 *
 * stroke-dashoffset is neither opacity nor transform, and it is the ONE
 * documented exception this file takes: tokens.md's motion contract names
 * "SVG draw: stroke-dashoffset 1200 -> 0, 3.4s" as a primitive of the system,
 * and it composites on the paint thread without triggering layout — which is
 * the property the hard limit is actually protecting.
 */
.tcs-hero__underline-path {
	stroke-dasharray: var(--tcs-svg-dash);
	animation: tcs-draw var(--tcs-dur-svg-draw) var(--tcs-ease-draw) forwards;
}

@keyframes tcs-draw {

	from {
		stroke-dashoffset: var(--tcs-svg-dash);
	}

	to {
		stroke-dashoffset: 0;
	}
}

/* --- 3c. The subheadline (Main.dc.html:144) ------------------------------ */

.tcs-hero__sub {
	margin: 0;
	max-width: 470px; /* Main.dc.html:144 */
	font-size: 18px;
	line-height: 1.62;
	color: var(--tcs-body);
}

/* --- 3d. The actions (Main.dc.html:146-149) ------------------------------ */

.tcs-hero__actions {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 14px;
	margin-top: 2px;
}

/*
 * The primary CTA carries the price in its own label — "Get the book —
 * $29.99". It is a real <a> with a real href, at least 44px tall from
 * .tcs-btn's min-height, and it is NEVER a reveal target: front-page.php puts
 * the reveal on the headline and the subheadline only, and this button is not
 * one of them.
 */
.tcs-hero__cta {
	padding: 16px 30px; /* Main.dc.html:147 */
	border-radius: var(--tcs-radius);
	font-size: var(--tcs-fs-body-sm);
}

/* The secondary action — outlined on the cream ground (Main.dc.html:148). */
.tcs-hero__cta-secondary {
	padding: 15px 24px;
	border: var(--tcs-border-width) solid color-mix(in srgb, var(--tcs-black) 20%, transparent);
	border-radius: var(--tcs-radius);
	background: color-mix(in srgb, var(--tcs-white) 55%, transparent);
	color: var(--tcs-black);
	font-size: var(--tcs-fs-body-sm);
	font-weight: var(--tcs-fw-medium);
}

.tcs-hero__cta-secondary:hover {
	background: var(--tcs-white);
	color: var(--tcs-black);
}

/* --- 3e. The three assurances (Main.dc.html:151-155) --------------------- */

.tcs-hero__assurances {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 22px;
	margin-top: 6px;
	padding-top: 6px;
	border-top: var(--tcs-border-width) solid color-mix(in srgb, var(--tcs-black) 10%, transparent);
}

.tcs-hero__assurance {
	display: flex;
	align-items: center;
	gap: 8px;
	padding-top: 12px;
	font-size: 13.5px;
	color: var(--tcs-body);
}

.tcs-hero__assurance svg {
	flex: 0 0 auto;
}

/*
 * The refund assurance is a LINK, so it needs the 44px floor that the
 * plain-text assurances beside it do not. The rule is scoped to the link
 * rather than applied to every assurance, because giving a non-interactive
 * <span> a 44px height would only add whitespace to the row.
 */
.tcs-hero__refund-link {
	display: inline-flex;
	align-items: center;
	min-height: var(--tcs-tap-min);
	color: var(--tcs-amber);
	font-weight: var(--tcs-fw-semibold);
	text-decoration: underline;
}

/*
 * The 44px link inside a row whose siblings are ~20px tall would stretch the
 * whole assurance row. Pulling the extra height out of the flow with negative
 * block margins keeps the TAP TARGET at 44px — which is what the constraint
 * is about — without the row growing to match.
 *
 * DERIVED FROM TOKENS, not a hand-tuned -12px (code-review fix, 2026-09-04):
 * pricing.css:231-235 solves the identical problem (a 44px link in a row of
 * shorter siblings) with this exact formula rather than a literal, and this
 * rule now matches it rather than restating the same shape as a magic number.
 */
.tcs-hero__assurance--link {
	margin-block: calc((var(--tcs-tap-min) - 1em * var(--tcs-lh-body)) / -2);
}

/*
 * The mobile assurance row is desktop's three assurances collapsed into one.
 * Both are in the served HTML at every width — the refund window must be
 * present for a crawler and for a reader with JavaScript off, whichever width
 * they arrive at — and exactly one of them is ever displayed.
 */
.tcs-hero__mobile-assurance {
	display: none;
	margin: 0;
}

/* ===========================================================================
 * 4. THE BOOK COLUMN  —  the stage (redesign 2026-09-03)
 *
 * One object and its instrument. A soft glow, a hairline dial with a tick
 * scale and one slow orange sweep, three coins placed on the dial where they
 * never cross the cover, two chips, and the book at a fixed tilt breathing
 * on a cast shadow. The whole stage enters once, in order, in ~1.1s; after
 * that every loop is slow enough to be felt rather than watched.
 *
 * TWO ANIMATIONS PER ELEMENT, NO SEAM. Each moving element lists its
 * entrance first and its idle loop second. The idle loop's delay is the
 * entrance's delay plus its duration, so it begins on the exact frame the
 * entrance lands on its final value; and because the later animation in the
 * list wins for a shared property, the loop then owns `transform` while the
 * entrance's `both` fill keeps `opacity` at 1. Only opacity and transform
 * animate anywhere below.
 *
 * CENTRING WITHOUT TRANSFORM. Fixed-size layers centre with `inset: 0;
 * margin: auto` rather than translate(-50%, -50%), because their entrance
 * and idle keyframes need the whole transform to themselves.
 * ========================================================================= */

.tcs-hero__stage {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	height: 560px; /* Main.dc.html:158 */
	min-width: 0;
}

/* --- 4a. Entrance keyframes ---------------------------------------------- */

@keyframes tcs-stage-fade {

	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

@keyframes tcs-stage-settle {

	from {
		opacity: 0;
		transform: scale(var(--tcs-stage-settle-scale));
	}

	to {
		opacity: 1;
		transform: scale(1);
	}
}

@keyframes tcs-stage-rise {

	from {
		opacity: 0;
		transform: translateY(var(--tcs-stage-rise));
	}

	to {
		opacity: 1;
		transform: translateY(0);
	}
}

@keyframes tcs-stage-pop {

	from {
		opacity: 0;
		transform: translateY(8px) scale(var(--tcs-stage-pop-scale));
	}

	to {
		opacity: 1;
		transform: translateY(0) scale(1);
	}
}

/* --- 4b. The glow (behind everything) ------------------------------------ */

.tcs-hero__glow {
	position: absolute;
	inset: 0;
	margin: auto;
	width: 460px;
	height: 460px;
	border-radius: var(--tcs-radius-full);
	background: radial-gradient(
		circle,
		color-mix(in srgb, var(--tcs-orange) 34%, transparent) 0%,
		color-mix(in srgb, var(--tcs-orange) 10%, transparent) 42%,
		color-mix(in srgb, var(--tcs-orange) 0%, transparent) 70%
	);
	pointer-events: none;
	animation:
		tcs-stage-fade var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-glow var(--tcs-dur-glow) ease-in-out infinite;
	animation-delay:
		var(--tcs-stage-delay-glow),
		calc(var(--tcs-stage-delay-glow) + var(--tcs-dur-stage-enter));
}

/* Floor .7, never 0 — a glow that vanishes flickers. */
@keyframes tcs-glow {

	0%,
	100% {
		opacity: var(--tcs-glow-opacity-from);
		transform: scale(1);
	}

	50% {
		opacity: 1;
		transform: scale(var(--tcs-glow-scale));
	}
}

/* --- 4c. The dial and its sweep ------------------------------------------ */

/*
 * Two hairline rings and a 72-step scale, generated by tcs_hero_dial()
 * (inc/chapters-data.php). Static once it has settled: an instrument is
 * precise because it holds still.
 */
.tcs-hero__dial,
.tcs-hero__dial-sweep {
	position: absolute;
	inset: 0;
	margin: auto;
	width: 492px;
	height: 492px;
	overflow: visible;
	pointer-events: none;
}

.tcs-hero__dial {
	animation: tcs-stage-settle var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both;
	animation-delay: var(--tcs-stage-delay-dial);
}

.tcs-hero__dial-ring {
	stroke: color-mix(in srgb, var(--tcs-black) 13%, transparent);
	stroke-width: 1;
}

.tcs-hero__dial-ring--inner {
	stroke: color-mix(in srgb, var(--tcs-black) 8%, transparent);
}

.tcs-hero__dial-ticks {
	stroke: color-mix(in srgb, var(--tcs-black) 16%, transparent);
	stroke-width: 1;
	stroke-linecap: round;
}

.tcs-hero__dial-tick--major {
	stroke: color-mix(in srgb, var(--tcs-black) 30%, transparent);
	stroke-width: 1.5;
}

/*
 * The one thing on the dial that moves: a 42-degree orange arc making a
 * 48s lap. The <svg> rotates about its own centre, which is the dial's
 * centre, so the arc rides the outer ring exactly.
 */
.tcs-hero__dial-sweep {
	transform-origin: 50% 50%;
	animation:
		tcs-stage-fade var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-dial-sweep var(--tcs-dur-dial-sweep) linear infinite;
	animation-delay:
		calc(var(--tcs-stage-delay-dial) + 300ms),
		calc(var(--tcs-stage-delay-dial) + 300ms);
}

.tcs-hero__dial-arc {
	stroke: var(--tcs-orange);
	stroke-width: 2;
	stroke-linecap: round;
}

@keyframes tcs-dial-sweep {

	from {
		transform: rotate(0deg);
	}

	to {
		transform: rotate(360deg);
	}
}

/* --- 4d. The three coins, placed --------------------------------------- */

/*
 * WHERE THEY SIT, AND WHY THEY NEVER TOUCH THE BOOK. The stage centre is the
 * book's centre; the book is 292x438 plus a 13px page block on the right,
 * so its box runs x = -146..159 and y = -219..219 from the centre. Each coin
 * is set on the outer ring (radius 246) at an angle chosen so its disc
 * clears that box: Bitcoin at 55 degrees (x +201, y -141), Ethereum at 235
 * (x -201, y +141) and Tether at 110 (x +231, y +84). Two on the right, one
 * lower-left, balanced against the light chip top-left and the dark chip
 * bottom-right. The gate measures the clearance rather than trusting it.
 *
 * No rotation, no counter-rotation: a coin that never orbits cannot tumble.
 * Each one drifts 6px on its own period so the three never move as one.
 */
.tcs-hero__coin {
	position: absolute;
	z-index: 3;
	pointer-events: none;
	filter: drop-shadow(0 10px 18px color-mix(in srgb, var(--tcs-black) 22%, transparent));
}

.tcs-hero__coin svg {
	display: block;
}

@keyframes tcs-coin-float {

	0%,
	100% {
		transform: translateY(0);
	}

	50% {
		transform: translateY(var(--tcs-coin-float));
	}
}

.tcs-hero__coin--1 {
	width: 46px;
	height: 46px;
	left: calc(50% + 178px);
	top: calc(50% - 164px);
	animation:
		tcs-stage-pop var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-coin-float var(--tcs-dur-coin-float-1) ease-in-out infinite;
	animation-delay:
		var(--tcs-stage-delay-coin-1),
		calc(var(--tcs-stage-delay-coin-1) + var(--tcs-dur-stage-enter));
}

.tcs-hero__coin--2 {
	width: 38px;
	height: 38px;
	left: calc(50% - 220px);
	top: calc(50% + 122px);
	animation:
		tcs-stage-pop var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-coin-float var(--tcs-dur-coin-float-2) ease-in-out infinite;
	animation-delay:
		var(--tcs-stage-delay-coin-2),
		calc(var(--tcs-stage-delay-coin-2) + var(--tcs-dur-stage-enter));
}

.tcs-hero__coin--3 {
	width: 32px;
	height: 32px;
	left: calc(50% + 215px);
	top: calc(50% + 68px);
	animation:
		tcs-stage-pop var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-coin-float var(--tcs-dur-coin-float-3) ease-in-out infinite;
	animation-delay:
		var(--tcs-stage-delay-coin-3),
		calc(var(--tcs-stage-delay-coin-3) + var(--tcs-dur-stage-enter));
}

/* --- 4e. The two chips ---------------------------------------------------- */

.tcs-hero__chip {
	position: absolute;
	z-index: 4;
	display: flex;
	align-items: center;
	gap: 9px;
	padding: 11px 14px;
	border-radius: 10px;
	font-size: 12.5px;
	font-weight: var(--tcs-fw-semibold);
	white-space: nowrap;
	/*
	 * Decorative captions, not controls. They are aria-hidden in markup — the
	 * claims they carry are made in full sentences elsewhere on the page, so
	 * a screen reader loses nothing, and they must not become tab stops.
	 */
	pointer-events: none;
	animation:
		tcs-stage-rise var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-chip var(--tcs-dur-chip) ease-in-out infinite;
}

.tcs-hero__chip--light {
	top: 56px;
	left: 0;
	background: var(--tcs-white);
	border: var(--tcs-border-width) solid var(--tcs-border);
	color: var(--tcs-black);
	box-shadow: 0 12px 28px -10px color-mix(in srgb, var(--tcs-black) 24%, transparent);
	animation-delay:
		var(--tcs-stage-delay-chip-1),
		calc(var(--tcs-stage-delay-chip-1) + var(--tcs-dur-stage-enter));
}

/*
 * The second chip's idle bob is offset by a further 2.4s so the pair never
 * moves in lockstep — two chips moving as one read as a single panel.
 */
.tcs-hero__chip--dark {
	right: 0;
	bottom: 82px;
	background: var(--tcs-black);
	color: var(--tcs-cream);
	box-shadow: 0 12px 28px -10px color-mix(in srgb, var(--tcs-black) 40%, transparent);
	animation-delay:
		var(--tcs-stage-delay-chip-2),
		calc(var(--tcs-stage-delay-chip-2) + var(--tcs-dur-stage-enter) + var(--tcs-chip-delay-2));
}

@keyframes tcs-chip {

	0%,
	100% {
		transform: translateY(0);
	}

	50% {
		transform: translateY(var(--tcs-chip-lift));
	}
}

/* --- 4f. The book, its shadow and its sheen ------------------------------ */

/*
 * The shadow is on the GROUND. It sits under the book's resting position as
 * a sibling of the floating object, so when the book breathes upward the
 * shadow shrinks and softens beneath it instead of rising with it — the one
 * cue that turns "an image moving" into "an object floating".
 */
.tcs-hero__book-shadow {
	position: absolute;
	z-index: 1;
	left: 50%;
	top: calc(50% + 214px);
	width: 260px;
	height: 44px;
	margin-left: -124px;
	border-radius: 50%;
	background: radial-gradient(
		ellipse at center,
		color-mix(in srgb, var(--tcs-black) 42%, transparent) 0%,
		color-mix(in srgb, var(--tcs-black) 0%, transparent) 70%
	);
	filter: blur(8px);
	pointer-events: none;
	animation:
		tcs-stage-fade var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-book-shadow var(--tcs-dur-book-float) ease-in-out infinite;
	animation-delay:
		var(--tcs-stage-delay-book),
		calc(var(--tcs-stage-delay-book) + var(--tcs-dur-stage-enter));
}

@keyframes tcs-book-shadow {

	0%,
	100% {
		opacity: 1;
		transform: scale(1);
	}

	50% {
		opacity: var(--tcs-book-shadow-opacity-to);
		transform: scale(var(--tcs-book-shadow-scale));
	}
}

/*
 * The floating object. It carries the entrance and the breath; the book
 * inside carries the static tilt. Splitting them is what lets the tilt be a
 * fixed pose instead of a value the float has to keep restating.
 */
.tcs-hero__object {
	position: relative;
	z-index: 2;
	animation:
		tcs-stage-rise var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
		tcs-book-float var(--tcs-dur-book-float) ease-in-out infinite;
	animation-delay:
		var(--tcs-stage-delay-book),
		calc(var(--tcs-stage-delay-book) + var(--tcs-dur-stage-enter));
}

@keyframes tcs-book-float {

	0%,
	100% {
		transform: translateY(0);
	}

	50% {
		transform: translateY(var(--tcs-book-float));
	}
}

/*
 * A fixed three-quarter pose. The artboard rotated the book continuously
 * between -14 and -7 degrees over 12s; at that amplitude a rectangle with a
 * printed cover reads as wobbling, not resting. -12/3 is the pose a hand
 * would hold a book at to show you its front, and it stays there.
 */
.tcs-hero__book {
	position: relative;
	width: 292px;
	/*
	 * 438, not 416. The artwork is 2:3 and the placeholder was 0.702, so
	 * keeping the artboard's width and letting the height grow is what
	 * preserves the composition uncropped — the title sits near the top of
	 * the cover and a centre crop would cut into it.
	 */
	height: 438px;
	transform:
		perspective(var(--tcs-book-perspective))
		rotateY(var(--tcs-book-tilt-y))
		rotateX(var(--tcs-book-tilt-x));
	transform-style: preserve-3d;
}

/* The page block — the stack of paper visible along the fore edge. */
.tcs-hero__book-pages {
	position: absolute;
	top: 7px;
	right: -13px;
	bottom: 7px;
	width: 13px;
	border-radius: 0 3px 3px 0;
	background: repeating-linear-gradient(90deg, var(--tcs-cream-2) 0 1px, var(--tcs-border-2) 1px 2.5px);
	box-shadow: inset -2px 0 4px color-mix(in srgb, var(--tcs-black) 12%, transparent);
	pointer-events: none;
}

/*
 * The cover itself. The artwork is exactly 2:3 and the box is exactly 2:3,
 * so `cover` crops nothing; it is used rather than `fill` so the rule stays
 * correct if the artwork is ever re-exported at a slightly different ratio.
 */
.tcs-hero__book-shell {
	position: absolute;
	inset: 0;
	overflow: hidden;
	border-radius: 4px 6px 6px 4px;
	background: var(--tcs-black);
	box-shadow:
		0 30px 60px -24px color-mix(in srgb, var(--tcs-black) 55%, transparent),
		0 2px 6px color-mix(in srgb, var(--tcs-black) 18%, transparent);
}

.tcs-hero__cover {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The lit spine, ABOVE the image in stacking order — it is what makes the
 * left edge read as a folded, lit surface rather than as a printed stripe.
 * Narrow (5px) because the artwork already carries its own spine band.
 */
.tcs-hero__book-spine {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	z-index: 2;
	width: 5px;
	background: linear-gradient(180deg, var(--tcs-orange), var(--tcs-amber));
	box-shadow: 2px 0 6px color-mix(in srgb, var(--tcs-black) 35%, transparent);
	pointer-events: none;
}

/*
 * The sheen: a diagonal band of light that crosses the cover once every 9s
 * and rests off-cover the remainder of the cycle. The gradient is drawn
 * diagonally INSIDE an element the size of the shell, and the element slides
 * horizontally across it — the shell's overflow: hidden does the clipping.
 * It lights the object, not the artwork: translucent, moving, a reflection.
 */
.tcs-hero__book-sheen {
	position: absolute;
	inset: 0;
	z-index: 1;
	background: linear-gradient(
		108deg,
		transparent 38%,
		var(--tcs-sheen-highlight) 48%,
		color-mix(in srgb, var(--tcs-sheen-highlight) 30%, transparent) 52%,
		transparent 62%
	);
	transform: translateX(-100%);
	animation: tcs-sheen var(--tcs-dur-sheen) ease-in-out infinite;
	animation-delay: calc(var(--tcs-stage-delay-book) + var(--tcs-dur-stage-enter) + 1.6s);
	pointer-events: none;
}

@keyframes tcs-sheen {

	0% {
		transform: translateX(-100%);
	}

	24%,
	100% {
		transform: translateX(100%);
	}
}

/* ===========================================================================
 * 5. THE SCROLL CUE  —  Main.dc.html:206-211
 *
 * The only DOWNWARD motion in the system, and deliberately so: it points at
 * the content below the fold.
 * ========================================================================= */

.tcs-hero__cue-wrap {
	position: relative;
	display: flex;
	justify-content: center;
	margin-top: 10px;
}

.tcs-hero__cue {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 5px;
	animation: tcs-cue var(--tcs-dur-cue) ease-in-out infinite;
	pointer-events: none;
}

.tcs-hero__cue-label {
	/*
	 * 12px, not the artboard's 11.5px (Story 4.5's type-floor sweep caught
	 * it). The 12px floor is the design system's own rule (DESIGN.md type
	 * floor) — the artboard drew beneath its own floor, which makes this
	 * an artboard slip, treated the same way chrome.css treated the mobile
	 * footer board's failing disclaimer colour.
	 */
	font-size: 12px;
	font-weight: var(--tcs-fw-semibold);
	letter-spacing: var(--tcs-ls-eyebrow);
	color: var(--tcs-muted);
}

@keyframes tcs-cue {

	0%,
	100% {
		opacity: var(--tcs-cue-opacity-from);
		transform: translateY(0);
	}

	50% {
		opacity: 1;
		transform: translateY(var(--tcs-cue-travel));
	}
}

/* ===========================================================================
 * 6. THE MOBILE PRICE BLOCK  —  HomeMobile.dc.html:75-83
 *
 * THIS BLOCK IS THE STORY. At 390 the header's price is display:none
 * (chrome.css moves it into the overlay, which is closed), so the nav cannot
 * satisfy the price-above-the-fold criterion the way it does at 1440. The
 * hero has to carry its own, and it has to carry it high enough to survive a
 * 667px-tall viewport.
 *
 * It is rendered on every width and hidden above 768 rather than injected by
 * a script, so it is in the served HTML unconditionally: the price must be
 * visible to a crawler, to a reader with JavaScript off, and on the first
 * paint before any stylesheet-dependent layout settles.
 * ========================================================================= */

.tcs-hero__price-block {
	display: none;
}

.tcs-hero__price {
	display: flex;
	align-items: baseline;
	gap: 12px;
}

.tcs-hero__price-now {
	font-size: 44px;
	font-weight: var(--tcs-fw-semibold);
	letter-spacing: var(--tcs-ls-hero);
	line-height: 1;
	color: var(--tcs-black);
}

/*
 * <s>, not a span with text-decoration. The struck anchor price is a semantic
 * statement — "this was 60.00" — and an assistive technology that ignores CSS
 * would otherwise read the two numbers as a single confusing price. This is
 * the same decision header.php took for the nav price.
 */
.tcs-hero__price-was {
	font-size: 20px;
	font-weight: var(--tcs-fw-medium);
	color: var(--tcs-muted);
}

/* ===========================================================================
 * 7. MOBILE  —  HomeMobile.dc.html:38-88
 *
 * A DESIGNED STATE, not a reflow. The grid collapses, the orbit rings and
 * their three coins are replaced by two bobbing coins, the chips and the
 * scroll cue do not render at all, and the price block appears.
 *
 * THE STACKING ORDER IS THE ACCEPTANCE CRITERION. headline -> subheadline ->
 * price -> CTA -> refund link -> book — the price sits BEFORE the book in the
 * DOM, not after it, and the price must clear a 667px fold well before the
 * stack reaches the book. Section 7b is where that is actually paid for.
 *
 * Code-review fix, 2026-09-04: this comment previously read "book -> price",
 * which reverses the two and would have endorsed reintroducing the
 * below-the-fold price this epic exists to remove. The DOM in front-page.php
 * (and the Spec Change Log entry it implements) has always put the price
 * block ahead of the book; only this comment disagreed with it.
 * ========================================================================= */

@media (max-width: 768px) {

	.tcs-hero {
		padding-top: 40px;    /* HomeMobile.dc.html:50 */
		padding-bottom: 44px;
	}

	.tcs-hero__grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 22px; /* HomeMobile.dc.html:50 */
	}

	.tcs-hero__copy {
		gap: 16px;
	}

	.tcs-hero__headline {
		font-size: var(--tcs-fs-hero-mobile);
		line-height: var(--tcs-lh-hero-mobile);
		letter-spacing: var(--tcs-ls-hero-mobile);
	}

	/*
	 * The three lines stop being three lines. HomeMobile.dc.html:52 sets the
	 * headline as one flowing sentence at 42px, and forcing the desktop
	 * breaks at 390 would leave three short ragged lines with a hole in the
	 * middle. The spans stay in the markup — one <h1>, three spans — and
	 * simply stop being blocks.
	 */
	.tcs-hero__line {
		display: inline;
	}

	/*
	 * The drawn underline is a 440px-wide SVG positioned against a line that
	 * no longer exists as its own block. It is decoration, and at 390 it is
	 * decoration that would overflow the viewport.
	 */
	.tcs-hero__underline {
		display: none;
	}

	.tcs-hero__sub {
		font-size: 16.5px;
		line-height: 1.6;
		max-width: none;
	}

	/*
	 * No pill, no chips, no scroll cue, no dial at mobile —
	 * HomeMobile.dc.html draws none of them. Every one of them is pure
	 * decoration, and every pixel they would occupy is a pixel the price
	 * needs to stay above a 667px fold.
	 */
	/*
	 * MOBILE KEEPS THE STAGE ALIVE (mobile pass, 2026-09-05). This list used
	 * to hide the glow, the book's shadow and the sheen too, and the book
	 * itself stopped floating — at 390 the hero read as a static picture
	 * while the desktop one breathes. The dial, chips, proof line and cue
	 * stay hidden (they are laid out for a 492px board), but the glow,
	 * shadow, sheen and float are cheap transforms/opacity and come back
	 * below at mobile sizes.
	 */
	.tcs-hero__proof,
	.tcs-hero__chip,
	.tcs-hero__cue-wrap,
	.tcs-hero__dial,
	.tcs-hero__dial-sweep,
	.tcs-hero__grid-paper,
	.tcs-hero__twinkle,
	.tcs-hero__assurances {
		display: none;
	}
	.tcs-hero__glow {
		width: 300px;
		height: 300px;
	}
	.tcs-hero__book-shadow {
		top: auto;
		bottom: -30px;
		width: 190px;
		height: 32px;
		margin-left: -95px;
	}

	/*
	 * Three placed coins become the two drifting coins the mobile board
	 * draws (HomeMobile.dc.html:59-60). The third is dropped rather than
	 * repositioned — a third floating coin at 390 is clutter, and the board
	 * does not draw one.
	 */
	.tcs-hero__coin--3 {
		display: none;
	}

	/*
	 * The surviving two keep their entrance and swap the desktop drift for
	 * the mobile board's own — which rotates a degree or two, fine here
	 * because nothing is orbiting.
	 */
	.tcs-hero__coin--1 {
		top: 30px;   /* HomeMobile.dc.html:59 */
		left: 22px;
		width: 44px; /* HomeMobile.dc.html:59 */
		height: 44px;
		animation:
			tcs-stage-pop var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
			tcs-drift var(--tcs-dur-drift-1) ease-in-out infinite;
	}

	.tcs-hero__coin--2 {
		top: auto;
		left: auto;
		right: 20px;
		bottom: 60px; /* HomeMobile.dc.html:60 */
		width: 36px;  /* HomeMobile.dc.html:60 */
		height: 36px;
		animation:
			tcs-stage-pop var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
			tcs-drift-2 var(--tcs-dur-drift-2) ease-in-out infinite;
	}

	/* --- 7b. THE BOOK SHRINKS, AND THIS IS WHY -------------------------- */

	/*
	 * HomeMobile.dc.html:61 draws a 212x300 book. At 844 that leaves 94px of
	 * headroom below the price — comfortable. At 667 it does not: the price
	 * lands BELOW the fold, which is the exact defect this story exists to
	 * fix, and no document states a mobile fold height that would let the
	 * artboard settle it.
	 *
	 * So the book gives up the margin rather than the price. `height` here is
	 * a static declaration, not an animated one — the hard limit is about
	 * what ANIMATES, and nothing animates this.
	 *
	 * 2:3 is preserved by aspect-ratio rather than by a second magic number,
	 * so the width follows the height automatically and the two can never
	 * drift into a crop.
	 */
	.tcs-hero__stage {
		height: auto;
		padding-block: 0;
	}

	/*
	 * The book keeps its entrance and loses its breath at mobile: the board
	 * draws it still, and a floating object over a stack the reader is
	 * about to scroll past is motion with no audience.
	 */
	.tcs-hero__object {
		animation:
			tcs-stage-rise var(--tcs-dur-stage-enter) var(--tcs-ease-stage) both,
			tcs-book-float var(--tcs-dur-book-float) ease-in-out infinite;
		animation-delay:
			var(--tcs-stage-delay-book),
			calc(var(--tcs-stage-delay-book) + var(--tcs-dur-stage-enter));
	}

	/*
	 * THE BOOK SHRINKS SO THE WHOLE STACK CLEARS THE FOLD, not just the
	 * price. HomeMobile.dc.html:61 draws 212x300; at 390x844 a 300px book
	 * pushes its own bottom edge to y=921 and the object is cut off by the
	 * fold — which is not a price defect, but it is a hero whose subject is
	 * half off-screen on the commonest phone in the matrix.
	 *
	 * 224 is the measured value at which the full stack — headline,
	 * subheadline, price, CTA, refund link and the ENTIRE book — lands inside
	 * 844, with the book's bottom edge at y=841.
	 *
	 * The price is unaffected either way, and that is the important part: it
	 * sits ABOVE the book in the DOM, so it clears the fold at 667 whatever
	 * the book does. This declaration is preserving the artboard's
	 * composition, not meeting the acceptance criterion — the DOM order is
	 * what meets that, and it cannot be undone by a spacing change.
	 */
	.tcs-hero__book {
		width: auto;
		height: 224px;
		aspect-ratio: 2 / 3;
		/*
		 * No tilt at mobile. The board draws the book flat, and a 3D rotation
		 * on a 390px-wide viewport pushes the cover's corner past the edge.
		 */
		transform: none;
	}

	/*
	 * The page block and the sheen are desktop-scale details on a book two
	 * thirds the size. The board draws neither.
	 */
	.tcs-hero__book-pages {
		display: none;
	}

	.tcs-hero__book-shell {
		border-radius: 4px;
		box-shadow: 0 30px 60px -20px color-mix(in srgb, var(--tcs-black) 45%, transparent);
	}

	.tcs-hero__book-spine {
		width: 4px;
	}

	/* --- 7c. The price block appears ------------------------------------ */

	.tcs-hero__price-block {
		display: flex;
		flex-direction: column;
		gap: 16px; /* HomeMobile.dc.html:74 */
	}

	/*
	 * Full-width at mobile — HomeMobile.dc.html:81 draws a block button. The
	 * 44px floor is already met by .tcs-btn's min-height; the 17px padding
	 * takes it well past.
	 */
	.tcs-hero__cta {
		width: 100%;
		padding: 17px 0;
		font-size: 16px;
	}

	/* The board draws no secondary action at mobile. */
	.tcs-hero__cta-secondary {
		display: none;
	}

	.tcs-hero__actions {
		margin-top: 0;
	}

	/*
	 * The refund link becomes the mobile assurance row (HomeMobile.dc.html:82).
	 * It keeps its 44px tap target, and here it is NOT pulled out of the flow
	 * — at mobile it is a row of its own rather than one item among three, so
	 * the height it needs is height the layout should actually have.
	 */
	.tcs-hero__mobile-assurance {
		display: flex;
		align-items: center;
		gap: 8px;
		font-size: 13.5px;
		color: var(--tcs-body);
	}

	.tcs-hero__mobile-assurance svg {
		flex: 0 0 auto;
	}
}

/*
 * The two bobbing coins — HomeMobile.dc.html's `drift` / `drift2`
 * (its _head.html:19-20). They rotate a degree or two, which is fine: these
 * coins are not on an orbit, so there is no inherited rotation for the gate's
 * uprightness rule to be about. That rule is measured on the desktop orbits.
 */
@keyframes tcs-drift {

	0%,
	100% {
		transform: translateY(0) rotate(0deg);
	}

	50% {
		transform: translateY(-8px) rotate(1.5deg);
	}
}

@keyframes tcs-drift-2 {

	0%,
	100% {
		transform: translateY(0) rotate(0deg);
	}

	50% {
		transform: translateY(7px) rotate(-2deg);
	}
}

/*
 * A SHORT VIEWPORT, not merely a narrow one.
 *
 * 390x667 is the case the I/O matrix names, and it is 177px shorter than the
 * 844 the mobile layout was measured against.
 *
 * WHAT ACTUALLY KEEPS THE PRICE ABOVE THE FOLD HERE, established by breaking
 * each candidate in turn and watching the gate: it is the DOM ORDER, not any
 * declaration in this block. The price sits above the book in the document, so
 * growing the book to 600px does not move the price by a pixel and the gate
 * stays green — which is the right architecture, and worth stating plainly so
 * nobody later "fixes" the fold by shrinking the book and believes they have
 * done something load-bearing.
 *
 * What this block does is buy comfort rather than correctness: it tightens the
 * vertical rhythm and the book so the whole hero — decoration included — sits
 * closer to the fold on a short screen, instead of leaving the book two thirds
 * cut off. The thing that FAILS the gate is an oversized headline or
 * subheadline, because those are above the price; the gate was mutation-tested
 * against exactly that and reported the price's bottom edge at 1046 against a
 * 667 fold.
 *
 * Keyed on viewport HEIGHT rather than on a device, so it is correct on a
 * short window at any width and does nothing on a tall phone.
 */
@media (max-width: 768px) and (max-height: 740px) {

	.tcs-hero {
		padding-top: 24px;
		padding-bottom: 32px;
	}

	.tcs-hero__grid {
		gap: 14px;
	}

	.tcs-hero__copy {
		gap: 12px;
	}

	.tcs-hero__book {
		height: 196px;
	}

	.tcs-hero__price-block {
		gap: 12px;
	}

	.tcs-hero__price-now {
		font-size: 38px;
	}
}

/* ===========================================================================
 * 8. REDUCED MOTION
 *
 * Every animation above resolves to its FINAL value — never to zero, never to
 * invisible, never to zero height. Two of them need more than `animation:
 * none`, because their final value is not their default value.
 *
 * NOT SCOPED TO .tcs-js, following css/motion.css:379-401 and for the same
 * reason: reveal.js can only remove that class at DOMContentLoaded, and
 * anything scoped to it would spend the interval before that at its start
 * value — which is motion, for a reader who asked for none.
 * ========================================================================= */

@media (prefers-reduced-motion: reduce) {

	/*
	 * The blanket rule. `opacity: 1` rather than `opacity: initial` is what
	 * makes this a resolution to the FINAL value: several of these animations
	 * (twinkle, ring, cue, pulse) have a start opacity below 1, and dropping
	 * the animation without pinning the opacity would leave them dimmed at
	 * whatever the last computed frame was.
	 */
	.tcs-hero__blob,
	.tcs-hero__twinkle,
	.tcs-hero__proof-dot,
	.tcs-hero__glow,
	.tcs-hero__dial,
	.tcs-hero__dial-sweep,
	.tcs-hero__coin,
	.tcs-hero__chip,
	.tcs-hero__cue,
	.tcs-hero__book-shadow,
	.tcs-hero__object,
	.tcs-hero__book-sheen {
		animation: none !important;
		opacity: 1 !important;
		transform: none !important;
	}

	/*
	 * THE ENTRANCE IS THE THIRD PLACE `animation: none` needs a partner.
	 * Every stage element starts its entrance at opacity 0 and holds that
	 * start with `both`; the blanket `opacity: 1` above is what makes the
	 * stage simply BE there for a reader who asked for no motion, rather
	 * than never arriving. The sheen's rest pose is off-cover
	 * (translateX(-100%)); `transform: none` parks it over the cover as a
	 * fixed soft highlight, which is a lit object rather than a bar.
	 */

	/*
	 * THE DRAWN UNDERLINE — the one place `animation: none` alone is a bug.
	 *
	 * The stroke's resting state is dasharray 1200 with the offset still at
	 * 1200, which is a COMPLETELY INVISIBLE line. Stopping the animation
	 * without clearing the dash array leaves the reader with a headline whose
	 * underline never appears. Clearing the dasharray is what resolves it to
	 * its final value: a fully drawn stroke.
	 */
	.tcs-hero__underline-path {
		animation: none !important;
		stroke-dasharray: none !important;
		stroke-dashoffset: 0 !important;
	}

	/*
	 * THE BOOK'S TILT STAYS. It is a fixed pose, not an animation — nothing
	 * about it moves, so reduced motion has nothing to reduce, and a book
	 * shown three-quarter on is the same object at rest as one shown flat.
	 * (The old design's continuous tilt WAS motion, and was flattened here;
	 * the note is kept so nobody re-adds that rule by reflex.)
	 */
}
