/* ==========================================================================
   Hanuman Sena — effects.css  (behaviour + motion layer)
   Powers assets/js/main.js · animations.js · gallery-lightbox.js · models.js

   Rules of this file
   - Hidden / initial states exist ONLY under html.hs-js (set inline in <head>), and every one
     of them has a failsafe: if main.js never boots (html.hs-ready missing) everything reveals
     itself after 2.5 s. No-JS visitors never see a hidden state at all.
   - Reveals are CSS *animations with a backwards fill*: when they finish, the element simply
     falls back to its own natural styles — no stale transform/opacity, no clash with hover rules.
   - Individual transform properties (translate / scale / rotate) are used for reveals, float,
     Ken Burns and pointer depth so GSAP's `transform` (parallax, tilt) and component hover
     transforms keep composing instead of fighting.
   - Feel: ceremonial. Reveal 700–1000 ms, travel 24–48 px, hover 180–240 ms, no bounce, no spin.
   - Component skins (.card, .btn, .media-slot*, header/footer, forms) belong to components.css/site.css/forms.css.

   Hooks set by JS (all on elements, never inline design):
     html            hs-js · hs-ready · hs-motion · hs-reduced · hs-touch · lenis      body.is-locked
     reveal          .is-revealed  .is-reveal-instant   --rv-delay --rv-dur --rv-dist
     split           .is-split  .split-line > .split-line__inner (words: .split-line.split-word)  --i
     scroll          [data-scroll-progress] --progress · #back-to-top .is-visible --progress · .site-header.is-scrolled
     scrolly/hscroll [data-scrolly] data-active --scrolly-progress · [data-hscroll].is-hscroll-active --hscroll-progress
     marquee         .marquee.is-ready  --marquee-dur --marquee-n  .is-paused  .is-offscreen
     lightbox        .lb (.is-open / .is-closing)   model  .is-model-loading|ready|error
   ========================================================================== */


/* ==========================================================================
   0. SCROLLTRIGGER SAFETY
   ScrollTrigger measures start/end by resetting the scroll position. With CSS `scroll-behavior: smooth` that reset
   animates, every trigger is measured mid-scroll and lands thousands of px off (seen on touch devices, where Lenis
   — which forces `auto` — is not running). main.js scrolls to anchors with an explicit `behavior`, so the CSS
   default is not needed while the motion layer is alive. (html.hs-motion is only set when GSAP booted.)
   ========================================================================== */
html.hs-motion {
	scroll-behavior: auto;
}


/* ==========================================================================
   1. REVEAL ON SCROLL   data-reveal · data-stagger · data-hero-item
   ========================================================================== */
html.hs-js [data-reveal]:not(.is-revealed),
html.hs-js [data-stagger] > *:not(.is-revealed),
html.hs-js [data-hero-item]:not([data-split]):not(.is-revealed) {
	opacity: 0;
	translate: 0 var(--rv-dist, 32px);
}

html.hs-js [data-reveal="down"]:not(.is-revealed) { translate: 0 calc(var(--rv-dist, 32px) * -1); }
html.hs-js [data-reveal="left"]:not(.is-revealed) { translate: calc(var(--rv-dist, 32px) * -1) 0; }
html.hs-js [data-reveal="right"]:not(.is-revealed) { translate: var(--rv-dist, 32px) 0; }
html.hs-js [data-reveal="fade"]:not(.is-revealed) { translate: none; }
html.hs-js [data-reveal="zoom"]:not(.is-revealed) { translate: none; scale: 0.94; }
html.hs-js [data-reveal="blur"]:not(.is-revealed) {
	translate: 0 calc(var(--rv-dist, 32px) * 0.4);
	filter: blur(14px);
}
/* Wipes: the box stays "visible" but is clipped to nothing (negative insets keep shadows/glows after the wipe). */
html.hs-js [data-reveal="mask-x"]:not(.is-revealed) {
	opacity: 1;
	translate: none;
	clip-path: inset(-24px 100% -24px 0);
}
html.hs-js [data-reveal="mask-y"]:not(.is-revealed) {
	opacity: 1;
	translate: none;
	clip-path: inset(100% -24px -24px -24px);
}

/* The reveal itself. `backwards` fill = hidden during the delay, natural afterwards. */
html.hs-js :where([data-reveal], [data-stagger] > *, [data-hero-item]):not([data-split]).is-revealed {
	animation: hs-rv-up var(--rv-dur, 900ms) var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) var(--rv-delay, 0ms) backwards;
}
html.hs-js [data-reveal="down"].is-revealed { animation-name: hs-rv-down; }
html.hs-js [data-reveal="left"].is-revealed { animation-name: hs-rv-left; }
html.hs-js [data-reveal="right"].is-revealed { animation-name: hs-rv-right; }
html.hs-js [data-reveal="fade"].is-revealed { animation-name: hs-rv-fade; }
html.hs-js [data-reveal="zoom"].is-revealed { animation-name: hs-rv-zoom; }
html.hs-js [data-reveal="blur"].is-revealed { animation-name: hs-rv-blur; }
html.hs-js [data-reveal="mask-x"].is-revealed { animation-name: hs-rv-mask-x; animation-timing-function: var(--ease-in-out, cubic-bezier(0.65, 0, 0.35, 1)); }
html.hs-js [data-reveal="mask-y"].is-revealed { animation-name: hs-rv-mask-y; animation-timing-function: var(--ease-in-out, cubic-bezier(0.65, 0, 0.35, 1)); }

