/*
 * pp-dynamic.css — Pasta & Panda Cinematic
 * Motion + interaction presentation layer.
 * Loaded FRONT-END ONLY — never in the block editor.
 *
 * Index:
 *   §0  CSS custom property registrations (@property)
 *   §1  Per-continent accent system (B1)
 *   §2  Time-of-day background tint (B6)
 *   §3  Film grain overlay (A1)
 *   §4  Letterbox bars (A1)
 *   §5  Custom cursor + ring (B5) — pointer:fine only
 *   §6  Cursor spotlight (B2)
 *   §7  Card sheen ::after (B3)
 *   §8  Focus-pull on card grids (A2)
 *   §9  Scroll text reveal utility (B7)
 *   §10 Scroll ruler (A3)
 *   §11 Mono ticker strip (B9)
 *   §12 Micro-polish (B10)
 *   §13 Header progressive blur (B10)
 *   §14 Stat counter animation (B8)
 *   §15 Responsive / reduced-motion guards
 */

/* ── §0 · @property registrations ───────────────────────────────────────── */

/*
 * Register --pp-accent as <color> so CSS can transition it between continents.
 * NOTE: --pp-rec and --pp-rec-text are NOT registered here — they are static.
 */
@property --pp-accent {
	syntax: '<color>';
	inherits: true;
	initial-value: #E08B3E;
}

/* Spotlight position as registered numbers so CSS transition creates the lag */
@property --sx {
	syntax: '<number>';
	inherits: true;
	initial-value: 0.5;
}

@property --sy {
	syntax: '<number>';
	inherits: true;
	initial-value: 0.5;
}

/* Stat counter animated integer */
@property --stat-num {
	syntax: '<integer>';
	inherits: false;
	initial-value: 0;
}

/* ── §1 · Per-continent accent colours (B1) ──────────────────────────────── */
/*
 * Override --pp-accent per continent body class.
 * Default / Europe stays amber — the brand baseline.
 *
 * EXCLUSION: --pp-rec and --pp-rec-text are never touched here.
 */
