/* Website-only layer on top of shared/scenes.css: page scroll, entry, date reveal, countdown, music. */

html {
	height: 100%;
	scroll-snap-type: y mandatory;
	overflow-y: auto;
	background: var(--ivory);
	-webkit-text-size-adjust: 100%;
	-webkit-tap-highlight-color: transparent;
}
html.is-locked { overflow: hidden; touch-action: none; } /* touch-action: iOS Safari ignores overflow:hidden for panning */
/* Hide the cover's line art before first paint (no inline script under the CSP); app.js parks its strokes, then shows it */
html.is-locked .cover__ganesha { opacity: 0; }
/* Boot fallback (boot.js): the motion layer never reported ready, so the invite shows settled, without the envelope.
   Opacity and transform only: the !important beats inline state GSAP set before a mid-file throw */
html.motion-failed .cover { display: none; }
html.motion-failed :is(.scene__inner > *, .scene__inner li, .s-opening .lines > *) { opacity: 1 !important; transform: none !important; }
html.motion-failed .foil { display: none; } /* the scratch canvas: show the date under it */
html.motion-failed .curtain { display: none; }
body { margin: 0; background: var(--ivory); }
main { display: block; }

.scene {
	height: 100svh;
	scroll-snap-align: start;
	scroll-snap-stop: always;
}
@supports not (height: 100svh) { .scene { height: 100vh; } }

/* ---------- Scene 1: entry ---------- */
.s1-stage { position: relative; display: grid; place-items: center; width: 100%; }
.s1-stage > * { grid-area: 1 / 1; }
.s-opening:not(.is-open) .lines > * { opacity: 0; }
.s-opening .ganesha { height: auto; }



.scroll-cue {
	position: absolute;
	left: 50%;
	bottom: calc(3 * var(--u) + env(safe-area-inset-bottom));
	width: calc(8 * var(--u));
	height: calc(8 * var(--u));
	margin-left: calc(-4 * var(--u));
	color: var(--gold-ink);
	opacity: 0;
	z-index: 3;
}

/* Royal foil, the names' resting style (reduced motion and lite too): a dark gold body that keeps contrast, one bright
   band parked off the glyphs that foilSweep carries across. The swash padding lives on .t-name in scenes.css. */
