/* =============================================================
   Captives — the daily cascade
   -------------------------------------------------------------
   A continuous fall of disparate documents.

   Architecture:
     .doc        outer layer — vertical fall, primary rotation
     .sway       inner layer — lateral drift, slight wobble
     <svg>       the document itself

   Each layer runs its own animation with its own duration and
   delay, so the combined motion never repeats and never feels
   mechanical. All variation comes from CSS custom properties
   set inline by captives-teaser.js.

   The cascade fills its parent container. Vertical motion uses
   container query units (cqh) so the fall tracks the container's
   height regardless of viewport size. captives-teaser.js positions
   each doc in pixels with a safe range so nothing overflows.
   ============================================================= */

/* --------------------  Animation wrapper  ----------------------------

   Fills the section's animation column and centers the cascade in
   it — the cascade just needs a parent with a defined width and
   height. No padding: the cascade spans its full 1fr column, the
   mirror of the product composition's footprint. */

.animation {
	width: 100%;
	height: 100%;
	display: grid;
	place-items: center;
	padding: 0;
}

.animation .cascade {
	width: 100%;
	height: 100%;
}

/* --------------------  Cascade canvas  -------------------- */

.cascade {
	position: relative;
	width: 100%;
	height: 100%;
	margin: 0;
	overflow: hidden;

	/* Establish a containing context for cqh units used in keyframes.
     The fall translates by cqh, so the motion always traverses the
     cascade's own height, not the viewport's. */
	container-type: size;

	/* soft edges top and bottom only: docs surface and sink through
	   the vertical fades. The sides have no fade — placement in
	   captives-teaser.js insets every doc (sway, drift and rotation
	   included) so nothing ever reaches, or clips against, a side. */
	-webkit-mask-image: linear-gradient(
		to bottom,
		transparent 0%,
		#000 6%,
		#000 94%,
		transparent 100%
	);
	mask-image: linear-gradient(
		to bottom,
		transparent 0%,
		#000 6%,
		#000 94%,
		transparent 100%
	);
}

/* --------------------  Document instance  -------------------- *

   Each .doc is positioned via JS-injected custom properties:

     --x          horizontal placement       (px, safe-ranged)
     --w / --h    rendered size              (px)
     --rot-a      starting rotation          (deg)
     --rot-b      ending rotation            (deg)
     --drift      gentle horizontal carry    (px, bounded)
     --opacity    target opacity at mid-fall (0–1)
     --doc-ink    per-instance ink colour    (any colour)

   Inner .sway carries:
     --sway-amp   lateral oscillation        (px, bounded)
     --wobble     rotational oscillation     (deg)

   Both layers animate with their own duration + negative delay.
*/

.doc {
	position: absolute;
	top: 0;
	left: var(--x);
	width: var(--w);
	height: var(--h);

	color: var(--doc-ink, var(--ink));
	opacity: 0;
	will-change: transform, opacity;

	animation-name: fall;
	animation-iteration-count: infinite;
	animation-timing-function: linear;
}

.sway {
	width: 100%;
	height: 100%;
	animation-name: sway;
	animation-iteration-count: infinite;
	animation-direction: alternate;
	animation-timing-function: ease-in-out;
}

.doc svg {
	display: block;
	width: 100%;
	height: 100%;
	filter: drop-shadow(0 1px 1.5px rgba(26, 23, 20, 0.05));
}

/* Atmospheric depth — a fraction of documents recede into a back
   plane. Blur replaces the drop-shadow; the soft focus does the
   spatial work on its own. */
.doc.deep svg {
	filter: blur(1.1px);
}

/* --------------------  Paper & ink  ------------------------------

   The card artwork (../shared/cards.js) carries its colors inline;
   only the overlays styled below — whispers via currentColor
   (--doc-ink), amber accents explicitly — are themed here. */

/* --------------------  Whisper (Garamond word)  -------------------- */

.doc .whisper {
	font-family: var(--font-sans);
	font-style: italic;
	font-weight: 400;
	fill: currentColor;
	fill-opacity: 0.26;
	letter-spacing: 0.04em;
}

/* --------------------  Amber accents  -------------------- */

.doc .accent-stroke {
	stroke: var(--amber);
	stroke-opacity: 1;
	stroke-width: 0.7;
	stroke-linecap: round;
	stroke-linejoin: round;
	fill: none;
}

/* a felt-tip-style highlight: thicker, softer, lower alpha */
.doc .accent-swipe {
	stroke: var(--amber);
	stroke-opacity: 0.3;
	stroke-width: 2.6;
	stroke-linecap: round;
	fill: none;
}

/* --------------------  Motion  ------------------------------

   Two animations run in parallel:
     fall  — vertical translation (in cqh, container-relative),
             primary rotation, opacity
     sway  — lateral oscillation and a slight rotational wobble

   They have unrelated durations and delays. The two cycles
   beat against each other and produce drift that never repeats. */

/* Longer, eased fades: the intermediate half-opacity stops bend the
   linear keyframe ramps into a soft ease at both ends. */
@keyframes fall {
	0% {
		transform: translate3d(0, -28cqh, 0) rotate(var(--rot-a));
		opacity: 0;
	}
	8% {
		opacity: calc(var(--opacity) * 0.5);
	}
	18% {
		opacity: var(--opacity);
	}
	76% {
		opacity: var(--opacity);
	}
	90% {
		opacity: calc(var(--opacity) * 0.45);
	}
	100% {
		transform: translate3d(var(--drift), 118cqh, 0) rotate(var(--rot-b));
		opacity: 0;
	}
}

@keyframes sway {
	from {
		transform: translate3d(calc(var(--sway-amp) * -1), 0, 0)
			rotate(calc(var(--wobble) * -1));
	}
	to {
		transform: translate3d(var(--sway-amp), 0, 0) rotate(var(--wobble));
	}
}

/* --------------------  Offscreen parking  --------------------

   captives-teaser.js toggles .parked from an IntersectionObserver,
   the CSS counterpart of the scene scripts' rAF parking: the fall and
   sway loops are ambient, so the phase shift a pause causes is
   untrackable across an offscreen gap. */

.cascade.parked .doc,
.cascade.parked .sway {
	animation-play-state: paused;
}

/* --------------------  Reduced-motion respect  -------------------- */

@media (prefers-reduced-motion: reduce) {
	.doc,
	.sway {
		animation: none;
	}
	.doc {
		opacity: var(--opacity);
		transform: translate3d(0, var(--frozen-y, 40cqh), 0) rotate(var(--rot-a));
	}
}