:root,
body.pp-continent-default,
body.pp-continent-europe   { --pp-accent: #E08B3E; } /* amber */
body.pp-continent-asia     { --pp-accent: #4E9E86; } /* jade */
body.pp-continent-africa   { --pp-accent: #C4622D; } /* terracotta */
body.pp-continent-americas { --pp-accent: #C7566E; } /* rose */
body.pp-continent-oceania  { --pp-accent: #3E86A8; } /* deep cyan */

/* Animate accent transitions on same-page class changes */
body {
	transition: --pp-accent 600ms ease;
}

/* Spotlight lag: CSS transitions the registered numbers instead of JS lerp */
:root {
	transition: --sx 120ms ease, --sy 120ms ease;
}

/* ── §2 · Time-of-day background tint (B6) ───────────────────────────────── */
/*
 * All tints are small percentages. Contrast ratio cream (#EFEAE0) on ink
 * starts at ~11:1, well above the 4.5:1 minimum — tiny tints cannot drop it.
 */
body.pp-dawn  { background-color: color-mix(in oklch, var(--pp-ink) 91%, #8B5A2B 9%); }
body.pp-day   { /* default — no override needed */ }
body.pp-dusk  { background-color: color-mix(in oklch, var(--pp-ink) 91%, #5B2B5B 9%); }
body.pp-night { background-color: color-mix(in oklch, var(--pp-ink) 92%, #0A1525 8%); }

/* ── §3 · Film grain overlay (A1) ────────────────────────────────────────── */
/*
 * SVG feTurbulence rendered as a tiled background image.
 * mix-blend-mode: overlay at 5% opacity is barely visible but adds texture.
 * Animation steps background-position through 8 frames (NOT opacity/filter).
 * Animation is disabled below 900 px and on prefers-reduced-motion.
 */
.pp-grain {
	position: fixed;
	inset: 0;
	z-index: 998;
	pointer-events: none;
	mix-blend-mode: overlay;
	opacity: 0.05;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
	background-size: 200px 200px;
	background-repeat: repeat;
}

@keyframes pp-grain-step {
	0%    { background-position:   0px   0px; }
	100%  { background-position: 400px 300px; }
}

/* ── §4 · Letterbox bars (A1) ────────────────────────────────────────────── */
.pp-lb {
	position: fixed;
	left: 0;
	right: 0;
	z-index: 997;
	pointer-events: none;
	background: var(--pp-ink);
	height: 28px;
	/* Entrance: animate from height 0 on load */
	transform: scaleY(0);
	transform-origin: top center;
}

.pp-lb--top {
	top: 0;
	transform-origin: top center;
	border-bottom: 1px solid var(--pp-rule);
}

.pp-lb--bottom {
	bottom: 0;
	transform-origin: bottom center;
	border-top: 1px solid var(--pp-rule);
}

/* .pp-cinematic-bars body class requests thicker 56px bars */
body.pp-cinematic-bars .pp-lb { height: 56px; }

@media (prefers-reduced-motion: no-preference) {
	@keyframes pp-lb-in {
		from { transform: scaleY(0); }
		to   { transform: scaleY(1); }
	}

	.pp-lb--top    { animation: pp-lb-in 500ms cubic-bezier(0.16, 1, 0.3, 1) both; }
	.pp-lb--bottom { animation: pp-lb-in 500ms cubic-bezier(0.16, 1, 0.3, 1) 80ms both; }

	@media (min-width: 900px) {
		.pp-grain {
			animation: pp-grain-step 0.6s steps(8, end) infinite;
		}
	}
}

/* Letterbox only on desktop */
@media (max-width: 899px) {
	.pp-lb { display: none; }
}

/* ── §5 · Custom cursor ring + dot (B5) ──────────────────────────────────── */
/*
 * Scoped entirely to pointer:fine so touch/stylus devices are unaffected.
 * cursor:none on the whole page, native cursor restored on text inputs.
 */
@media (pointer: fine) {
	* { cursor: none !important; }
	input, textarea, select { cursor: text !important; }

	.pp-cursor-ring {
		position: fixed;
		inset: 0 auto auto 0;
		z-index: 9999;
		width: 22px;
		height: 22px;
		border: 1px solid var(--pp-accent);
		border-radius: 50%;
		pointer-events: none;
		/* JS sets transform: translate(x, y) translate(-50%, -50%) */
		display: flex;
		align-items: center;
		justify-content: center;
		/* Contextual transitions */
		transition:
			width        300ms cubic-bezier(0.16, 1, 0.3, 1),
			height       300ms cubic-bezier(0.16, 1, 0.3, 1),
			background   200ms ease,
			border-color 200ms ease,
			opacity      200ms ease;
		will-change: transform;
	}

	.pp-cursor-ring[data-state="card"] {
		width: 64px;
		height: 64px;
	}

	.pp-cursor-ring[data-state="play"] {
		width: 64px;
		height: 64px;
		border-color: color-mix(in oklch, var(--pp-accent) 80%, white);
	}

	.pp-cursor-ring[data-state="link"] {
		width: 12px;
		height: 12px;
		background: var(--pp-accent);
		border-color: var(--pp-accent);
	}

	.pp-cursor-ring[data-state="text"] {
		width: 2px;
		height: 22px;
		border-radius: 1px;
		background: var(--pp-accent);
		border: none;
	}

	.pp-cursor-label {
		font-family: var(--pp-font-mono, monospace);
		font-size: 0.5625rem;
		letter-spacing: 0.1em;
		color: var(--pp-accent);
		text-transform: uppercase;
		white-space: nowrap;
		pointer-events: none;
		user-select: none;
	}

	.pp-cursor-dot {
		position: fixed;
		inset: 0 auto auto 0;
		z-index: 9999;
		width: 4px;
		height: 4px;
		background: var(--pp-accent);
		border-radius: 50%;
		pointer-events: none;
		will-change: transform;
		/* dot tracks the real position without lerp — set directly in JS */
	}
}

/* ── §6 · Cursor spotlight (B2) ──────────────────────────────────────────── */
/*
 * Radial gradient centred at --sx/--sy (lagged positions).
 * CSS transitions on --sx/--sy (registered @property) provide the 120ms lag.
 */
@media (pointer: fine) {
	.pp-spotlight {
		position: fixed;
		inset: 0;
		z-index: 996;
		pointer-events: none;
		mix-blend-mode: soft-light;
		background: radial-gradient(
			600px circle at calc(var(--sx, 0.5) * 100%) calc(var(--sy, 0.5) * 100%),
			color-mix(in oklch, var(--pp-accent) 6%, transparent),
			transparent 100%
		);
	}
}

/* ── §7 · Card sheen — ::after radial highlight (B3) ─────────────────────── */
/*
 * The card ::after element follows the cursor via --cx/--cy set per-card in JS.
 * data-hover="1" is set/removed by the global pointer listener.
 */
@media (pointer: fine) {
	.pp-card,
	.pp-case-card {
		position: relative;
	}

	.pp-card::after,
	.pp-case-card::after {
		content: '';
		position: absolute;
		inset: 0;
		z-index: 1;
		background: radial-gradient(
			180px circle at calc(var(--cx, 0.5) * 100%) calc(var(--cy, 0.5) * 100%),
			color-mix(in oklch, var(--pp-accent) 10%, transparent),
			transparent 100%
		);
		opacity: 0;
		pointer-events: none;
		transition: opacity 300ms ease;
	}

	.pp-card[data-hover="1"]::after,
	.pp-case-card[data-hover="1"]::after {
		opacity: 1;
	}
}

/* ── §8 · Focus-pull on card grids (A2) ──────────────────────────────────── */
/*
 * Uses :has() to dim non-hovered cards when any card is hovered.
 * Also responds to :focus-within for keyboard users.
 * Applied to .pp-card-grid (films/posts) and .pp-case-grid (case studies).
 */
@media (prefers-reduced-motion: no-preference) {
	.pp-card-grid .pp-card,
	.pp-case-grid .pp-case-card {
		transition:
			filter    450ms cubic-bezier(0.16, 1, 0.3, 1),
			opacity   450ms cubic-bezier(0.16, 1, 0.3, 1),
			transform 450ms cubic-bezier(0.16, 1, 0.3, 1);
	}

	/* Dim siblings when one card is hovered */
	.pp-card-grid:has(.pp-card:hover) .pp-card:not(:hover),
	.pp-card-grid:has(.pp-card:focus-within) .pp-card:not(:focus-within),
	.pp-case-grid:has(.pp-case-card:hover) .pp-case-card:not(:hover),
	.pp-case-grid:has(.pp-case-card:focus-within) .pp-case-card:not(:focus-within) {
		filter: blur(3px) saturate(0.55) brightness(0.7);
		opacity: 0.5;
		transform: scale(0.985);
	}

	/* Lift the active card */
	.pp-card-grid .pp-card:hover,
	.pp-card-grid .pp-card:focus-within,
	.pp-case-grid .pp-case-card:hover,
	.pp-case-grid .pp-case-card:focus-within {
		filter: none;
		transform: scale(1.015);
	}
}

/* ── §9 · Scroll text reveal — .pp-reveal utility (B7) ──────────────────── */
/*
 * Pure CSS using animation-timeline: view().
 * Elements rise 24px and fade in as they enter the viewport.
 * Static fallback: elements are always visible (no initial hidden state).
 */
@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.pp-reveal,
		.pp-section__heading,
		.pp-archive__title,
		.pp-article__title,
		.pp-film-title,
		.pp-404__headline,
		.pp-stats-hud .pp-stat {
			animation: pp-view-reveal linear both;
			animation-timeline: view();
			animation-range: entry 10% cover 35%;
		}

		@keyframes pp-view-reveal {
			from {
				opacity: 0;
				transform: translateY(24px);
			}
			to {
				opacity: 1;
				transform: translateY(0);
			}
		}
	}
}

/* ── §10 · Scroll ruler (A3) ─────────────────────────────────────────────── */
.pp-scroll-ruler {
	position: fixed;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	z-index: 900;
	width: 32px;
	pointer-events: none;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
}

.pp-ruler__track {
	position: relative;
	width: 1px;
	height: 200px;
	background: var(--pp-rule);
	overflow: hidden;
}

.pp-ruler__fill {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 100%;
	background: var(--pp-accent);
	transform: scaleY(0);
	transform-origin: top center;
}

/* CSS scroll-driven animation where supported */
@supports (animation-timeline: scroll()) {
	@media (prefers-reduced-motion: no-preference) {
		.pp-ruler__fill {
			animation: pp-ruler-progress linear both;
			animation-timeline: scroll(root block);
			animation-range: 0% 100%;
		}

		@keyframes pp-ruler-progress {
			from { transform: scaleY(0); }
			to   { transform: scaleY(1); }
		}
	}
}

.pp-ruler__ticks {
	position: absolute;
	inset: 0;
	/* Tick marks are injected by pp-timeline.js */
}

.pp-ruler__tick {
	position: absolute;
	left: 0;
	right: 0;
	height: 1px;
	background: var(--pp-accent);
	opacity: 0.4;
}

.pp-ruler__section {
	font-family: var(--pp-font-mono, monospace);
	font-size: 0.5625rem;
	letter-spacing: 0.12em;
	color: var(--pp-accent);
	text-transform: uppercase;
	writing-mode: vertical-rl;
	white-space: nowrap;
	opacity: 0;
	transition: opacity 400ms ease;
	max-height: 120px;
	overflow: hidden;
}

.pp-ruler__section.is-active {
	opacity: 1;
}

.pp-ruler__time {
	font-family: var(--pp-font-mono, monospace);
	font-size: 0.5625rem;
	letter-spacing: 0.08em;
	color: var(--pp-cream-70, rgba(239,234,224,.70));
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum";
}

/* ── §11 · Mono ticker strip (B9) ────────────────────────────────────────── */
.pp-ticker-wrap {
	position: fixed;
	bottom: 28px; /* clears the bottom letterbox */
	left: 0;
	right: 32px;  /* clears the scroll ruler */
	z-index: 995;
	overflow: hidden;
	height: 1.625rem;
	border-top: 1px solid var(--pp-rule);
	border-bottom: 1px solid var(--pp-rule);
	background: color-mix(in oklch, var(--pp-ink) 90%, transparent);
	pointer-events: none;
}

.pp-ticker {
	display: flex;
	width: max-content;
	height: 100%;
	align-items: center;
}

.pp-ticker__inner {
	display: block;
	white-space: nowrap;
	font-family: var(--pp-font-mono, monospace);
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	color: var(--pp-cream-70, rgba(239,234,224,.70));
	text-transform: uppercase;
	padding: 0 3rem; /* breathing room between duplicates */
}

@media (prefers-reduced-motion: no-preference) {
	@keyframes pp-ticker-scroll {
		from { transform: translateX(0); }
		to   { transform: translateX(-50%); }
	}

	.pp-ticker {
		animation: pp-ticker-scroll 35s linear infinite;
	}

	.pp-ticker-wrap:hover .pp-ticker {
		animation-play-state: paused;
	}
}

/* ── §12 · Micro-polish (B10) ────────────────────────────────────────────── */

/* Text selection */
::selection {
	background: var(--pp-accent);
	color: var(--pp-ink, #132A20);
}

/* Scrollbar — accent track, narrow */
::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
	background: color-mix(in oklch, var(--pp-accent) 50%, transparent);
	border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover { background: var(--pp-accent); }
/* Firefox */
* { scrollbar-width: thin; scrollbar-color: var(--pp-accent) transparent; }

/* Focus-visible ring — 2px accent, 3px offset */
:focus-visible {
	outline: 2px solid var(--pp-accent) !important;
	outline-offset: 3px;
	border-radius: 0 !important;
}

/* Mono link underlines: scaleX from left on hover */
a.tc-link,
a.pp-yt-link,
.pp-footer__nav-list a,
.pp-article-nav a,
.pp-article-body a {
	text-underline-offset: 3px;
	text-decoration-thickness: 1px;
}

@media (prefers-reduced-motion: no-preference) {
	a.tc-link,
	a.pp-yt-link,
	.pp-footer__nav-list a {
		text-decoration: none;
		position: relative;
	}

	a.tc-link::after,
	a.pp-yt-link::after,
	.pp-footer__nav-list a::after {
		content: '';
		position: absolute;
		bottom: -1px;
		left: 0;
		right: 0;
		height: 1px;
		background: var(--pp-accent);
		transform: scaleX(0);
		transform-origin: left center;
		transition: transform 250ms cubic-bezier(0.16, 1, 0.3, 1);
	}

	a.tc-link:hover::after,
	a.pp-yt-link:hover::after,
	.pp-footer__nav-list a:hover::after {
		transform: scaleX(1);
	}
}

/* ── §13 · Header progressive blur (B10) ─────────────────────────────────── */
/*
 * CSS scroll-driven approach: blur increases over the first 80px of scroll.
 * Falls back to a JS-toggled class (.pp-header--scrolled) added in pp-timeline.js.
 */
.pp-header {
	backdrop-filter: blur(0px);
	-webkit-backdrop-filter: blur(0px);
}

@supports (animation-timeline: scroll()) {
	@media (prefers-reduced-motion: no-preference) {
		.pp-header {
			animation: pp-header-blur linear;
			animation-timeline: scroll(root block);
			animation-range: 0px 80px;
			animation-fill-mode: both;
		}

		@keyframes pp-header-blur {
			from {
				backdrop-filter: blur(0px);
				-webkit-backdrop-filter: blur(0px);
				background-color: var(--pp-ink);
			}
			to {
				backdrop-filter: blur(12px);
				-webkit-backdrop-filter: blur(12px);
				background-color: color-mix(in oklch, var(--pp-ink) 82%, transparent);
			}
		}
	}
}

/* JS fallback class */
.pp-header--scrolled {
	backdrop-filter: blur(12px);
	-webkit-backdrop-filter: blur(12px);
	background-color: color-mix(in oklch, var(--pp-ink) 82%, transparent) !important;
}

/* ── §14 · Stat counter animation (B8) ───────────────────────────────────── */
/*
 * IntersectionObserver in pp-pointer.js adds .pp-stat--counting.
 * The @property --stat-num animation is declared; JS also runs a
 * number count-up for browsers that need content updates.
 */
.pp-stat__value {
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum";
}

@media (prefers-reduced-motion: no-preference) {
	@keyframes pp-stat-count {
		from { --stat-num: 0; }
		to   { --stat-num: var(--stat-target, 100); }
	}

	.pp-stat--counting {
		animation: pp-stat-count 1.4s cubic-bezier(0, 0, 0.2, 1) both;
	}
}

/* ── §15 · Responsive + reduced-motion guards ────────────────────────────── */

/* Hide ruler and ticker on narrow screens */
@media (max-width: 1099px) {
	.pp-scroll-ruler,
	.pp-ticker-wrap { display: none; }

	/* Adjust ticker right offset since ruler is hidden */
	.pp-ticker-wrap { right: 0; }
}

@media (max-width: 899px) {
	/* Grain animation off — battery cost */
	.pp-grain { animation: none !important; }
	/* Letterbox off */
	.pp-lb { display: none !important; }
}

/* Hard disable all dynamic overlays for reduced-motion */
@media (prefers-reduced-motion: reduce) {
	.pp-grain          { animation: none !important; }
	.pp-cursor-ring,
	.pp-cursor-dot     { display: none !important; }
	.pp-spotlight      { display: none !important; }
	.pp-scroll-ruler   { display: none !important; }
	.pp-ticker-wrap    { display: none !important; }
	.pp-lb             { animation: none !important; transform: scaleY(1); }
}