.t-name {
	background: var(--foil) 100% 0 / 250% 100% no-repeat;
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
/* The Wedding title: a sweep band (parked off the glyphs at 0% 0%) over the light foil; fun.js sweeps the two-value position */
.s-wedding .t-title {
	background: linear-gradient(100deg, transparent 42%, rgb(255 246 214 / .95) 50%, transparent 58%) 0% 0% / 250% 100% no-repeat, var(--foil-light, var(--gold-light));
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
/* background-clip: text skips transformed children: solid gold while riseIn moves the chars */
.s-wedding .t-title.is-rising { background: none; color: var(--gold-light); }
/* SplitText word masks: room for italic overhangs and descenders, layout-neutral */
.w-mask { padding: .15em .12em .25em; margin: -.15em -.12em -.25em; }
/* Petal back face: duller and paler than the front, toggled at each edge-on crossing (M.tumble) */
.petal.is-back { filter: saturate(.55) brightness(1.15); }
/* The pen nib riding a write-on: one per scene, a direct child, placed by GSAP x/y only (never CSS translate) */
.scene > .nib { position: absolute; left: 0; top: 0; z-index: 3; width: calc(4 * var(--u)); aspect-ratio: 1; margin: calc(-2 * var(--u)) 0 0 calc(-2 * var(--u)); border-radius: 50%; opacity: 0; pointer-events: none; background: radial-gradient(circle, #FFF6D6 0 20%, #E9CF78 38%, transparent 70%); will-change: transform, opacity; }

/* ---------- Date reveal + countdown (site only) ---------- */
.s-date {
	background: radial-gradient(90% 60% at 50% 45%, var(--powder-soft) 0%, var(--ivory) 70%);
}
.s-date .corner { width: calc(80 * var(--u)); opacity: .28; }
.s-date .corner--tl { left: calc(-40 * var(--u)); top: calc(-40 * var(--u)); }
.s-date .corner--br { right: calc(-40 * var(--u)); bottom: calc(-40 * var(--u)); }
.s-date .scene__inner { gap: var(--sp-2); }
.save-title { font-size: calc(19 * var(--u)); }
.save-sub { color: var(--ink); margin-bottom: var(--sp-2); }
.hearts { display: flex; justify-content: center; gap: calc(3.5 * var(--u)); }
.heart-group { display: grid; justify-items: center; gap: calc(1.6 * var(--u)); }
.heart-label { font-family: var(--font-title); font-size: var(--fs-small); font-weight: 600; letter-spacing: .2em; color: var(--gold-ink); }
.heart-wrap { position: relative; width: calc(26 * var(--u)); aspect-ratio: 100 / 90; will-change: transform; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.heart {
	position: absolute; inset: 0;
	display: grid; place-items: center;
	background: radial-gradient(circle at 50% 40%, #FFFFFF, #FBF1EE);
	-webkit-mask: url("shared/svg/heart.svg") center / 100% 100% no-repeat;
	mask: url("shared/svg/heart.svg") center / 100% 100% no-repeat;
	cursor: grab;
}
.heart:focus-visible { outline: none; }
.heart-wrap:has(.heart:focus-visible) .heart-line path { stroke-width: 3; }
.heart-value { margin-top: -10%; font-size: calc(8.6 * var(--u)); font-weight: 600; line-height: 1; color: var(--gold-ink); text-shadow: none; }
.heart-line { position: absolute; inset: -3%; width: 106%; height: 106%; overflow: visible; pointer-events: none; }
.heart-line path { fill: none; stroke: var(--gold); stroke-width: 1.6; vector-effect: non-scaling-stroke; }
.heart-line .trace { stroke: var(--gold-ink); stroke-width: 2.4; stroke-linecap: round; }
.heart-spark { position: absolute; left: 50%; top: 45%; width: calc(1.6 * var(--u)); height: calc(1.6 * var(--u)); border-radius: 50%; margin: calc(-.8 * var(--u)) 0 0 calc(-.8 * var(--u)); background: var(--gold-light); pointer-events: none; will-change: transform, opacity; }

.foil {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border-radius: inherit;
	cursor: grab;
	touch-action: none;
	z-index: 2;
}
.s-date.is-revealed .foil { pointer-events: none; }

.countdown {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: calc(2.6 * var(--u));
	width: calc(84 * var(--u));
	flex: none;
}
.cd-tile {
	display: grid;
	justify-items: center;
	gap: calc(.6 * var(--u));
	padding: calc(3.2 * var(--u)) 0 calc(2.6 * var(--u));
	border: var(--line) solid rgb(201 162 39 / .55);
	border-radius: calc(2.2 * var(--u));
	background: rgb(255 255 255 / .55);
}
.cd-num { font-size: calc(9 * var(--u)); font-weight: 500; line-height: 1; color: var(--gold-ink); font-variant-numeric: tabular-nums lining-nums; }
.cd-label { font-size: var(--fs-small); line-height: 1; color: var(--ink); }
/* Digit roll (app.js builds two .cd-dg slots per cell): the new digit drops in, the old one (data-old) drops out.
   The tabular figures on .cd-num keep the slot widths fixed. */
.cd-dg { position: relative; display: inline-block; }
.cd-dg b { display: inline-block; font-weight: inherit; }
.cd-dg::before { content: attr(data-old); position: absolute; inset: 0; opacity: 0; pointer-events: none; }
.cd-dg.is-rolling b { animation: cd-in .45s var(--ease-out) both; }
.cd-dg.is-rolling::before { animation: cd-out .45s var(--ease-out) both; }
@keyframes cd-in { from { transform: translateY(-60%); opacity: 0; } }
@keyframes cd-out { from { opacity: 1; } to { transform: translateY(60%); opacity: 0; } }
/* Hidden until the hearts are scratched, but its space is kept, so the hearts and the hashtag never jump */
.s-date:not(.is-revealed) .countdown { visibility: hidden; }
.s-date.is-past .countdown { display: none; }
/* A & D monogram: thin gold double ring with vine sprigs (drawn by app.js); the letters are an image on top */
.monogram { position: relative; flex: none; width: calc(24 * var(--u)); aspect-ratio: 1; color: var(--gold-ink); }
.monogram svg, .monogram img { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.monogram img { left: -5%; top: -5%; width: 110%; height: 110%; } /* letters fill the ring, still inside its inner line */
/* Couple slide: the monogram crowns the arch: its bottom rests on the arch's top point (the same 4% - 1.4u as
   .arch::after), clear of the couple's heads; the ivory disc keeps it legible on the painted palace */
.monogram--crest { --cw: calc(18.5 * var(--u)); position: absolute; z-index: 2; left: 50%; top: calc(4% - 1.4 * var(--u)); width: var(--cw); margin: calc(-1 * var(--cw) - .8 * var(--u)) 0 0 calc(-.5 * var(--cw)); border-radius: 50%; background: radial-gradient(circle closest-side, rgb(250 246 236 / .98) 0 90%, transparent 92%); filter: drop-shadow(0 calc(.5 * var(--u)) calc(1.4 * var(--u)) rgb(90 66 5 / .35)); }
/* The couple slide's hashtag is the quieter echo (Save the Date carries the big one); a size down also keeps it clear of the
   music button in the bottom corner on phones */
.s-couple .hashtag { font-size: var(--fs-small); }
/* The crest sits above the arch, and the centred stack does not count it: keep room for it on phones
   (the desktop grid resets the arch's margin) */
.s-couple .arch { margin-top: calc(20 * var(--u)); }
/* Closing: the monogram signs off above the closing line (20u = 72 px on a 360 px phone, the brand minimum) */
.s-closing .monogram { width: calc(20 * var(--u)); }
.s-closing .hashtag { font-size: var(--fs-body); }
/* Desktop: the date slide's stack would fill the whole height; a smaller ring and tighter spacing give it air */
@container (orientation: landscape) and (min-width: 820px) {
	.s-date .scene__inner { gap: var(--sp-1); }
	.s-date .monogram { width: calc(17 * var(--u)); }
	.s-couple .hashtag { font-size: var(--fs-lead); } /* desktop has room: the couple slide's hashtag at full size */
	.s-closing .monogram { width: calc(18 * var(--u)); }
	.monogram--crest { --cw: calc(16 * var(--u)); } /* fits the space above the 76cqh arch */
	.s-closing .hashtag { font-size: var(--fs-lead); }
}
/* The wedding hashtag: the couple's names inside it carry a gold highlighter swipe (drawn in by app.js) */
/* An ivory pill with a thin gold border, so the hashtag reads on any painting */
.hashtag { align-self: center; width: fit-content; margin: var(--sp-1) auto 0; padding: calc(.8 * var(--u)) calc(3.4 * var(--u)) calc(1.2 * var(--u)); border: var(--line) solid rgb(201 162 39 / .65); border-radius: 999px; background: rgb(255 251 240 / .88); box-shadow: 0 calc(.6 * var(--u)) calc(2.2 * var(--u)) rgb(110 82 10 / .16); font: italic 600 var(--fs-lead) / 1.25 var(--font-serif); color: var(--ink); letter-spacing: .01em; white-space: nowrap; }
.hashtag .hl { display: inline-block; font: 400 1.5em / 1 var(--font-script); color: #6B4F06; -webkit-text-stroke: .018em currentColor; padding: 0 .12em; border-radius: .3em; background: linear-gradient(90deg, rgb(233 207 120 / .75), rgb(243 201 198 / .85)) no-repeat 0 92% / 100% .46em; }

/* ---------- Music toggle (direct child of body: never inside a transformed parent) ---------- */
/* ---------- Corner controls: music bottom-right, "Pause animations" bottom-left ---------- */
.music-toggle, .motion-toggle {
	position: fixed;
	bottom: max(16px, env(safe-area-inset-bottom));
	z-index: 50;
	width: 44px;
	height: 44px;
	display: grid;
	place-items: center;
	padding: 0;
	border: 1px solid var(--gold);
	border-radius: 50%;
	background: rgb(250 246 236 / .92);
	color: var(--gold-ink);
	cursor: pointer;
	box-shadow: 0 4px 14px rgb(60 45 15 / .15);
	transition: scale 120ms var(--ease-out), opacity .3s var(--ease-gentle), display .3s allow-discrete;
}
.music-toggle { right: max(16px, env(safe-area-inset-right)); }
.motion-toggle { left: max(16px, env(safe-area-inset-left)); }
:is(.music-toggle, .motion-toggle)[hidden] { display: none; }
@starting-style { .music-toggle, .motion-toggle { opacity: 0; } }
/* The two icons share one cell and crossfade (no display swap) */
:is(.music-toggle, .motion-toggle) svg { grid-area: 1 / 1; width: 20px; height: 20px; transition: opacity .25s var(--ease-gentle), scale .25s var(--ease-out); }
.music-toggle[aria-pressed="true"] .ic-off, .music-toggle[aria-pressed="false"] .ic-on,
.motion-toggle[aria-pressed="true"] .ic-pause, .motion-toggle[aria-pressed="false"] .ic-play { opacity: 0; scale: .25; }
:is(.music-toggle, .motion-toggle):focus-visible { outline: 2px solid var(--gold-ink); outline-offset: 3px; }

/* Touch: no double-tap zoom delay or label selection on controls; a press scales them (GSAP never tweens these;
   .cover__btn's press belongs to GSAP). The .cover rules live in the cover block of shared/scenes.css. */
:is(.btn, .rsvp a, .music-toggle, .motion-toggle, .rail button, .cover__btn) { touch-action: manipulation; -webkit-user-select: none; user-select: none; }
:is(.btn, .rsvp a, .music-toggle, .motion-toggle):active { scale: .97; }

/* Placeholder links that still need real values: visibly unfinished */
[data-fill] { outline: 1px dashed rgb(180 60 60 / .55); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	:is(.btn, .rsvp a, .music-toggle, .motion-toggle):active { scale: none; }
	.cd-dg.is-rolling b, .cd-dg.is-rolling::before { animation: none; }
	/* Designed still: each petal rests at its own angle and tilt */
	.petal { rotate: calc(var(--r) * 1deg); scale: calc(.45 + var(--o) * .55) 1; opacity: calc(.35 + var(--o) * .5); }
}


/* ---------- Playful layer (fun.js) ---------- */
.fx-petal, .fx-bubble { position: absolute; z-index: 6; pointer-events: none; margin: calc(-2.5 * var(--u)) 0 0 calc(-2 * var(--u)); }
.couple-img img { cursor: pointer; }
.pop-heart {
	position: absolute; left: 50%; top: 30%; z-index: 3;
	width: calc(7.5 * var(--u)); aspect-ratio: 100 / 90; margin-left: calc(-3.75 * var(--u));
	background: linear-gradient(160deg, #F58D9C, #C93A52);
	-webkit-mask: url("shared/svg/heart.svg") center / 100% 100% no-repeat;
	mask: url("shared/svg/heart.svg") center / 100% 100% no-repeat;
	pointer-events: none;
}
.butterfly { position: absolute; left: 0; top: 0; z-index: 1; width: calc(13 * var(--u)); margin: calc(-6.5 * var(--u)) 0 0 calc(-6.5 * var(--u)); pointer-events: none; }
.butterfly svg { display: block; width: 100%; overflow: visible; filter: drop-shadow(0 calc(.6 * var(--u)) calc(.8 * var(--u)) rgb(80 60 20 / .18)); }
.butterfly path { fill: rgb(188 212 230 / .92); stroke: var(--gold); stroke-width: .8; }
.butterfly--blush path { fill: rgb(243 201 198 / .94); }
.butterfly .body { fill: none; stroke: #6E520A; stroke-width: 1.2; stroke-linecap: round; }
.rail {
	position: fixed; right: max(10px, env(safe-area-inset-right)); top: 50%; translate: 0 -50%; z-index: 40;
	display: grid; gap: 2px;
	opacity: 0; pointer-events: none; transition: opacity .6s var(--ease-gentle);
}
.rail.is-on { opacity: 1; pointer-events: auto; }
.rail button { width: 28px; height: 28px; padding: 0; border: 0; background: none; cursor: pointer; display: grid; place-items: center; }
.rail button::before { content: ""; width: 8px; height: 8px; border-radius: 50%; border: 1px solid var(--gold); background: rgb(250 246 236 / .85); box-shadow: 0 1px 3px rgb(60 45 15 / .2); transition: transform .2s var(--ease-gentle), background-color .2s var(--ease-gentle); }
.rail button[aria-current="true"]::before { background: var(--gold); transform: scale(1.4); }
@media (hover: hover) and (pointer: fine) { .rail button:hover::before { transform: scale(1.25); } }
.rail button:focus-visible { outline: 2px solid var(--gold-ink); outline-offset: 2px; border-radius: 50%; }
@media (max-width: 599px) { .rail { display: none; } }
.pop-heart--float { left: 0; top: 0; margin: 0; z-index: 1; }
.pin-ring { position: absolute; left: 50%; bottom: -6%; width: 70%; aspect-ratio: 2.6; margin-left: -35%; border-radius: 50%; border: 2px solid var(--gold); background: rgb(201 162 39 / .12); pointer-events: none; }
/* app.js blooms the span; fun.js breathes its inner i */
.ganesha-halo { position: absolute; z-index: 0; left: -30%; top: -32%; width: 160%; aspect-ratio: 1; pointer-events: none; }
.ganesha-halo i { position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(circle, rgb(240 214 140 / .6), rgb(240 214 140 / .2) 45%, transparent 70%); }
.bloom { position: absolute; width: calc(var(--s) * var(--u)); aspect-ratio: 1; background: center / contain no-repeat; filter: drop-shadow(0 calc(.4 * var(--u)) calc(.6 * var(--u)) rgb(70 60 50 / .18)); }
.bloom--white { background-image: url("shared/svg/bloom-white.svg"); }
.bloom--blush { background-image: url("shared/svg/bloom-blush.svg"); }
.bokeh { position: absolute; z-index: 6; width: calc(var(--b) * var(--u)); aspect-ratio: 1; border-radius: 50%; pointer-events: none; opacity: 0; filter: blur(calc(.25 * var(--u))); }
.bokeh--0 { background: radial-gradient(circle, rgb(255 255 255 / .9), rgb(255 255 255 / .25) 55%, transparent 70%); }
.bokeh--1 { background: radial-gradient(circle, rgb(240 214 140 / .9), rgb(240 214 140 / .25) 55%, transparent 70%); }
.bokeh--2 { background: radial-gradient(circle, rgb(243 201 198 / .85), rgb(243 201 198 / .2) 55%, transparent 70%); }

/* ================= Desktop / landscape: full-bleed paintings, two-column scenes =================
   Each .scene is a size container; only landscape frames at least 820px wide switch layout.
   --u is redefined on every scene child (cq units never resolve against the container itself), so text,
   effects and the JS unit probe all scale together. */
@container (orientation: landscape) and (min-width: 820px) {
	.scene > * { --u: min(0.48cqi, 0.66cqh); }
	.scene__inner { width: min(100%, calc(235 * var(--u))); padding: calc(6 * var(--u)) calc(9 * var(--u)); }

	/* Entrance: the whole envelope lying on the lace cloth (owner, 2026-11-09: the seal close-up was "not showing
	   envelope"). 92cqh tall, so the phone rule's flap tip at 60cqh leaves 3.4cqh above it. */
	.cover__photo { --pw: calc(92cqh * 1084 / 1451); box-shadow: 0 calc(1.2 * var(--u)) calc(5 * var(--u)) rgb(70 50 20 / .3); }

	/* Art left, words right */
	.s-couple .scene__inner, .event .scene__inner, .s-closing .scene__inner {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
		grid-template-rows: 1fr repeat(var(--rows), auto) 1fr;
		column-gap: calc(8 * var(--u));
		row-gap: calc(1.4 * var(--u));
		align-items: center;
		justify-items: center;
	}
	.s-couple .scene__inner { --rows: 7; }
	.event .scene__inner { --rows: 5; }
	.s-sehra .scene__inner { --rows: 4; }
	.s-closing .scene__inner { --rows: 8; }
	.s-closing :is(.t-label, .actions) { margin-top: var(--sp-1); } /* eight rows in one column: the buttons cleared the slide's foot by -6px */
	.s-couple .scene__inner > *, .event .scene__inner > *, .s-closing .scene__inner > * { grid-column: 2; }
	/* An empty first item holds the top spacer row, so the words auto-place from row 2 in document order */
	.s-couple .scene__inner::before, .event .scene__inner::before, .s-closing .scene__inner::before { content: ""; grid-column: 2; grid-row: 1; }
	.s-couple .arch, .event .scene__inner > :first-child, .s-closing .halo { grid-column: 1; grid-row: 1 / -1; margin: 0; }
	.s-couple .arch { width: auto; height: 76cqh; aspect-ratio: 50 / 58; }
	.event .couple-img { width: 100%; height: 82cqh; margin: 0; }
	/* Sehra: the box takes the picture's own 667:1000, so the nimbus and the glint (in % of the box) stay on the head at every width */
	/* fun.js turns the square nimbus endlessly: at 45deg its box reaches 0.38 of the picture's height above its centre, so the
	   groom stands on the slide's floor, a size down (82 to 76.5cqh), to keep that box inside the slide */
	.s-sehra .couple-img { width: min(100%, 51cqh); height: auto; aspect-ratio: 667 / 1000; align-self: end; }
	.s-cocktail .frame { width: auto; height: 82cqh; max-height: none; aspect-ratio: 300 / 420; margin: 0; }
	/* The couple overhangs the mandap box by ~16%, so the box sits at the top to keep their feet on screen
	   (not CSS translate: GSAP writes inline translate: none on every element it animates) */
	.s-wedding .mandap { width: auto; height: 80cqh; max-height: none; aspect-ratio: 400 / 446; margin: 0; align-self: start; }
	.s-closing .halo { width: auto; height: 76cqh; aspect-ratio: 56 / 58; }
	.s-closing .halo .mandala { width: 150%; }
	/* Side by side, the words never sit under the figure: no sill cut, the couple run past the arch as in draft 1 */
	.s-couple .arch .couple-img { clip-path: none; }
	/* The closing picture is taller than its halo and would run ~90px past the slide: size the img to the box and crop it
	   (width-fit, top kept), so its layout box is the visible part */
	.s-closing .halo .couple-img { grid-template-rows: 100%; }
	.s-closing .halo .couple-img img { object-fit: cover; object-position: center top; }

	/* Single centred column, larger */
	/* Hero: Ganesh ji and the shloka on the left, the blessings and names on the right */
	.s-opening .scene__inner { --u: min(0.48cqi, 0.7cqh); display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); grid-template-rows: 1fr auto auto 1fr; column-gap: calc(6 * var(--u)); align-items: center; justify-items: center; }
	.s-opening .ganesha { grid-column: 1; grid-row: 2; width: min(100%, 50cqh); }
	.s-opening .t-deva { grid-column: 1; grid-row: 3; }
	.s-opening .s1-stage { grid-column: 2; grid-row: 1 / -1; }
	.s-opening .toran { width: 38%; left: 5%; } /* crowns Ganesh ji's column */
	.s-date .scene__inner { --u: min(0.48cqi, 0.7cqh); }

	/* Venue: the painting carries the resort; words and map share the lower half */
	.s-venue .scene__inner { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: 1fr repeat(4, auto); column-gap: calc(8 * var(--u)); row-gap: calc(1.2 * var(--u)); align-items: center; justify-items: center; }
	.s-venue .resort { grid-column: 1 / -1; grid-row: 1; align-self: stretch; width: 100%; height: auto; }
	.s-venue .resort > img { display: none; }
	.s-venue .pin { top: 30%; width: calc(12 * var(--u)); }
	.s-venue .scene__inner > :not(.resort):not(.map) { grid-column: 1; }
	.s-venue .map { grid-column: 2; grid-row: 2 / span 4; width: 100%; height: calc(48 * var(--u)); margin: 0; }
	.s-venue::after { background: linear-gradient(transparent 42%, rgb(250 246 236 / .8) 56%, rgb(250 246 236 / .9) 100%); }
}

/* 1u probe for JS: see unit() in app.js */
.u-probe { position: absolute; left: 0; top: 0; width: calc(100 * var(--u)); height: 0; visibility: hidden; pointer-events: none; }
/* Gold glint sweeping across the wax Om, masked to the seal's own shape. The strip is parked off the seal with left (never
   a CSS transform), so GSAP's xPercent starts from 0 and 335 carries it past the right edge */
.cover__glint {
	position: absolute; inset: 0; overflow: hidden; pointer-events: none; mix-blend-mode: screen;
	-webkit-mask: url("shared/photo/seal-om.webp") center / contain no-repeat;
	mask: url("shared/photo/seal-om.webp") center / contain no-repeat;
}
.cover__glint i { position: absolute; top: -10%; bottom: -10%; left: -50%; width: 45%; background: linear-gradient(105deg, transparent 20%, rgb(255 240 200 / .9) 50%, transparent 80%); }

/* Fireworks (Cocktail Night sky, wedding sparkles): behind the couple and words (z 1), above the painting */
.fw-spark, .fw-streak, .fw-flash, .twinkle { position: absolute; z-index: 1; pointer-events: none; }
.fw-spark { width: calc(.55 * var(--u)); height: calc(3.6 * var(--u)); margin: calc(-1.8 * var(--u)) 0 0 calc(-.28 * var(--u)); border-radius: 999px; background: linear-gradient(to bottom, #FFFFFF, var(--c) 30%, transparent); box-shadow: 0 0 calc(1 * var(--u)) var(--c); }
.fw-streak { width: calc(.6 * var(--u)); height: calc(5 * var(--u)); margin-left: calc(-.3 * var(--u)); border-radius: 999px; background: linear-gradient(to top, transparent, #F4E2A1); box-shadow: 0 0 calc(1.2 * var(--u)) #F4E2A1; }
.fw-flash { width: calc(16 * var(--u)); aspect-ratio: 1; margin: calc(-8 * var(--u)) 0 0 calc(-8 * var(--u)); border-radius: 50%; background: radial-gradient(circle, rgb(255 246 214 / .9), rgb(255 246 214 / 0) 65%); }
.twinkle { width: calc(3.2 * var(--u)); aspect-ratio: 1; margin: calc(-1.6 * var(--u)) 0 0 calc(-1.6 * var(--u)); background: radial-gradient(circle, #FFF8E1 0 20%, rgb(244 226 161 / .75) 34%, transparent 64%); clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%); }
/* Cocktail Night: sparks without the blurred box-shadow; the gradient streak carries the colour (the Wedding keeps its glow) */
.s-cocktail .fw-spark { box-shadow: none; }
/* The Wedding: maroon velvet curtains with a gold inner edge, gathering to the sides */
.curtain { position: absolute; top: 0; bottom: 0; z-index: 8; width: 51%; pointer-events: none;
	background:
		linear-gradient(90deg, rgb(0 0 0 / .22), transparent 14%, transparent 86%, rgb(0 0 0 / .22)),
		repeating-linear-gradient(90deg, rgb(255 255 255 / .07) 0 1.2%, rgb(0 0 0 / .16) 3%, rgb(255 255 255 / .05) 4.6%, rgb(0 0 0 / .12) 6.4%),
		linear-gradient(180deg, #7A1424, #8B1E2D 45%, #5E0F1B); }
.curtain--l { left: 0; transform-origin: 0 50%; box-shadow: inset calc(-1.2 * var(--u)) 0 0 #C9A227; }
.curtain--r { right: 0; transform-origin: 100% 50%; box-shadow: inset calc(1.2 * var(--u)) 0 0 #C9A227; }
/* The Wedding: embers from the sacred fire */
.ember { position: absolute; z-index: 3; width: calc(1.1 * var(--u)); aspect-ratio: 1; margin: calc(-.55 * var(--u)) 0 0 calc(-.55 * var(--u)); border-radius: 50%; background: radial-gradient(circle, #E8BF40 0 28%, #E3951F 46%, rgb(185 29 3 / .55) 62%, transparent 72%); pointer-events: none; } /* a cooling ramp in one gradient, no box-shadow */
/* Particles animate transform/opacity only: give them their own compositor layers so glows are not repainted each frame (measured: 26% slow frames on Cocktail at 4x CPU before) */
.fw-spark, .fw-streak, .fw-flash, .ember, .fx-petal, .fx-bubble, .bloom, .twinkle, .curtain, .agni, .vow { will-change: transform, opacity; }
/* Doves: white with a soft grey edge so they read on pale skies too. Doves and butterflies fly at z 1, behind the words */
.dove { position: absolute; left: 0; top: 0; z-index: 1; width: calc(9 * var(--u)); margin: calc(-2.6 * var(--u)) 0 0 calc(-4.5 * var(--u)); pointer-events: none; will-change: transform; }
.dove svg { display: block; width: 100%; overflow: visible; filter: drop-shadow(0 calc(.4 * var(--u)) calc(.6 * var(--u)) rgb(60 50 40 / .25)); }
.dove path { fill: #FFFFFF; stroke: rgb(120 110 100 / .55); stroke-width: .7; }
/* Sehra Bandi: a miniature-painting nimbus behind the safa (the image sits above it). app.js blooms .groom-aura; fun.js
   breathes and turns .groom-halo. Placed in % of the portrait box, which matches the picture */
.s-sehra .couple-img { isolation: isolate; }
.s-sehra .couple-img img { position: relative; z-index: 1; }
.groom-aura { position: absolute; z-index: 0; left: 9%; top: -12%; width: 78%; height: 52%; pointer-events: none; opacity: 0; }
.groom-halo { position: absolute; inset: 0; border-radius: 50%; will-change: transform, opacity;
	background: radial-gradient(circle, rgb(255 249 230 / .94) 0 25%, rgb(252 236 194 / .7) 30%, transparent 35.6%),
		radial-gradient(circle, transparent 0 35.4%, rgb(170 128 24 / .9) 36% 37%, rgb(226 190 96 / .5) 37.6%, transparent 39%),
		repeating-conic-gradient(rgb(201 158 52 / 0) 0deg 4deg, rgb(201 158 52 / .7) 7.5deg, rgb(201 158 52 / 0) 11deg 15deg);
	-webkit-mask: radial-gradient(circle, #000 0 38%, rgb(0 0 0 / .55) 52%, transparent 68%);
	mask: radial-gradient(circle, #000 0 38%, rgb(0 0 0 / .55) 52%, transparent 68%); }
/* The kalgi jewel on the safa; .twinkle supplies the star (after the .twinkle rules so z and size win) */
.kalgi-glint { z-index: 2; left: 51%; top: 9.4%; width: calc(6 * var(--u)); margin: calc(-3 * var(--u)) 0 0 calc(-3 * var(--u)); opacity: 0; }
@media (prefers-reduced-motion: reduce) { .groom-aura { opacity: 1; } }
/* Desktop pointer trail */
.trail { position: fixed; z-index: 60; width: 12px; aspect-ratio: 1; margin: -6px 0 0 -6px; pointer-events: none; background: radial-gradient(circle, #FFF6D6 0 20%, #E9CF78 36%, transparent 64%); clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%); }

/* ---------- Motion you feel all the time (draft 2) ---------- */
/* A soft light drifting across each painting (fun.js adds it after .scene__bg and moves it with xPercent). Same z as the
   painting and later in the DOM, so it sits over the painting and under the deco, effects and words. At xPercent 0 the
   band crosses the middle of the slide. */
/* Front florals (painted cutouts, shared/photo/spray-*): a spray in each top corner of the painted slides, behind the people and text, below the Wedding
   curtain. app.js drifts and sways the box and fun.js leans it; the img inside carries the flip, so nothing fights GSAP */
.spray { z-index: 1; top: calc(-3 * var(--u)); width: calc(52 * var(--u)); }
.spray img { display: block; width: 100%; aspect-ratio: auto 1 / 1; } /* a height before the lazy load: a zero-height box above the fold never loads */
.spray--tl { left: calc(-3 * var(--u)); }
.spray--tr { right: calc(-3 * var(--u)); width: calc(44 * var(--u)); }
.spray--tr img { transform: scaleX(-1); }
/* the Wedding and Venue art fills the slide's top, so their sprays sit in front of it, smaller, clear of the faces */
:is(.s-wedding, .s-venue) .spray { z-index: 3; width: calc(42 * var(--u)); }
:is(.s-wedding, .s-venue) .spray--tr { width: calc(36 * var(--u)); }
.s-wedding .spray--tl { left: 3%; } /* inside the parted curtains' edges */
.s-wedding .spray--tr { right: 3%; }
@container (orientation: landscape) and (min-width: 820px) { /* wide screens: a unit is smaller against the width, so larger sprays */
	.spray { width: calc(70 * var(--u)); }
	.spray--tr { width: calc(58 * var(--u)); }
	:is(.s-wedding, .s-venue) .spray { width: calc(60 * var(--u)); }
	:is(.s-wedding, .s-venue) .spray--tr { width: calc(50 * var(--u)); }
}
.scene__light { --tint: rgb(255 244 214 / .26); position: absolute; inset: 0; z-index: 0; pointer-events: none; background: linear-gradient(105deg, transparent 32%, var(--tint) 50%, transparent 68%); }
.s-haldi .scene__light { background: linear-gradient(105deg, transparent 32%, rgb(255 255 255 / .3) 46%, rgb(188 212 230 / .26) 54%, transparent 68%); } /* Haldi: white to powder blue, never yellow */
.s-cocktail .scene__light { --tint: rgb(226 196 99 / .2); } /* gold over the night sky, never a new midnight */
/* The page-turn light seam (app.js): one fixed gold line that crosses the screen during each slide's travel, invisible at
   rest. Above the slides, below the rail and the corner buttons. Every slide is its own stacking context (container-type),
   so the cover's z only counts inside the first slide: the seam stays at opacity 0 while the envelope is closed. */
.seam { position: fixed; left: 0; right: 0; top: 0; z-index: 30; height: 2px; opacity: 0; pointer-events: none; will-change: transform, opacity;
	background: linear-gradient(90deg, transparent, var(--gold) 18%, var(--gold-light) 50%, var(--gold) 82%, transparent);
	box-shadow: 0 0 8px 1px rgb(226 196 99 / .7), 0 0 22px 4px rgb(226 196 99 / .3); }
/* The gold thread (fun.js): a hairline on the right edge that fills with the page. It runs through the rail's dots where
   the rail shows, and stops 12px above the round corner buttons */
.thread { position: fixed; z-index: 39; right: 6px; top: calc(env(safe-area-inset-top) + 12px); bottom: calc(max(16px, env(safe-area-inset-bottom)) + 56px); width: 2px; border-radius: 1px; background: rgb(201 162 39 / .28); opacity: 0; pointer-events: none; transition: opacity .6s var(--ease-gentle); }
@media (min-width: 600px) { .thread { right: calc(max(10px, env(safe-area-inset-right)) + 13px); } } /* the centre of the rail's 28px buttons */
.thread.is-on { opacity: 1; }
.thread__fill { position: absolute; inset: 0; border-radius: inherit; background: linear-gradient(var(--gold-light), var(--gold)); box-shadow: 0 0 4px rgb(226 196 99 / .6); transform-origin: 50% 0; will-change: transform; }
.thread__bead { position: absolute; left: 50%; top: 0; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; background: radial-gradient(circle, #FFF6D6 0 22%, var(--gold-light) 45%, rgb(201 162 39 / 0) 72%); box-shadow: 0 0 10px 2px rgb(226 196 99 / .45); will-change: transform, opacity; }
