/**
 * hero.css — hero choreography for /test-homepage/ (pairs with hero.js).
 *
 * Layers on the "Homepage (black canvas)" section of main.css. Sibling module
 * atmosphere.css/js owns boot overlay, starfield and CRT layers (z-index
 * 0 / 9998 / 9999); everything here stays within z-index 1–100.
 * Class prefix: zp-hero- (custom cursor: zp-cur-). Accent: #C4A7FB.
 */

/* ── 1. Terminal typewriter ─────────────────────────────────────── */

[data-typewriter] { position: relative; }

/* Real text, always in the accessibility tree, visually hidden. */
.zp-hero-tw-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* Full text kept in flow but invisible — reserves height, zero layout shift. */
.zp-hero-tw-sizer { visibility: hidden; }

/* aria-hidden overlay that receives the typed characters. */
.zp-hero-tw-live {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.zp-hero-tw-cursor { color: #C4A7FB; }

@media (prefers-reduced-motion: no-preference) {
	.zp-hero-tw-cursor { animation: zp-hero-blink 1s step-end infinite; }
}

@keyframes zp-hero-blink {
	0%   { opacity: 1; }
	50%  { opacity: 0; }
	100% { opacity: 1; }
}

.zp-hero-tw-cursor--out {
	animation: none;
	opacity: 0;
	transition: opacity 0.45s ease;
}

[data-typewriter-after] { transition: opacity 0.5s ease, filter 0.5s ease; }

[data-typewriter-after].zp-hero-tw-wait {
	opacity: 0;
	filter: blur(6px);
	pointer-events: none;
}

/* ── 2. Hero art gravity ────────────────────────────────────────── */

[data-tilt] {
	position: relative;
	will-change: transform;
	--zp-hero-glow-hi: 0.75;
	--zp-hero-glow-lo: 0.45;
	--zp-hero-chroma-a: 0;
}

/* Soft lilac radial glow behind the moon. Static by default (reduced-motion
   safe); breathes + intensifies on hover under no-preference below. */
[data-tilt]::before {
	content: "";
	position: absolute;
	inset: -10%;
	border-radius: 50%;
	background: radial-gradient(
		circle,
		rgba(196, 167, 251, 0.14) 0%,
		rgba(196, 167, 251, 0.05) 45%,
		rgba(196, 167, 251, 0) 72%
	);
	filter: blur(80px);
	opacity: var(--zp-hero-glow-hi);
	pointer-events: none;
	z-index: 0;
}

[data-tilt] .zp-home__art {
	position: relative;
	z-index: 1;
}

@media (prefers-reduced-motion: no-preference) {
	[data-tilt]::before { animation: zp-hero-breathe 5s ease-in-out infinite; }

	/* Chroma flicker runs alongside the float at all times but its shadow
	   alpha is 0 until hover — so the float animation never restarts and
	   nothing can freeze mid-burst when the cursor leaves. */
	[data-tilt] .zp-home__art {
		animation:
			zp-hero-float 7s ease-in-out infinite,
			zp-hero-chroma 2s linear infinite;
	}
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
	[data-tilt]:hover {
		--zp-hero-glow-hi: 1;
		--zp-hero-glow-lo: 0.7;
		--zp-hero-chroma-a: 0.25;
	}
}

@keyframes zp-hero-breathe {
	0%, 100% { transform: scale(0.92); opacity: var(--zp-hero-glow-lo); }
	50%      { transform: scale(1.05); opacity: var(--zp-hero-glow-hi); }
}

@keyframes zp-hero-float {
	0%, 100% { transform: translateY(-6px); }
	50%      { transform: translateY(6px); }
}

/* ~150ms chromatic-aberration burst once per 2s cycle; alpha comes from
   --zp-hero-chroma-a (0 at rest, 0.25 while the art is hovered). */
@keyframes zp-hero-chroma {
	0%, 89.9%, 97.6%, 100% { filter: none; }
	90%, 93.5% {
		filter:
			drop-shadow(-2px 0 rgba(255, 0, 80, var(--zp-hero-chroma-a, 0)))
			drop-shadow(2px 0 rgba(0, 160, 255, var(--zp-hero-chroma-a, 0)));
	}
	93.6%, 97.5% {
		filter:
			drop-shadow(2px 0 rgba(255, 0, 80, var(--zp-hero-chroma-a, 0)))
			drop-shadow(-2px 0 rgba(0, 160, 255, var(--zp-hero-chroma-a, 0)));
	}
}

/* ── 3. Planets arcade ──────────────────────────────────────────── */

/* Glitch burst frames (hero.js cycles these rapidly, 50–90ms each).
   The -37px translateX from main.css lives on the wrapper, so
   transforming the svg is safe. Three flavours:
   a = slice + jump, b = RGB channel split, c = tear + hue invert kick. */
[data-planets].zp-hero-glitched--a svg {
	transform: translateX(-4px);
	clip-path: polygon(
		0 0, 100% 0, 100% 32%, 0 32%,
		0 42%, 100% 42%, 100% 100%, 0 100%
	);
	filter: hue-rotate(55deg) saturate(1.6);
}

[data-planets].zp-hero-glitched--b svg {
	transform: translateX(3px) skewX(-1.5deg);
	filter:
		drop-shadow(-3px 0 rgba(255, 0, 80, 0.55))
		drop-shadow(3px 0 rgba(0, 160, 255, 0.55))
		saturate(1.4);
}

[data-planets].zp-hero-glitched--c svg {
	transform: translateX(-2px) translateY(2px);
	clip-path: polygon(
		0 0, 100% 0, 100% 55%, 0 55%,
		0 62%, 100% 62%, 100% 78%, 0 78%,
		0 86%, 100% 86%, 100% 100%, 0 100%
	);
	filter: hue-rotate(-70deg) contrast(1.3) brightness(1.35);
}

/* ── 4. Phosphor cursor (zp-cur-) ───────────────────────────────── */

/* Class added by hero.js only on fine pointers without reduced motion. */
body.zp-hero-nocursor,
body.zp-hero-nocursor * { cursor: none !important; }

.zp-cur-layer {
	position: fixed;
	inset: 0;
	z-index: 100;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.3s ease;
}

.zp-cur-dot,
.zp-cur-ghost {
	position: absolute;
	top: 0;
	left: 0;
	pointer-events: none;
	will-change: transform;
}

/* 28px box scaled to a 6px dot; ring state scales to 1 and hollows out,
   so growth is transform-only (no layout). */
.zp-cur-core {
	display: block;
	width: 28px;
	height: 28px;
	margin: -14px 0 0 -14px;
	border-radius: 50%;
	border: 1.5px solid rgba(196, 167, 251, 0);
	background: #C4A7FB;
	mix-blend-mode: difference;
	transform: scale(0.215);
	transition:
		transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
		background-color 0.2s ease,
		border-color 0.2s ease;
}

.zp-cur-dot--ring .zp-cur-core {
	transform: scale(1);
	background: rgba(196, 167, 251, 0);
	border-color: #C4A7FB;
}

.zp-cur-ghost {
	width: 5px;
	height: 5px;
	margin: -2.5px 0 0 -2.5px;
	border-radius: 50%;
	background: #C4A7FB;
}

/* ── 5. Magnetic links + text glitch ────────────────────────────── */

[data-magnetic] {
	display: inline-block;
	will-change: transform;
}

@media (pointer: fine) and (prefers-reduced-motion: no-preference) {
	/* Soft overshoot spring for the snap-back… */
	[data-magnetic] { transition: transform 0.55s cubic-bezier(0.3, 1.6, 0.4, 1); }
	/* …suspended while hero.js is steering the element frame-by-frame. */
	[data-magnetic].zp-hero-magnet-live { transition: none; }
}

[data-glitch] { position: relative; }

/* aria-hidden scramble overlay; the real text stays in the a11y tree
   (color: transparent for the ~160ms glitch, never removed). */
.zp-hero-glitch-fake {
	display: none;
	position: absolute;
	inset: 0;
	overflow: hidden;
	white-space: nowrap;
	color: #C4A7FB;
}

[data-glitch].zp-hero-glitching {
	text-shadow:
		0 0 10px rgba(196, 167, 251, 0.9),
		0 0 28px rgba(196, 167, 251, 0.45);
}

[data-glitch].zp-hero-glitching .zp-hero-glitch-real { color: transparent; }
[data-glitch].zp-hero-glitching .zp-hero-glitch-fake { display: block; }

/* Shell fix: the tilt wrapper must carry the art's 44% width (the bare img
   resolved 44% against a shrink-to-fit parent and drifted off-center). */
.zp-test .zp-home__art-wrap { width: 100%; max-width: 524px; }
.zp-test .zp-home__art-wrap .zp-home__art { width: 100%; }

/* ── 6. Ambient signal surge (class toggled by hero.js) ─────────── */

@media (prefers-reduced-motion: no-preference) {
	/* Chroma alpha + glow ride the existing custom properties (no
	   animation restarts); the harsh steps() filter on the wrapper adds
	   frame-snap RGB tears. Only `filter` animates here — the wrapper's
	   transform belongs to the JS tilt lerp. */
	[data-tilt].zp-hero-art-surge {
		--zp-hero-chroma-a: 0.35;
		--zp-hero-glow-hi: 1;
		animation: zp-hero-surge 0.38s steps(1) infinite;
	}
}

@keyframes zp-hero-surge {
	0%, 100% { filter: none; }
	22% {
		filter:
			drop-shadow(-3px 0 rgba(255, 0, 80, 0.35))
			drop-shadow(3px 0 rgba(0, 160, 255, 0.35));
	}
	48% { filter: none; }
	74% {
		filter:
			drop-shadow(2px 0 rgba(196, 167, 251, 0.4))
			drop-shadow(-2px 1px rgba(0, 160, 255, 0.3))
			brightness(1.15);
	}
}

/* ── Short viewports (13–14" laptops) ─────────────────────────
   main.css shrinks .zp-home__art on short screens so the Pac-Man planets
   strip is not clipped by the bottom edge. Here the art is sized by its tilt
   wrapper instead, so the wrapper must shrink in step — otherwise the image
   shrinks inside a 524px box and sits off-centre. This file loads after
   main.css, so these values win. Keep the two in sync. */
@media (max-height: 900px) {
	.zp-test .zp-home__art-wrap { max-width: 460px; }
}

@media (max-height: 760px) {
	.zp-test .zp-home__art-wrap { max-width: 400px; }
}