/* Already-scrolled-past content (back navigation, deep links): never leave it hidden, never replay it. */
html.hs-js .is-reveal-instant,
html.hs-js .is-reveal-instant .split-line__inner {
	animation: none !important;
}

@keyframes hs-rv-up { from { opacity: 0; translate: 0 var(--rv-dist, 32px); } }
@keyframes hs-rv-down { from { opacity: 0; translate: 0 calc(var(--rv-dist, 32px) * -1); } }
@keyframes hs-rv-left { from { opacity: 0; translate: calc(var(--rv-dist, 32px) * -1) 0; } }
@keyframes hs-rv-right { from { opacity: 0; translate: var(--rv-dist, 32px) 0; } }
@keyframes hs-rv-fade { from { opacity: 0; } }
@keyframes hs-rv-zoom { from { opacity: 0; scale: 0.94; } }
@keyframes hs-rv-blur { from { opacity: 0; translate: 0 calc(var(--rv-dist, 32px) * 0.4); filter: blur(14px); } }
@keyframes hs-rv-mask-x {
	from { clip-path: inset(-24px 100% -24px 0); }
	to { clip-path: inset(-24px -24px -24px -24px); }
}
@keyframes hs-rv-mask-y {
	from { clip-path: inset(100% -24px -24px -24px); }
	to { clip-path: inset(-24px -24px -24px -24px); }
}

/* Image "settles" while its mask opens: 1.12 → 1 (individual `scale`, composes with hover transforms). */
html.hs-js .media-slot[data-reveal^="mask"].is-revealed .media-slot__media {
	animation: hs-img-settle calc(var(--rv-dur, 900ms) * 1.35) var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) var(--rv-delay, 0ms) backwards;
}
@keyframes hs-img-settle { from { scale: 1.12; } }

/* Failsafe: scripts never booted → reveal everything after 2.5 s. */
html.hs-js:not(.hs-ready) :is([data-reveal], [data-stagger] > *, [data-hero-item], [data-split]):not(.is-revealed) {
	animation: hs-failsafe 0.01s linear 2.5s forwards;
}
@keyframes hs-failsafe {
	to { opacity: 1; translate: none; scale: none; filter: none; clip-path: none; visibility: visible; }
}


/* ==========================================================================
   2. HERO INTRO   data-hero · data-hero-item · .hero__sweep
   Items reuse the reveal keyframes (main.js sets --rv-delay = 120 ms × index). One-time light sweep.
   ========================================================================== */
.hero__sweep {
	position: absolute;
	inset: 0;
	z-index: 1;
	overflow: hidden;
	pointer-events: none;
}

.hero__sweep::before {
	content: '';
	position: absolute;
	top: -10%;
	bottom: -10%;
	left: 0;
	width: 46%;
	opacity: 0;
	translate: -120% 0;
	transform: skewX(-16deg);
	background: linear-gradient(
		100deg,
		transparent 0%,
		rgba(255, 154, 77, 0.1) 30%,
		rgba(255, 206, 150, 0.24) 50%,
		rgba(255, 154, 77, 0.1) 70%,
		transparent 100%
	);
	mix-blend-mode: screen;
}

[data-hero].is-hero-in .hero__sweep::before {
	animation: hs-sweep 2400ms var(--ease-in-out, cubic-bezier(0.65, 0, 0.35, 1)) 500ms 1 both;
}

@keyframes hs-sweep {
	0% { translate: -120% 0; opacity: 0; }
	15% { opacity: 1; }
	85% { opacity: 1; }
	100% { translate: 320% 0; opacity: 0; }
}


/* ==========================================================================
   3. SPLIT HEADINGS   data-split="lines|words"
   Each line/word lives in an overflow mask; the padding/negative-margin pair gives ascenders,
   descenders and Devanagari matras room so nothing is clipped while the layout stays identical.
   ========================================================================== */
html.hs-js [data-split]:not(.is-split) {
	visibility: hidden;
}

.split-line {
	display: block;
	overflow: hidden;
	padding: 0.16em 0 0.24em;
	margin: -0.16em 0 -0.24em;
}

.split-line.split-word {
	display: inline-block;
	vertical-align: top;
}

.split-line__inner {
	display: block;
}

.split-line.split-word > .split-line__inner {
	display: inline-block;
}

html.hs-js [data-split].is-split:not(.is-revealed) .split-line__inner {
	translate: 0 120%;
}

