:root {
  --cream: #f6eadc;
  --ink: #49352d;
  --sage: #708172;
  --glass: rgba(255, 249, 239, .80);
  --shadow: 0 18px 60px rgba(45, 30, 23, .22);
}
* { box-sizing: border-box; }
html, body { margin: 0; background: #c7a985; color: var(--ink); font-family: "DM Sans", system-ui, sans-serif; overscroll-behavior: none; }
body { min-height: 100vh; }
img { user-select: none; -webkit-user-drag: none; }
.chapter { position: relative; }
.stage { position: sticky; top: 0; width: 100%; height: 100svh; overflow: hidden; background: #d9c2a5; }
.chapter-exterior { height: 340svh; }
.chapter-door { height: 330svh; }
.chapter-interior { height: 760svh; }
.world, .door-bg, .door-interior, .door-threshold { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.exterior-world { height: auto; min-height: 170%; width: 100%; object-fit: cover; object-position: center top; transform-origin: 50% 60%; will-change: transform; }
.layer, .interior-layer, .effect { position: absolute; pointer-events: none; will-change: transform, opacity; }
.cloud { opacity: .64; filter: drop-shadow(0 12px 35px rgba(255,255,255,.12)); }
.cloud-1 { width: 62vw; left: -20vw; top: 10vh; }
.cloud-2 { width: 58vw; right: -18vw; top: 23vh; }
.cloud-3 { width: 34vw; left: 37vw; top: 4vh; opacity: .45; }
.bird { width: clamp(80px, 13vw, 210px); }
.bird-1 { left: 13%; top: 19%; }
.bird-2 { right: 12%; top: 28%; transform: scale(.72); }
.bird-3 { left: 57%; top: 10%; transform: scale(.5); }
.branch { width: min(70vw, 900px); top: -5%; }
.branch-left { left: -20%; }
.branch-right { right: -20%; }
.flowers-front { width: 120vw; max-width: 1500px; bottom: -17%; left: 50%; transform: translateX(-50%); }
.scroll-cue { position: absolute; z-index: 20; left: 50%; bottom: max(26px, env(safe-area-inset-bottom)); transform: translateX(-50%); color: white; text-shadow: 0 2px 20px rgba(0,0,0,.45); text-align: center; font-size: 11px; text-transform: uppercase; letter-spacing: .2em; }
.scroll-cue i { display: block; width: 1px; height: 36px; margin: 12px auto 0; background: linear-gradient(white, transparent); animation: cue 1.7s ease-in-out infinite; }
@keyframes cue { 0%,100% { transform: scaleY(.55); opacity:.35; } 50% { transform: scaleY(1); opacity:1; } }
.door-bg { object-position: center center; transform: scale(1.18); will-change: transform, opacity; }
.door-interior { opacity: 0; transform: scale(1.14); will-change: transform, opacity; }
.door-threshold { z-index: 5; opacity: 0; transform: scale(1.10); will-change: transform, opacity; }
.door-panorama-preview { position:absolute; z-index:6; inset:0; overflow:hidden; opacity:0; will-change:opacity,transform; background:#4a392f; }
.door-panorama-preview img { position:absolute; height:116%; width:auto; max-width:none; top:-8%; left:50%; transform:translateX(-50%) scale(1.025); filter:saturate(.96) contrast(1.02); }
.transition-bloom { position:absolute; z-index:9; inset:0; pointer-events:none; opacity:0; background:radial-gradient(circle at 50% 50%, rgba(255,249,232,.92) 0%, rgba(255,244,218,.48) 22%, rgba(255,244,218,0) 62%); mix-blend-mode:screen; will-change:opacity; }
.door-shade { position:absolute; inset:0; background: radial-gradient(circle at 50% 52%, transparent 15%, rgba(23,14,10,.18) 80%); }
.invite-title { position:absolute; z-index:10; width:100%; top:50%; left:0; transform:translateY(-50%); text-align:center; color:#fff9ee; text-shadow:0 3px 35px rgba(0,0,0,.52); will-change: transform, opacity; }
.invite-title .eyebrow, .kicker { text-transform:uppercase; letter-spacing:.22em; font-size:11px; font-weight:500; }
.invite-title h1 { font-family:"Cormorant Garamond", serif; font-weight:500; font-size:clamp(58px, 11vw, 150px); margin:.05em 0; line-height:.82; font-style:italic; }
.invite-title .ornament { display:block; font-size:14px; margin-top:16px; }
.door-panel {
  position:absolute;
  z-index:8;
  top:50%;
  height:112svh;
  width:auto;
  max-width:none;
  object-fit:contain;
  opacity:0;
  transform-style:preserve-3d;
  will-change:transform,opacity;
}
/* Align the generated door assets at the CENTER SEAM.
   The source PNGs contain a little transparent padding along their inner edges,
   so each panel deliberately overlaps the viewport center by 1.6vw.
   This removes the visible slit while the doors are closed; the overlap disappears
   naturally as the 3D opening animation begins. */
.door-left { left:auto; right:48.4%; object-position:right center; transform-origin:0 50%; }
.door-right { left:48.4%; right:auto; object-position:left center; transform-origin:100% 50%; }
.interior-stage { background:#4a392f; perspective:1600px; }
.panorama-wrap { position:absolute; inset:-8%; overflow:hidden; }
.panorama { position:absolute; height:116%; width:auto; max-width:none; top:-8%; left:0; will-change:transform; filter:saturate(.96) contrast(1.02); }
.interior-layer { z-index:5; }
.hanging-plant { width:min(48vw, 560px); left:-12vw; top:-10vh; }
.pendant { width:min(31vw, 360px); right:10vw; top:-17vh; }
.flowers-left { width:min(54vw, 620px); left:-19vw; bottom:-15vh; }
.flowers-right { width:min(56vw, 650px); right:-18vw; bottom:-13vh; }
.chair-front { width:min(38vw, 450px); right:-9vw; bottom:-17vh; }
.table-flowers { width:min(27vw, 320px); left:8vw; bottom:-8vh; }
.effect { inset:0; width:100%; height:100%; object-fit:cover; z-index:6; mix-blend-mode:screen; }
.sun-rays { opacity:.20; }
.bokeh { opacity:.14; animation:bokehFloat 8s ease-in-out infinite alternate; }
.dust { opacity:.18; }
.dust-b { transform:scaleX(-1) translateX(-2%); opacity:.10; animation:dustDrift 12s linear infinite alternate; }
@keyframes bokehFloat { to { transform:translate3d(1.5vw,-1vh,0) scale(1.025); } }
@keyframes dustDrift { to { transform:scaleX(-1) translate3d(2vw,-2vh,0); } }
.vignette { position:absolute; z-index:7; inset:0; pointer-events:none; background:linear-gradient(90deg, rgba(21,15,12,.18), transparent 28%, transparent 72%, rgba(21,15,12,.18)); }
.invitation-card { position:absolute; z-index:12; width:min(86vw, 620px); max-height:84svh; overflow:auto; left:50%; top:50%; transform:translate(-50%,-44%) scale(.96); opacity:0; pointer-events:none; padding:clamp(25px,4vw,46px); border:1px solid rgba(255,255,255,.50); border-radius:28px; background:var(--glass); box-shadow:var(--shadow); backdrop-filter:blur(14px) saturate(1.08); -webkit-backdrop-filter:blur(14px) saturate(1.08); text-align:center; transition:none; }
.invitation-card h2 { font-family:"Cormorant Garamond",serif; font-size:clamp(38px,7vw,70px); line-height:.92; margin:.16em 0 .28em; font-weight:600; }
.invitation-card p { font-size:clamp(13px,2.4vw,17px); line-height:1.65; margin:.45em 0; }
.invitation-card .large { font-family:"Cormorant Garamond",serif; font-size:clamp(23px,4vw,36px); line-height:1.2; }
.invitation-card .small { font-size:12px; opacity:.78; }
.rule { height:1px; width:70px; margin:20px auto; background:rgba(73,53,45,.35); }
.swatches { display:flex; justify-content:center; gap:10px; margin:18px 0 8px; }
.swatches i { width:24px; height:24px; border-radius:50%; box-shadow:inset 0 0 0 1px rgba(0,0,0,.08); }
.pink{background:#e7b7bf}.blue{background:#b8cedc}.yellow{background:#eadb9f}.green{background:#bfd0b1}.violet{background:#c7b6d1}
.names { display:grid; grid-template-columns:2fr 1fr; gap:22px; text-align:left; margin-top:18px; }
.names h3 { font-family:"Cormorant Garamond",serif; font-size:24px; margin:0 0 8px; }
.names p { font-size:11px; line-height:1.5; }
.card-godparents { width:min(92vw,760px); }
.rsvp-actions { display:flex; gap:10px; justify-content:center; flex-wrap:wrap; margin-top:20px; }
.rsvp-actions a { color:#fff; background:var(--sage); text-decoration:none; padding:13px 18px; border-radius:999px; font-size:13px; }
@media (min-width: 900px) {
  .exterior-world { width:min(760px,54vw); left:50%; transform:translateX(-50%); }
  .branch { width:45vw; }
  .flowers-front { width:80vw; }
  .panorama-wrap { inset:-4%; }
  .panorama { height:108%; top:-4%; }
  .invitation-card { width:min(52vw,650px); }
  .card-godparents { width:min(62vw,820px); }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration:.001ms !important; animation-iteration-count:1 !important; }
}


.cinematic { position:relative; height:1450svh; }
.cinematic-stage { position:sticky; top:0; width:100%; height:100svh; overflow:hidden; background:#4a392f; isolation:isolate; }
.scene { position:absolute; inset:0; overflow:hidden; will-change:opacity, transform, filter; }
.scene-exterior { z-index:1; opacity:1; }
.scene-entrance { z-index:2; opacity:0; pointer-events:none; }
.scene-interior { z-index:3; opacity:0; pointer-events:none; background:#4a392f; }

/* Keep source worlds full-bleed. */
.scene .world, .scene .door-bg, .scene .door-interior, .scene .door-threshold { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.scene-exterior .exterior-world { height:auto; min-height:178%; width:100%; object-fit:cover; object-position:center top; transform-origin:50% 70%; }

/* Door layers all overlap, never participate in document flow. */
.scene-entrance .door-bg { z-index:1; opacity:1; }
.scene-entrance .door-interior { z-index:2; opacity:0; }
.scene-entrance .door-threshold { z-index:3; opacity:0; }
.scene-entrance .invite-title { z-index:7; }
.scene-entrance .door-panel { z-index:8; }

/* V8 · single authoritative door geometry.
   No legacy !important transform rules: JavaScript owns the opening animation. */
.scene-entrance .door-panel {
  position: absolute;
  z-index: 8;
  top: 50%;
  width: 50.5vw;
  height: 100svh;
  max-width: none;
  object-fit: fill;
  opacity: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transform-style: preserve-3d;
  will-change: transform, opacity;
}
.scene-entrance .door-left {
  left: 0;
  right: auto;
  object-position: right center;
  transform-origin: 100% 50%;
}
.scene-entrance .door-right {
  left: 49.5vw;
  right: auto;
  object-position: left center;
  transform-origin: 0% 50%;
}
@supports (height:100dvh) {
  .scene-entrance .door-panel { height:100dvh; }
}

/* Interior panorama begins centered, then JS pans it. */
.scene-interior .panorama-wrap { position:absolute; inset:-7%; overflow:hidden; }
.scene-interior .panorama { position:absolute; height:114%; width:auto; max-width:none; top:-7%; left:0; filter:saturate(.96) contrast(1.02); will-change:transform; }

/* Global transition cover objects deliberately sit ABOVE all three worlds. */
.transition-foliage { position:absolute; z-index:20; inset:0; pointer-events:none; opacity:0; overflow:hidden; }
.transition-flower { position:absolute; bottom:-12%; width:72vw; max-width:800px; filter:drop-shadow(0 18px 28px rgba(26,18,13,.18)); will-change:transform,opacity; }
.transition-flower-left { left:-28%; transform-origin:0 100%; }
.transition-flower-right { right:-28%; transform-origin:100% 100%; }
.global-effect { z-index:21 !important; opacity:0; pointer-events:none; }
.transition-bloom { z-index:22 !important; }
.vignette { z-index:23; }
.invitation-card { z-index:30; }
.scroll-cue { z-index:40; }

/* Old multi-chapter selectors no longer control the document. */
.chapter-exterior,.chapter-door,.chapter-interior { height:auto !important; }

@media (min-width:900px) {
  .scene-exterior .exterior-world { width:min(760px,54vw); left:50%; }
  .transition-flower { width:48vw; }
}


/* V8 safety override: geometry only. Never set transform here. */
.scene-entrance img.door-panel {
  width: 50.5vw !important;
  height: 100svh !important;
  max-width: none !important;
  object-fit: fill !important;
}
.scene-entrance img.door-left {
  left: 0 !important;
  right: auto !important;
  transform-origin: 100% 50% !important;
}
.scene-entrance img.door-right {
  left: 49.5vw !important;
  right: auto !important;
  transform-origin: 0% 50% !important;
}
@supports (height:100dvh) {
  .scene-entrance img.door-panel { height:100dvh !important; }
}


/* V9 door correction: oversized half-screen leaves with OUTER hinges.
   The center edges swing away; the outside jamb edges stay planted. */
.scene-entrance img.door-panel {
  width: 51.75vw !important;
  height: 100svh !important;
  max-width: none !important;
  object-fit: fill !important;
  top: 50% !important;
  backface-visibility: hidden !important;
  -webkit-backface-visibility: hidden !important;
}
.scene-entrance img.door-left {
  left: -1.25vw !important;
  right: auto !important;
  transform-origin: 0% 50% !important;
  object-position: right center !important;
}
.scene-entrance img.door-right {
  left: auto !important;
  right: -1.25vw !important;
  transform-origin: 100% 50% !important;
  object-position: left center !important;
}
@supports (height:100dvh) {
  .scene-entrance img.door-panel { height:100dvh !important; }
}

/* =========================================================
   V10 · CROPPED ASSETS + STRONGER CINEMATIC DEPTH
   ========================================================= */

/* New door PNGs are tightly cropped. Each leaf now simply owns half the viewport. */
.scene-entrance img.door-panel {
  width: 50.8vw !important;
  height: 100svh !important;
  top: 50% !important;
  max-width: none !important;
  object-fit: fill !important;
  backface-visibility: hidden !important;
  -webkit-backface-visibility: hidden !important;
}
.scene-entrance img.door-left {
  left: -0.4vw !important;
  right: auto !important;
  transform-origin: 0% 50% !important;
  object-position: center center !important;
}
.scene-entrance img.door-right {
  left: auto !important;
  right: -0.4vw !important;
  transform-origin: 100% 50% !important;
  object-position: center center !important;
}
@supports (height:100dvh) {
  .scene-entrance img.door-panel { height:100dvh !important; }
}

/* Make the interior foreground readable on a phone. These deliberately exceed
   the viewport in places, because they are meant to feel close to the lens. */
.scene-interior .hanging-plant {
  width: min(82vw, 720px);
  left: -27vw;
  top: -15vh;
  filter: blur(1.1px) drop-shadow(0 22px 28px rgba(28,18,12,.24));
}
.scene-interior .pendant {
  width: min(52vw, 470px);
  right: -2vw;
  top: -16vh;
  filter: blur(.35px) drop-shadow(0 18px 24px rgba(28,18,12,.22));
}
.scene-interior .flowers-left {
  width: min(94vw, 820px);
  left: -39vw;
  bottom: -18vh;
  filter: blur(2.3px) drop-shadow(0 28px 35px rgba(28,18,12,.26));
}
.scene-interior .flowers-right {
  width: min(96vw, 840px);
  right: -40vw;
  bottom: -17vh;
  filter: blur(2.6px) drop-shadow(0 30px 38px rgba(28,18,12,.28));
}
.scene-interior .chair-front {
  width: min(72vw, 620px);
  right: -29vw;
  bottom: -21vh;
  filter: blur(3px) drop-shadow(0 34px 42px rgba(20,13,10,.32));
}
.scene-interior .table-flowers {
  width: min(52vw, 440px);
  left: -5vw;
  bottom: -10vh;
  filter: blur(1.5px) drop-shadow(0 24px 30px rgba(28,18,12,.25));
}

/* Stronger exterior depth/transition veil. */
.transition-foliage { z-index: 11 !important; }
.transition-flower-left,
.transition-flower-right {
  width: 82vw !important;
  max-width: 760px !important;
  filter: blur(2px) drop-shadow(0 26px 34px rgba(32,18,12,.26));
}
.branch { filter: drop-shadow(0 22px 34px rgba(25,18,12,.18)); }
.flowers-front { filter: blur(.8px) drop-shadow(0 24px 34px rgba(25,18,12,.20)); }

/* Effects are LANDSCAPE source files. On portrait screens do not use cover,
   because that throws most of the image away. Stretching is visually harmless
   for optical overlays and preserves all of the generated pattern. */
.global-effect {
  position:absolute !important;
  inset:0 !important;
  width:100vw !important;
  height:100svh !important;
  object-fit:fill !important;
  object-position:center center !important;
  max-width:none !important;
  pointer-events:none !important;
}
.sun-rays {
  mix-blend-mode:screen;
  filter: brightness(1.38) contrast(1.12) saturate(1.08);
}
.bokeh {
  mix-blend-mode:screen;
  filter: brightness(1.55) contrast(1.16) saturate(1.08);
}
.dust {
  mix-blend-mode:screen;
  filter: brightness(1.7) contrast(1.22);
}
@supports (height:100dvh) {
  .global-effect { height:100dvh !important; }
}

/* A touch more depth on the master interior while keeping text readable. */
.scene-interior .panorama {
  height: 122%;
  top: -11%;
  filter: saturate(1.01) contrast(1.035) brightness(.98);
}
.scene-interior .panorama-wrap { inset:-10%; }

@media (min-width:900px) {
  .scene-interior .hanging-plant { width:min(46vw,720px); left:-14vw; }
  .scene-interior .pendant { width:min(30vw,470px); right:5vw; }
  .scene-interior .flowers-left { width:min(54vw,820px); left:-20vw; }
  .scene-interior .flowers-right { width:min(56vw,840px); right:-21vw; }
  .scene-interior .chair-front { width:min(39vw,620px); right:-12vw; }
  .scene-interior .table-flowers { width:min(29vw,440px); left:4vw; }
}


/* V11 · faster, livelier doorway crossing */
:root { --rush: 0; --rush-peak: 0; }

/* Existing optical overlays become much more active while crossing the door. */
.fx-rays {
  opacity: calc(.28 + (var(--rush-peak) * .72)) !important;
  transform: scale(calc(1.08 + (var(--rush) * .34)))
             translate3d(calc(var(--rush) * -8vw), calc(var(--rush) * 5vh), 0) !important;
  filter: brightness(1.55) contrast(1.18) blur(.35px) !important;
}
.fx-bokeh {
  opacity: calc(.22 + (var(--rush-peak) * .78)) !important;
  transform: scale(calc(1.18 + (var(--rush) * .58)))
             translate3d(calc(var(--rush) * 12vw), calc(var(--rush) * -7vh), 0) !important;
  filter: brightness(1.65) contrast(1.28) blur(calc(1px + var(--rush) * 3px)) !important;
}
.fx-dust {
  opacity: calc(.30 + (var(--rush-peak) * .70)) !important;
  transform: scale(calc(1.1 + (var(--rush) * .42)))
             translate3d(calc(var(--rush) * -10vw), calc(var(--rush) * -11vh), 0) !important;
  filter: brightness(1.8) contrast(1.35) !important;
}

/* Exterior foliage rushes past the lens as the visitor crosses the threshold. */
.scene-exterior .branch-left,
.scene-exterior .branch-right {
  filter: blur(calc(var(--rush) * 4px)) drop-shadow(0 12px 18px rgba(0,0,0,.16)) !important;
}
.scene-exterior .flowers-front {
  transform: scale(calc(1.05 + var(--rush) * .72))
             translate3d(0, calc(var(--rush) * -12vh), 0) !important;
  filter: blur(calc(.5px + var(--rush) * 5px)) brightness(1.08) !important;
}

/* Interior foreground elements arrive BEFORE the panorama is fully established.
   This hides the through-door/threshold image swaps and makes them feel like
   objects passing close to the camera. */
.scene-interior .flowers-front-left {
  opacity: calc(var(--rush-peak) * .92) !important;
  transform: translate3d(calc(-16vw + var(--rush) * 22vw),
                         calc(12vh - var(--rush) * 18vh),0)
             scale(calc(1.45 + var(--rush) * .75)) !important;
  filter: blur(calc(5px - var(--rush) * 2px))
          drop-shadow(0 18px 30px rgba(0,0,0,.24)) !important;
}
.scene-interior .flowers-front-right {
  opacity: calc(var(--rush-peak) * .9) !important;
  transform: translate3d(calc(18vw - var(--rush) * 24vw),
                         calc(10vh - var(--rush) * 14vh),0)
             scale(calc(1.4 + var(--rush) * .7)) !important;
  filter: blur(calc(4.5px - var(--rush) * 1.8px))
          drop-shadow(0 18px 30px rgba(0,0,0,.22)) !important;
}
.scene-interior .hanging-plant {
  opacity: calc(var(--rush-peak) * .82) !important;
  transform: translate3d(calc(-8vw + var(--rush) * 13vw),
                         calc(-15vh + var(--rush) * 13vh),0)
             scale(calc(1.25 + var(--rush) * .48)) !important;
  filter: blur(calc(3.5px - var(--rush) * 1.4px)) !important;
}
.scene-interior .pendant {
  opacity: calc(var(--rush-peak) * .72) !important;
  transform: translate3d(calc(10vw - var(--rush) * 15vw),
                         calc(-10vh + var(--rush) * 10vh),0)
             scale(calc(1.15 + var(--rush) * .36)) !important;
  filter: blur(calc(2.6px - var(--rush) * 1.1px))
          drop-shadow(0 0 28px rgba(255,220,160,.5)) !important;
}

/* Quick lens bloom at the midpoint instead of lingering on intermediate frames. */
.cinematic::after {
  content:"";
  position:absolute;
  inset:-8%;
  z-index:40;
  pointer-events:none;
  opacity: calc(var(--rush-peak) * .34);
  background: radial-gradient(circle at 50% 48%,
              rgba(255,245,220,.82) 0%,
              rgba(255,235,200,.30) 35%,
              rgba(255,255,255,0) 72%);
  mix-blend-mode: screen;
  transform: scale(calc(.9 + var(--rush) * .35));
}


/* =========================================================
   V11.3 PARALLAX FINE-TUNING
   ========================================================= */

/* Upper exterior flowers: slow scale-up while fading in/out. */
.scene-exterior .branch-left,
.scene-exterior .branch-right {
  transform-origin: top center;
  will-change: transform, opacity, filter;
}

/* Bottom foreground flower bank: always grounded, full width. */
.scene-exterior .flowers-front {
  position: absolute !important;
  left: 0 !important;
  right: auto !important;
  bottom: 0 !important;
  top: auto !important;
  width: 100vw !important;
  height: auto !important;
  max-width: none !important;
  object-fit: contain !important;
  object-position: bottom center !important;
  transform-origin: 50% 100% !important;
}

/* Tone down oversized interior flowers. */
.scene-interior .flowers-front-left,
.scene-interior .flowers-front-right {
  max-width: none !important;
  transform-origin: bottom center !important;
}

/* Landscape effects: keep full image visible on mobile without aggressive cropping. */
.fx-rays,
.fx-bokeh,
.fx-dust {
  position: absolute !important;
  left: 50% !important;
  top: 50% !important;
  width: 150vw !important;
  height: 100svh !important;
  max-width: none !important;
  object-fit: fill !important;
  transform-origin: center center !important;
  pointer-events: none !important;
  will-change: transform, opacity, filter;
}
@supports (height:100dvh) {
  .fx-rays, .fx-bokeh, .fx-dust { height:100dvh !important; }
}

/* Chair system: attached visually to interior plane, no giant floating chair. */
.interior-chair {
  position: absolute;
  z-index: 9;
  height: auto;
  max-width: none;
  opacity: 0;
  transform-origin: bottom center;
  pointer-events: none;
  will-change: transform, opacity, filter;
}
.chair-a {
  width: 24vw;
  bottom: 6vh;
  left: 16vw;
  filter: blur(.4px) drop-shadow(0 10px 18px rgba(0,0,0,.18));
}
.chair-b {
  width: 18vw;
  bottom: 10vh;
  left: 54vw;
  filter: blur(1.2px) drop-shadow(0 8px 14px rgba(0,0,0,.15));
}
.chair-c {
  width: 13vw;
  bottom: 15vh;
  left: 78vw;
  filter: blur(2px) drop-shadow(0 6px 12px rgba(0,0,0,.12));
}

/* Gifts readability. */
.gift-list {
  display: grid;
  gap: .55rem;
  margin-top: .75rem;
}
.gift-list p {
  margin: 0;
}

/* V11.3 override old V11 effect/flower !important transforms so JS can animate them. */
.fx-rays, .fx-bokeh, .fx-dust,
.scene-exterior .branch-left, .scene-exterior .branch-right,
.scene-exterior .flowers-front,
.scene-interior .flowers-front-left, .scene-interior .flowers-front-right {
  animation: none !important;
}
/* Inline JS values must own transform/opacity/filter from here onward. */


/* V11.4 visual-order and transition refinements */
.scene-entrance .door-panel {
  z-index: 8 !important;
}
.scene-entrance .invite-title,
.scene-entrance .entrance-copy,
.scene-entrance .hero-copy,
.scene-entrance .title-wrap,
.scene-entrance [class*="invite"] {
  position: relative;
  z-index: 18 !important;
}

/* Ensure optical FX don't cover invitation typography. */
.fx-rays, .fx-bokeh, .fx-dust { z-index: 12 !important; }
.scene-entrance .invite-title,
.scene-entrance .entrance-copy,
.scene-entrance .hero-copy,
.scene-entrance .title-wrap { z-index: 20 !important; }

/* V11.4: JS owns FX opacity/motion. Override earlier V11 !important burst rules. */
.cinematic .fx-rays,
.cinematic .fx-bokeh,
.cinematic .fx-dust {
  opacity: 0;
}


/* =========================================================
   V11.5 · ACTUAL EFFECT ELEMENTS + HARD FLOWER SIZE CAPS
   ========================================================= */

/* The HTML uses .sun-rays, .bokeh, .dust-a and .dust-b.
   Start ALL real optical overlays hidden. JS decides when each appears. */
.global-effect.sun-rays,
.global-effect.bokeh,
.global-effect.dust-a,
.global-effect.dust-b {
  opacity: 0 !important;
  animation: none !important;
  pointer-events: none !important;
  mix-blend-mode: screen;
  will-change: opacity, transform, translate, filter;
}

/* Landscape source sheets on portrait/mobile.
   Fill the viewport but retain independent sizing for depth. */
.global-effect.sun-rays {
  position: absolute !important;
  left: 50% !important;
  top: 50% !important;
  width: 150vw !important;
  height: 100svh !important;
  object-fit: fill !important;
  max-width: none !important;
  transform-origin: center center !important;
  z-index: 11 !important;
}

.global-effect.bokeh {
  position: absolute !important;
  left: 50% !important;
  top: 50% !important;
  width: 138vw !important;
  height: 100svh !important;
  object-fit: fill !important;
  max-width: none !important;
  transform-origin: center center !important;
  z-index: 12 !important;
}

/* Two dust copies are intentional now:
   one closer/larger and one farther/smaller. */
.global-effect.dust-a {
  position: absolute !important;
  left: 50% !important;
  top: 50% !important;
  width: 142vw !important;
  height: 100svh !important;
  object-fit: fill !important;
  max-width: none !important;
  transform-origin: center center !important;
  z-index: 13 !important;
}

.global-effect.dust-b {
  position: absolute !important;
  left: 50% !important;
  top: 50% !important;
  width: 112vw !important;
  height: 92svh !important;
  object-fit: fill !important;
  max-width: none !important;
  transform-origin: center center !important;
  z-index: 10 !important;
}

/* Ambient motion continues even if the user pauses scrolling.
   `translate` is independent from the JS-driven transform property. */
.global-effect.bokeh {
  animation: v115BokehAmbient 7.5s ease-in-out infinite alternate !important;
}
.global-effect.dust-a {
  animation: v115DustNear 9s ease-in-out infinite alternate !important;
}
.global-effect.dust-b {
  animation: v115DustFar 13s ease-in-out infinite alternate-reverse !important;
}
.global-effect.sun-rays {
  animation: v115RaysBreathe 10s ease-in-out infinite alternate !important;
}

@keyframes v115BokehAmbient {
  from { translate: -1.5vw 1vh; }
  to   { translate: 2.5vw -1.8vh; }
}
@keyframes v115DustNear {
  from { translate: -2vw 3vh; }
  to   { translate: 3vw -3vh; }
}
@keyframes v115DustFar {
  from { translate: 1vw -1vh; }
  to   { translate: -2vw 2vh; }
}
@keyframes v115RaysBreathe {
  from { translate: -1vw 0; }
  to   { translate: 1vw .8vh; }
}

@supports (height: 100dvh) {
  .global-effect.sun-rays,
  .global-effect.bokeh,
  .global-effect.dust-a {
    height: 100dvh !important;
  }
  .global-effect.dust-b {
    height: 92dvh !important;
  }
}

/* HARD CAP: interior foreground flowers stay well below 40vw.
   Even at their JS max scale they remain visually around 35vw. */
.scene-interior .flowers-front-left {
  width: 32vw !important;
  max-width: 32vw !important;
  height: auto !important;
  object-fit: contain !important;
  transform-origin: bottom left !important;
}

.scene-interior .flowers-front-right {
  width: 31vw !important;
  max-width: 31vw !important;
  height: auto !important;
  object-fit: contain !important;
  transform-origin: bottom right !important;
}


/* =========================================================
   V11.6 · native 3:4 optical overlays
   ========================================================= */
.global-effect.sun-rays,
.global-effect.bokeh,
.global-effect.dust-a,
.global-effect.dust-b {
  position: absolute !important;
  left: 50% !important;
  top: 50% !important;
  width: 100vw !important;
  height: auto !important;
  max-width: none !important;
  object-fit: contain !important;
  object-position: center center !important;
  transform-origin: center center !important;
}

/* Slight overscan only, preserving the new 3:4 composition. */
.global-effect.sun-rays { width: 106vw !important; }
.global-effect.bokeh    { width: 104vw !important; }
.global-effect.dust-a   { width: 105vw !important; }
.global-effect.dust-b   { width: 96vw !important; }

/* The new files already have stronger visible content, so keep effects tasteful. */
.global-effect.sun-rays { mix-blend-mode: screen; }
.global-effect.bokeh,
.global-effect.dust-a,
.global-effect.dust-b { mix-blend-mode: screen; }


/* =========================================================
   V11.7 · EFFECT CHOREOGRAPHY + INTERIOR CAMERA ENTRY
   ========================================================= */

/* Effects are now intentionally more visible. JS still owns opacity/timing. */
.global-effect.sun-rays {
  z-index: 14 !important;
  filter: brightness(1.30) contrast(1.06) saturate(1.04) !important;
}
.global-effect.dust-a,
.global-effect.dust-b {
  z-index: 15 !important;
  filter: brightness(1.40) contrast(1.10) saturate(1.06) !important;
}
.global-effect.bokeh {
  z-index: 17 !important;
  filter: brightness(1.28) contrast(1.05) saturate(1.05) blur(1.8px) !important;
}

/* Invitation text stays above doors and rays, but bokeh can briefly veil the transition. */
.scene-entrance .invite-title,
.scene-entrance .entrance-copy,
.scene-entrance .hero-copy,
.scene-entrance .title-wrap,
.scene-entrance [class*="invite"] {
  z-index: 20 !important;
}

/* Interior panorama gets its own camera transform instead of behaving as a flat fade. */
.scene-interior .interior-panorama,
.scene-interior img[src*="mary-grace-interior-panorama"] {
  transform-origin: 50% 50% !important;
  will-change: transform, opacity;
}

/* Save-the-date should feel tied to the camera settling at the left side. */
.scene-interior .save-the-date,
.scene-interior [class*="save"],
.scene-interior [data-card="date"] {
  will-change: opacity, transform;
}