html.hs-js [data-split].is-split.is-revealed .split-line__inner {
	animation: hs-line-in var(--rv-dur, 1000ms) var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1))
		calc(var(--rv-delay, 0ms) + var(--i, 0) * var(--split-stagger, 90ms)) backwards;
}

html.hs-js [data-split="words"].is-split.is-revealed .split-line__inner {
	--split-stagger: 55ms;
}

/* After a width-change re-split of an already revealed heading: rebuild silently. */
html.hs-js [data-split].is-split-static .split-line__inner {
	animation: none !important;
}

@keyframes hs-line-in { from { translate: 0 120%; } }


/* ==========================================================================
   4. COUNTERS   data-counter — tabular figures so the number does not jitter while it counts
   ========================================================================== */
[data-counter] {
	font-variant-numeric: tabular-nums lining-nums;
}

span[data-counter] {
	display: inline-block;
}


/* ==========================================================================
   5. FLOAT · KEN BURNS · PARALLAX · POINTER DEPTH
   ========================================================================== */
[data-float] {
	animation: hs-float 7s ease-in-out infinite;
}

@keyframes hs-float {
	0%, 100% { translate: 0 0; }
	50% { translate: 0 calc(var(--float-amp, 10px) * -1); }
}

/* Ken Burns: 1.00 → 1.04 over ~24 s, on the media wrapper (never on both wrapper and <img>). */
[data-ken-burns] .media-slot__inner,
[data-ken-burns].media-slot__inner,
[data-ken-burns] > img,
[data-ken-burns] > picture,
[data-ken-burns] > video,
img[data-ken-burns],
video[data-ken-burns] {
	animation: hs-kenburns 24s ease-in-out infinite alternate;
	transform-origin: 50% 55%;
}

@keyframes hs-kenburns {
	from { scale: 1; }
	to { scale: 1.04; }
}

/* Parallax media: components.css oversizes `.media-slot__inner[data-parallax]` vertically (inset: -9% 0 → ±9 % of the
   frame), animations.js caps the travel to that room. Horizontal parallax needs the same room sideways. */
@media (min-width: 768px) and (prefers-reduced-motion: no-preference) {
	html.hs-js:not(.hs-reduced) .media-slot__inner[data-parallax][data-parallax-axis="x"] {
		inset: 0 -9%;
		width: auto;
	}

	html.hs-js:not(.hs-reduced) .media-slot__inner[data-parallax] {
		will-change: transform;
	}
}

/* Pointer parallax: JS writes --dx / --dy (px) on every [data-depth] child of [data-pointer]. */
[data-pointer] [data-depth] {
	translate: var(--dx, 0px) var(--dy, 0px);
	will-change: translate;
}

/* Scroll-draw + progress line: only hidden while the motion layer is running (never without it, never under reduced motion). */
html.hs-motion:not(.hs-reduced) [data-draw]:not([data-draw-ready]) {
	opacity: 0;
}

html.hs-motion:not(.hs-reduced) [data-progress-line] {
	transform: scaleY(var(--progress, 0));
	transform-origin: 50% 0;
}

/* Horizontal lines (process steps): same --progress engine, drawn left → right. */
html.hs-motion:not(.hs-reduced) .steps__line > [data-progress-line],
html.hs-motion:not(.hs-reduced) [data-progress-line][data-progress-axis='x'] {
	transform: scaleX(var(--progress, 0));
	transform-origin: 0 50%;
}

/* ==========================================================================
   6. SCROLL PROGRESS BAR + BACK TO TOP
   ========================================================================== */
[data-scroll-progress] {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	height: 3px;
	z-index: var(--z-progress, 500);
	pointer-events: none;
	transform-origin: 0 50%;
	transform: scaleX(var(--progress, 0));
	background: linear-gradient(90deg, var(--saffron, #f47a1f), var(--antique-gold, #d9a441));
	box-shadow: 0 0 14px rgba(244, 122, 31, 0.45);
}

/* Markup variant with an inner bar (main.js adds .has-bar): the wrapper becomes a plain track. */
[data-scroll-progress].has-bar {
	transform: none;
	background: none;
	box-shadow: none;
}

[data-scroll-progress] > .scroll-progress__bar {
	display: block;
	height: 100%;
	transform-origin: 0 50%;
	transform: scaleX(var(--progress, 0));
	background: linear-gradient(90deg, var(--saffron, #f47a1f), var(--antique-gold, #d9a441));
	box-shadow: 0 0 14px rgba(244, 122, 31, 0.45);
}

.back-to-top {
	position: fixed;
	right: max(16px, env(safe-area-inset-right));
	bottom: max(16px, env(safe-area-inset-bottom));
	z-index: var(--z-header, 100);
	display: grid;
	place-items: center;
	width: 48px;
	height: 48px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: rgba(21, 16, 13, 0.82);
	color: var(--warm-ivory, #f6ebdd);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	box-shadow: 0 14px 36px -16px rgba(0, 0, 0, 0.85);
	text-decoration: none;
	cursor: pointer;
	opacity: 0;
	visibility: hidden;
	translate: 0 14px;
	transition: opacity 320ms var(--ease-out, ease), translate 320ms var(--ease-out, ease), visibility 0s linear 320ms,
		color 200ms ease, background-color 200ms ease;
}

.back-to-top.is-visible {
	opacity: 1;
	visibility: visible;
	translate: 0 0;
	transition: opacity 320ms var(--ease-out, ease), translate 320ms var(--ease-out, ease), visibility 0s,
		color 200ms ease, background-color 200ms ease;
}

.back-to-top:hover {
	color: var(--saffron-bright, #ff9a4d);
	background-color: rgba(38, 28, 22, 0.92);
}

.back-to-top > svg:not(.back-to-top__ring) {
	transition: translate 220ms var(--ease-out, ease);
}

.back-to-top:hover > svg:not(.back-to-top__ring) {
	translate: 0 -3px;
}

/* Default ring when the markup has no SVG ring (main.js adds .has-ring otherwise): conic gradient driven by --progress (0–1), cut to a 2px stroke. */
.back-to-top:not(.has-ring)::before {
	content: '';
	position: absolute;
	inset: 0;
	padding: 2px;
	border-radius: 50%;
	background: conic-gradient(var(--saffron, #f47a1f) calc(var(--progress, 0) * 360deg), rgba(246, 235, 221, 0.16) 0);
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
	pointer-events: none;
}

/* Optional SVG ring: <svg class="back-to-top__ring"><circle class="back-to-top__track" …/><circle class="back-to-top__bar" pathLength="1" …/></svg> */
.back-to-top__ring {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	rotate: -90deg;
	pointer-events: none;
}

.back-to-top__track {
	fill: none;
	stroke: rgba(246, 235, 221, 0.16);
	stroke-width: 2;
}

.back-to-top__bar {
	fill: none;
	stroke: var(--saffron, #f47a1f);
	stroke-width: 2;
	stroke-linecap: round;
	stroke-dasharray: 1;
	stroke-dashoffset: calc(1 - var(--progress, 0));
}


/* ==========================================================================
   7. MARQUEE   data-marquee — static + wrapped without JS / under reduced motion
   JS clones the items (aria-hidden + inert) and sets --marquee-n (copies) and --marquee-dur (s).
   Each item carries its own trailing gap (not flex gap) so the loop distance is exactly one set.
   ========================================================================== */
.marquee {
	--marquee-gap: clamp(2rem, 5vw, 4rem);
	position: relative;
	overflow: hidden;
}

.marquee__track {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 1rem var(--marquee-gap);
}

.marquee__item {
	flex: 0 0 auto;
}

html.hs-js .marquee.is-ready {
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
	mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}

html.hs-js .marquee.is-ready .marquee__track {
	flex-wrap: nowrap;
	justify-content: flex-start;
	gap: 0;
	width: max-content;
	animation: hs-marquee var(--marquee-dur, 40s) linear infinite;
	will-change: transform;
}

html.hs-js .marquee.is-ready .marquee__item {
	margin-inline-end: var(--marquee-gap);
}

html.hs-js .marquee--right.is-ready .marquee__track {
	animation-direction: reverse;
}

html.hs-js .marquee.is-ready:hover .marquee__track,
html.hs-js .marquee.is-ready:focus-within .marquee__track,
html.hs-js .marquee.is-ready.is-paused .marquee__track,
html.hs-js .marquee.is-ready.is-offscreen .marquee__track {
	animation-play-state: paused;
}

@keyframes hs-marquee {
	to { transform: translate3d(calc(-100% / var(--marquee-n, 2)), 0, 0); }
}

/* WCAG 2.2.2 pause control: only visible on hover / keyboard focus; tapping the strip also toggles it. */
.marquee__toggle {
	position: absolute;
	top: 50%;
	inset-inline-end: 8px;
	z-index: 2;
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1px solid var(--line-strong, rgba(155, 138, 125, 0.42));
	border-radius: 50%;
	background: rgba(11, 9, 7, 0.82);
	color: var(--warm-ivory, #f6ebdd);
	translate: 0 -50%;
	opacity: 0;
	transition: opacity 200ms ease;
}

.marquee:hover .marquee__toggle,
.marquee__toggle:focus-visible {
	opacity: 1;
}

.marquee__toggle::before {
	content: '';
	width: 10px;
	height: 12px;
	border-inline: 3px solid currentColor;
}

.marquee__toggle[aria-pressed="true"]::before {
	width: 0;
	height: 0;
	border: 0;
	border-block: 7px solid transparent;
	border-inline-start: 12px solid currentColor;
}


/* ==========================================================================
   8. TOAST   main.js creates <div class="toast hs-toast" role="status" aria-live="polite"> (copy-link, share, errors).
   The skin (.toast, .toast.is-visible) lives in blocks.css; only the error variant is added here.
   ========================================================================== */
.toast.is-error {
	border-color: rgba(183, 52, 32, 0.75);
}


/* ==========================================================================
   9. FUNCTIONAL BASELINES for the JS widgets (skins live in components.css / blocks.css / forms.css)
   The accordion's grid-rows 0fr → 1fr mechanism is in blocks.css (main.js only toggles .is-open + aria-expanded).
   ========================================================================== */
/* Form error slot created by main.js when the markup has no [data-error-for] line: always visible. */
.field__error.is-shown {
	display: block;
}

/* Tabs: the panel that just became visible fades up a little (not on first paint). */
[data-tabs].is-interacted > [role="tabpanel"]:not([hidden]),
[data-tabs].is-interacted [role="tabpanel"]:not([hidden]) {
	animation: hs-tab-in 320ms var(--ease-out, ease) both;
}

@keyframes hs-tab-in { from { opacity: 0; translate: 0 10px; } }

/* Filter chips: 250 ms fade/scale; `.is-filtering` exists only while a change is in flight so
   component transitions (card hover) are never overridden permanently. */
[data-filter-list].is-filtering > [data-filter-item] {
	transition: opacity 250ms var(--ease-out, ease), scale 250ms var(--ease-out, ease);
}

[data-filter-item].is-filtered-out {
	opacity: 0;
	scale: 0.96;
	pointer-events: none;
}

[data-loadmore].is-loading {
	pointer-events: none;
	opacity: 0.7;
	cursor: progress;
}

[data-hs-form].is-sending {
	cursor: progress;
}

[data-donate-submit][aria-disabled="true"] {
	opacity: 0.5;
	pointer-events: none;
}


/* ==========================================================================
   10. TILT + GLARE   data-tilt · data-tilt-glare  (fine pointers; JS adds .is-tilting)
   ========================================================================== */
[data-tilt].is-tilting {
	transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
	transition: transform 180ms var(--ease-out, ease);
	will-change: transform;
}

[data-tilt].is-tilting.is-tilt-return {
	transition: transform 650ms var(--ease-out, ease);
}

.tilt-host {
	position: relative;
}

.tilt-glare {
	position: absolute;
	inset: 0;
	z-index: 2;
	border-radius: inherit;
	pointer-events: none;
	opacity: 0;
	background: radial-gradient(
		circle at var(--glare-x, 50%) var(--glare-y, 50%),
		rgba(255, 200, 140, 0.26),
		rgba(255, 154, 77, 0.08) 38%,
		transparent 62%
	);
	mix-blend-mode: screen;
	transition: opacity 300ms var(--ease-out, ease);
}

[data-tilt].is-tilting:not(.is-tilt-return) > .tilt-glare {
	opacity: 1;
}


/* ==========================================================================
   11. SCROLLYTELLING   data-scrolly — sticky panel + steps (no pin) ≥ 1024px
   ========================================================================== */
.scrolly__sticky {
	display: none;
}

.scrolly__steps {
	display: grid;
	gap: clamp(2rem, 6vw, 4rem);
}

@media (min-width: 1024px) {
	.scrolly {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--gap, 32px) clamp(3rem, 6vw, 7rem);
		align-items: start;
	}

	.scrolly__sticky {
		display: block;
		position: sticky;
		top: calc(var(--header-h, 80px) + 24px);
		align-self: start;
		height: min(72vh, calc(100svh - var(--header-h, 80px) - 48px));
	}

	.scrolly--reverse .scrolly__sticky {
		order: 2;
	}

	.scrolly__steps {
		gap: 0;
	}

	.scrolly__step {
		display: flex;
		flex-direction: column;
		justify-content: center;
		min-height: 72vh;
		opacity: 0.6; /* dimmed but still ≥ 4.5:1 on the dark tones (was 0.45 ≈ 3.9:1) */
		transition: opacity 600ms var(--ease-out, ease);
	}

	.scrolly__step.is-active {
		opacity: 1;
	}

	.scrolly__panel {
		position: absolute;
		inset: 0;
		opacity: 0;
		visibility: hidden;
		translate: 0 16px;
		transition: opacity 600ms var(--ease-out, ease), translate 600ms var(--ease-out, ease), visibility 0s linear 600ms;
	}

	.scrolly__panel.is-active {
		opacity: 1;
		visibility: visible;
		translate: 0 0;
		transition: opacity 600ms var(--ease-out, ease), translate 600ms var(--ease-out, ease), visibility 0s;
	}

	/* If the motion layer is missing, keep the first panel on screen instead of an empty sticky box. */
	html:not(.hs-motion) .scrolly__panel:first-child {
		opacity: 1;
		visibility: visible;
		translate: 0 0;
	}

	html:not(.hs-motion) .scrolly__step {
		opacity: 1;
	}
}


/* ==========================================================================
   12. HORIZONTAL SCROLL   data-hscroll
   < 1024 px / reduced motion: plain vertical stack. ≥ 1024 px: a horizontal track that is
   natively swipeable until animations.js pins the section and takes over (.is-hscroll-active).
   ========================================================================== */
.hscroll__track {
	display: flex;
	flex-direction: column;
	gap: var(--gap, 24px);
}

@media (min-width: 1024px) and (prefers-reduced-motion: no-preference) {
	html.hs-js:not(.hs-reduced) .hscroll__viewport {
		overflow-x: auto;
		overflow-y: hidden;
		overscroll-behavior-x: contain;
		scrollbar-width: thin;
		scroll-snap-type: x proximity;
	}

	html.hs-js:not(.hs-reduced) .hscroll__track {
		flex-direction: row;
		align-items: stretch;
		width: max-content;
		gap: clamp(1.5rem, 3vw, 3rem);
		padding-inline: var(--gutter, 32px);
	}

	html.hs-js:not(.hs-reduced) .hscroll__panel {
		flex: 0 0 min(78vw, 1040px);
		scroll-snap-align: start;
	}

	html.hs-js:not(.hs-reduced) .hscroll.is-hscroll-active {
		display: flex;
		flex-direction: column;
		justify-content: center;
		min-height: 100vh;
		min-height: 100svh;
		overflow: hidden;
	}

	html.hs-js:not(.hs-reduced) .hscroll.is-hscroll-active .hscroll__viewport {
		overflow: hidden;
		scroll-snap-type: none;
	}

	html.hs-js:not(.hs-reduced) .hscroll.is-hscroll-active .hscroll__track {
		will-change: transform;
	}
}


/* ==========================================================================
   13. EMBERS   data-embers — dust/light motes on a canvas (JS draws, pauses offscreen)
   ========================================================================== */
.embers {
	position: absolute;
	inset: 0;
	z-index: 1;
	width: 100%;
	height: 100%;
	pointer-events: none;
}

@media (max-width: 767px) {
	.embers:not([data-embers-mobile]) {
		display: none;
	}
}

/* ==========================================================================
   14. LIGHTBOX   a[data-lightbox] → .lb  (DOM built lazily by gallery-lightbox.js)
   Dark glass backdrop, a sacred corner-bracket frame (saffron / antique gold), ≥ 44 px controls.
   ========================================================================== */
.lb {
	position: fixed;
	inset: 0;
	z-index: var(--z-modal, 300);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--warm-ivory, #f6ebdd);
	opacity: 0;
	overscroll-behavior: contain;
	transition: opacity 300ms var(--ease-out, ease);
}

.lb.is-open {
	opacity: 1;
}

.lb__backdrop {
	position: absolute;
	inset: 0;
	background: radial-gradient(120% 90% at 50% 42%, rgba(28, 21, 17, 0.86) 0%, rgba(11, 9, 7, 0.96) 70%);
	-webkit-backdrop-filter: blur(14px) saturate(1.1);
	backdrop-filter: blur(14px) saturate(1.1);
}

.lb__stage {
	position: relative;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	padding: 72px 88px 104px;
	touch-action: pan-y pinch-zoom;
}

.lb__frame {
	position: relative;
	max-width: 100%;
	padding: clamp(8px, 1.4vw, 16px);
	scale: 0.97;
	transition: scale 300ms var(--ease-out, ease);
}

.lb.is-open .lb__frame {
	scale: 1;
}

.lb__corner {
	position: absolute;
	width: clamp(16px, 2.4vw, 26px);
	height: clamp(16px, 2.4vw, 26px);
	border: 0 solid var(--saffron, #f47a1f);
	opacity: 0;
	pointer-events: none;
	filter: drop-shadow(0 0 5px rgba(244, 122, 31, 0.4));
	transition: opacity 500ms var(--ease-out, ease) 120ms, translate 600ms var(--ease-out, ease) 120ms;
}

.lb.is-open .lb__corner {
	opacity: 0.95;
	translate: 0 0;
}

.lb__corner--tl { top: 0; left: 0; border-top-width: 1.5px; border-left-width: 1.5px; translate: 12px 12px; }
.lb__corner--tr { top: 0; right: 0; border-top-width: 1.5px; border-right-width: 1.5px; border-color: var(--antique-gold, #d9a441); translate: -12px 12px; }
.lb__corner--bl { bottom: 0; left: 0; border-bottom-width: 1.5px; border-left-width: 1.5px; border-color: var(--antique-gold, #d9a441); translate: 12px -12px; }
.lb__corner--br { bottom: 0; right: 0; border-bottom-width: 1.5px; border-right-width: 1.5px; translate: -12px -12px; }

.lb__media {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
}

.lb__media.is-in-next { animation: hs-lb-in-next 380ms var(--ease-out, ease) both; }
.lb__media.is-in-prev { animation: hs-lb-in-prev 380ms var(--ease-out, ease) both; }

@keyframes hs-lb-in-next { from { opacity: 0; translate: 28px 0; } }
@keyframes hs-lb-in-prev { from { opacity: 0; translate: -28px 0; } }

.lb__img,
.lb__video {
	display: block;
	width: auto;
	height: auto;
	max-width: calc(100vw - 200px);
	max-height: calc(100vh - 210px);
	max-height: calc(100svh - 210px);
	object-fit: contain;
	background: #0b0907;
	box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.9);
}

.lb__img {
	opacity: 0;
	transition: opacity 400ms var(--ease-out, ease);
}

.lb__img.is-loaded {
	opacity: 1;
}

.lb__embed {
	width: min(calc(100vw - 200px), calc((100svh - 210px) * 16 / 9), 1280px);
	aspect-ratio: 16 / 9;
	background: #000;
	box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.9);
}

.lb__embed iframe {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

.lb__error {
	margin: 0;
	padding: 2rem 2.5rem;
	color: var(--fg-soft, rgba(246, 235, 221, 0.82));
	text-align: center;
}

.lb__loader {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	opacity: 0;
	pointer-events: none;
	transition: opacity 200ms ease;
}

.lb.is-loading .lb__loader {
	opacity: 1;
}

.lb__loader::before {
	content: '';
	width: 40px;
	height: 40px;
	border: 1.5px solid rgba(217, 164, 65, 0.6);
	border-radius: 50%;
	box-shadow: 0 0 24px rgba(244, 122, 31, 0.35);
	animation: hs-lb-pulse 1.5s ease-in-out infinite;
}

@keyframes hs-lb-pulse {
	0%, 100% { scale: 0.7; opacity: 0.4; }
	50% { scale: 1; opacity: 1; }
}

.lb__btn {
	position: absolute;
	z-index: 3;
	display: grid;
	place-items: center;
	width: 48px;
	height: 48px;
	padding: 0;
	border: 1px solid rgba(217, 164, 65, 0.38);
	border-radius: 50%;
	background: rgba(21, 16, 13, 0.62);
	color: var(--warm-ivory, #f6ebdd);
	-webkit-backdrop-filter: blur(8px);
	backdrop-filter: blur(8px);
	cursor: pointer;
	transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease, translate 200ms var(--ease-out, ease);
}

.lb__btn:hover {
	border-color: var(--saffron, #f47a1f);
	background: rgba(244, 122, 31, 0.2);
	color: #fff;
}

.lb__btn:focus-visible {
	outline: 2px solid var(--antique-gold, #d9a441);
	outline-offset: 3px;
}

.lb__btn svg {
	width: 22px;
	height: 22px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.6;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.lb__btn[hidden] { display: none; }

.lb__close {
	top: max(16px, env(safe-area-inset-top));
	right: max(16px, env(safe-area-inset-right));
}

.lb__prev,
.lb__next {
	top: 50%;
	translate: 0 -50%;
}

.lb__prev { left: max(16px, env(safe-area-inset-left)); }
.lb__next { right: max(16px, env(safe-area-inset-right)); }
.lb__prev:hover { translate: -3px -50%; }
.lb__next:hover { translate: 3px -50%; }

.lb__counter {
	position: absolute;
	top: max(28px, env(safe-area-inset-top));
	left: max(24px, env(safe-area-inset-left));
	z-index: 3;
	font: 700 0.8125rem / 1 var(--font-body, sans-serif);
	letter-spacing: 0.16em;
	text-transform: uppercase;
	font-variant-numeric: tabular-nums;
	color: var(--gold-soft, #e9c47b);
}

.lb__bar {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 2;
	padding: 56px max(88px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom));
	background: linear-gradient(to top, rgba(11, 9, 7, 0.92) 0%, rgba(11, 9, 7, 0.6) 55%, rgba(11, 9, 7, 0) 100%);
	text-align: center;
	pointer-events: none;
	transition: opacity 300ms ease;
}

.lb:not(.has-caption) .lb__bar {
	opacity: 0;
}

.lb__caption {
	max-width: 62ch;
	margin: 0 auto;
	font: 500 var(--fs-sm, 0.9375rem) / 1.55 var(--font-body, sans-serif);
	color: rgba(246, 235, 221, 0.92);
	text-wrap: balance;
	pointer-events: auto;
}

@media (max-width: 767px) {
	.lb__stage {
		padding: 68px 12px 124px;
	}

	.lb__img,
	.lb__video {
		max-width: calc(100vw - 40px);
		max-height: calc(100svh - 212px);
	}

	.lb__embed {
		width: min(calc(100vw - 40px), calc((100svh - 212px) * 16 / 9));
	}

	.lb__prev,
	.lb__next {
		top: auto;
		bottom: max(16px, env(safe-area-inset-bottom));
		translate: none;
	}

	.lb__prev:hover,
	.lb__next:hover {
		translate: none;
	}

	.lb__bar {
		padding: 40px 80px max(22px, env(safe-area-inset-bottom));
	}
}


/* ==========================================================================
   15. 3D   <model-viewer> injected by models.js over the poster
   ========================================================================== */
model-viewer {
	display: block;
	width: 100%;
	height: 100%;
	background: transparent;
	--poster-color: transparent;
	--progress-bar-color: rgba(244, 122, 31, 0.85);
	--progress-bar-height: 2px;
}

model-viewer:focus-visible {
	outline: 2px solid var(--antique-gold, #d9a441);
	outline-offset: 2px;
}

[data-model-src].is-model-host {
	position: relative;
}

[data-model-src] > model-viewer {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 700ms var(--ease-out, ease);
}

[data-model-src].is-model-ready > model-viewer {
	opacity: 1;
}

/* Poster / placeholder art cross-fades out once the model is on screen (and stays as the failure fallback). */
[data-model-src] > .media-slot__poster,
[data-model-src] > .media-slot__art {
	transition: opacity 700ms var(--ease-out, ease);
}

[data-model-src].is-model-ready > .media-slot__poster,
[data-model-src].is-model-ready > .media-slot__art {
	opacity: 0;
}


/* ==========================================================================
   16. SCROLL LOCK · PAGE TRANSITIONS
   ========================================================================== */
/* main.js writes --sbw (scrollbar width) while locked so the page does not jump sideways. */
body.is-locked {
	padding-right: var(--sbw, 0px);
}

body.is-locked .site-header {
	padding-right: var(--sbw, 0px);
}

@media (prefers-reduced-motion: no-preference) {
	.site-header {
		view-transition-name: site-header;
	}

	::view-transition-old(root),
	::view-transition-new(root) {
		animation-duration: 260ms;
		animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
	}

	/* Header stays put; only the page body cross-fades. */
	::view-transition-group(site-header) {
		animation-duration: 0s;
	}
}


/* ==========================================================================
   17. REDUCED MOTION — everything above becomes static and visible, instantly.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
	html.hs-js :is([data-reveal], [data-stagger] > *, [data-hero-item]):not([data-split]):not(.is-revealed) {
		opacity: 1;
		translate: none;
		scale: none;
		filter: none;
		clip-path: none;
	}

	html.hs-js :is([data-reveal], [data-stagger] > *, [data-hero-item]).is-revealed,
	html.hs-js .media-slot[data-reveal^="mask"].is-revealed .media-slot__media,
	html.hs-js [data-split].is-split .split-line__inner {
		animation: none !important;
	}

	html.hs-js [data-split]:not(.is-split) { visibility: visible; }
	html.hs-js [data-split].is-split:not(.is-revealed) .split-line__inner { translate: none; }

	.marquee__track { animation: none !important; transform: none !important; }
	.marquee__item[data-marquee-clone],
	.marquee__toggle,
	.hero__sweep,
	.embers,
	.tilt-glare { display: none !important; }

	[data-float],
	[data-ken-burns] .media-slot__inner,
	[data-ken-burns].media-slot__inner,
	[data-ken-burns] > img,
	[data-ken-burns] > picture,
	[data-ken-burns] > video,
	img[data-ken-burns],
	video[data-ken-burns] { animation: none !important; }

	[data-parallax],
	[data-tilt].is-tilting,
	[data-pointer] [data-depth] { transform: none !important; translate: none !important; }

	.scrolly__panel,
	.scrolly__step,
	.back-to-top,
	.toast,
	[data-filter-list].is-filtering > [data-filter-item],
	.lb,
	.lb *,
	.lb *::before,
	[data-model-src] > model-viewer,
	[data-model-src] > .media-slot__poster,
	[data-model-src] > .media-slot__art { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; }

	[data-tabs].is-interacted [role="tabpanel"] { animation: none !important; }

	::view-transition-group(*),
	::view-transition-old(*),
	::view-transition-new(*) { animation: none !important; }
}

/* ==========================================================================
   3D model motion presets (data-anim on <model-viewer>, set from inc/media-3d-anim.php).
   Spin / slow turn use model-viewer's own auto-rotate (models.js); the rest move the whole viewer gently.
   Off for reduced motion and while editing.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
	html:not(.hs-reduced) model-viewer[data-anim="monumentFloat"],
	html:not(.hs-reduced) model-viewer[data-anim="float"],
	html:not(.hs-reduced) model-viewer[data-anim="hoverTilt"] {
		animation: hs-3d-bob 8s ease-in-out infinite;
	}

	html:not(.hs-reduced) model-viewer[data-anim="networkPulse"] {
		animation: hs-3d-bob 9s ease-in-out infinite, hs-3d-pulse 5s ease-in-out infinite;
	}

	html:not(.hs-reduced) model-viewer[data-anim="flameFloat"] {
		animation: hs-3d-bob 5s ease-in-out infinite, hs-3d-pulse 2.6s ease-in-out infinite;
	}

	html:not(.hs-reduced) model-viewer[data-anim="flagSway"],
	html:not(.hs-reduced) model-viewer[data-anim="bellSway"] {
		transform-origin: 50% 8%;
		animation: hs-3d-sway 6s ease-in-out infinite;
	}
}

@keyframes hs-3d-bob {
	0%, 100% { translate: 0 0; }
	50% { translate: 0 -2.2%; }
}

@keyframes hs-3d-pulse {
	0%, 100% { scale: 1; }
	50% { scale: 1.025; }
}

@keyframes hs-3d-sway {
	0%, 100% { rotate: -1.6deg; }
	50% { rotate: 1.6deg; }
}
