/* ==========================================================================
   Enchant layer: falling petals, scene transitions and smooth navigation.
   Loaded after styles.css so it can refine the existing motion system.
   ========================================================================== */

:root {
  --enchant-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --enchant-blush: 244, 196, 196;
  --enchant-gold: 222, 189, 140;
}

/* The canvas petal sky replaces the old handful of CSS petals. */
.petals {
  display: none !important;
}

.petal-sky {
  position: fixed;
  inset: 0;
  z-index: 1100;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Staggered reveals: siblings cascade in instead of appearing together.
   -------------------------------------------------------------------------- */

/* Reveals animate only opacity and transform so the GPU can composite them.
   The old blur(10px) filter forced large photo cards to repaint every frame. */
html.reveal-enabled .reveal,
html.reveal-enabled .reveal.is-visible {
  filter: none !important;
  transition:
    opacity 0.85s ease calc(var(--stagger, 0) * 110ms),
    transform 1s var(--enchant-ease) calc(var(--stagger, 0) * 110ms) !important;
}

/* --------------------------------------------------------------------------
   Scroll performance fixes for the base theme.
   -------------------------------------------------------------------------- */

/* A fixed background repaints the whole section on every scroll frame;
   enchant.js drives a composited parallax on this layer instead. */
.quote-image {
  background-attachment: scroll !important;
  inset: -12% 0 !important;
  will-change: transform;
}

/* These panels are ~80% opaque, so the backdrop blur was invisible but
   re-rendered continuously while the story camera moved. */
.story-step__glass {
  backdrop-filter: none !important;
}

.story-hud {
  backdrop-filter: none !important;
  background: rgba(22, 15, 12, 0.58) !important;
}

/* The camera transform is written per frame by app.js; a CSS transition on
   top of that restarts every frame and lags behind the scroll. */
.story-camera {
  transition: none !important;
  will-change: transform;
}

/* Where CSS scroll timelines exist (html.scroll-timeline), the scroll-linked
   motion runs on the compositor instead of a JS write per scroll frame, so a
   busy main thread never makes it lag. Same curves as the JS fallback. */
/* Off-screen sections skip rendering; their measured height (enchant.js,
   initLazySections) holds their place. */
html.lazy-sections :is(main > section:not(#home), .site-footer) {
  content-visibility: auto;
  contain-intrinsic-block-size: auto var(--section-height, 900px);
}

/* Story: 0 when the block's top meets the viewport top, 1 when its bottom
   meets the viewport bottom ("contain"). */
html.scroll-timeline .story-experience {
  view-timeline: --story block;
}

html.scroll-timeline #storyProgress {
  animation: storyProgress linear both;
  animation-timeline: --story;
  animation-range: contain;
}

@keyframes storyProgress {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

html.scroll-timeline:not([data-effects="off"]) .story-camera {
  animation: storyCamera linear both;
  animation-timeline: --story;
  animation-range: contain;
}

@keyframes storyCamera {
  from { transform: translate3d(0, 6px, 0) rotateZ(-1.1deg); }
  to { transform: translate3d(0, -6px, 0) rotateZ(1.1deg); }
}

/* Quote photo: ±10% of the section height while the section crosses the
   viewport. The photo is 124% of the section tall, so that is ±8.06% of it.
   The timeline sits on the section, since the photo's own clipping parent
   would count as its scroller. filmDrift (scale) keeps running alongside. */
html.scroll-timeline .quote-break {
  view-timeline: --quote block;
}

html.scroll-timeline:not([data-effects="off"]) body #quote .quote-image {
  animation: filmDrift 26s ease-in-out infinite alternate, quoteParallax linear both;
  animation-timeline: auto, --quote;
  animation-range: normal, cover;
}

@keyframes quoteParallax {
  from { transform: translate3d(0, -8.065%, 0); }
  to { transform: translate3d(0, 8.065%, 0); }
}

/* A permanent will-change gave every card its own GPU layer, so each frame had
   ~80 layers to commit. Promote a card only while the pointer is tilting it. */
[data-tilt],
.person-card,
.origin-place,
.event-card,
.gallery-item,
.qr-card,
.wish-form,
.wish-wall {
  will-change: auto !important;
}

[data-tilt].is-tilting,
.is-tilting {
  will-change: transform !important;
}

/* The full-screen film-grain overlay is static. On 1x screens Chrome may leave
   a fixed element unpromoted and repaint it with every scroll step; giving it
   its own layer means it is rasterised once and only composited afterwards. */
body::before {
  will-change: transform;
  transform: translateZ(0);
}

/* Fireflies are drawn in the petal canvas now (see enchant.js). */
.luxury-fireflies {
  display: none !important;
}

/* Looping decorations rest while their section is out of view. The repeated
   class out-ranks base rules such as `body.hero-ready .scroll-cue i::after`
   that set their animation shorthand with !important. */
.is-offscreen.is-offscreen.is-offscreen,
.is-offscreen.is-offscreen.is-offscreen *,
.is-offscreen.is-offscreen.is-offscreen::before,
.is-offscreen.is-offscreen.is-offscreen::after,
.is-offscreen.is-offscreen.is-offscreen *::before,
.is-offscreen.is-offscreen.is-offscreen *::after {
  animation-play-state: paused !important;
}

/* --------------------------------------------------------------------------
   Headings rise word by word as their scene arrives.
   -------------------------------------------------------------------------- */

.scenes-enabled .word-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding: 0 0.06em 0.12em;
  margin: 0 -0.06em -0.12em;
}

.scenes-enabled .word {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, 105%, 0) rotate(5deg);
  transform-origin: 0 100%;
  transition:
    transform 1.1s var(--enchant-ease),
    opacity 0.9s ease;
  transition-delay: calc(var(--w, 0) * 80ms + 180ms);
}

.scenes-enabled .scene-in .word {
  opacity: 1;
  transform: none;
}

/* --------------------------------------------------------------------------
   Photos fade in and settle from a gentle zoom (compositor-only properties).
   -------------------------------------------------------------------------- */

.scenes-enabled .portrait-frame img,
.scenes-enabled .gallery-item img {
  transition:
    opacity 1.2s ease,
    transform 1.8s var(--enchant-ease);
  transition-delay: calc(var(--stagger, 0) * 110ms + 150ms);
}

.scenes-enabled section:not(.scene-in) .portrait-frame img,
.scenes-enabled section:not(.scene-in) .gallery-item img {
  opacity: 0;
  transform: scale(1.18);
}

.scenes-enabled .gallery-item:hover img {
  transform: scale(1.06);
  transition-delay: 0s;
}

/* --------------------------------------------------------------------------
   Section scenes: a soft champagne glow blooms behind each new chapter.
   -------------------------------------------------------------------------- */

.scenes-enabled main > section {
  position: relative;
}

.scenes-enabled main > section > .section-heading::before,
.scenes-enabled main > section > .gallery-heading::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 40%;
  width: min(620px, 90vw);
  aspect-ratio: 1;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    circle,
    rgba(var(--enchant-blush), 0.32) 0%,
    rgba(var(--enchant-gold), 0.12) 38%,
    transparent 68%
  );
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.6);
  transition:
    opacity 1.6s ease,
    transform 2.2s var(--enchant-ease);
}

.scenes-enabled .section-heading,
.scenes-enabled .gallery-heading {
  position: relative;
  isolation: isolate;
}

.scenes-enabled .scene-in > .section-heading::before,
.scenes-enabled .scene-in > .gallery-heading::before {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* Chapter numbers draw a fine gold rule as they appear. */
.scenes-enabled .section-number {
  position: relative;
}

.scenes-enabled .section-number::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -8px;
  width: 64px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgb(var(--enchant-gold)), transparent);
  transform: translateX(-50%) scaleX(0);
  transition: transform 1.4s var(--enchant-ease) 0.3s;
}

.scenes-enabled .gallery-heading .section-number::after {
  left: 0;
  transform: scaleX(0);
  transform-origin: left;
}

.scenes-enabled .scene-in .section-number::after {
  transform: translateX(-50%) scaleX(1);
}

.scenes-enabled .scene-in .gallery-heading .section-number::after {
  transform: scaleX(1);
}

/* --------------------------------------------------------------------------
   Navigation veil: a rose-gold wash that sweeps across while gliding
   between chapters, and a warm bloom when the seal is broken.
   -------------------------------------------------------------------------- */

.scene-veil {
  position: fixed;
  inset: -20%;
  z-index: 1050;
  pointer-events: none;
  opacity: 0;
  background:
    radial-gradient(ellipse at 30% 40%, rgba(var(--enchant-blush), 0.55), transparent 55%),
    radial-gradient(ellipse at 70% 60%, rgba(var(--enchant-gold), 0.4), transparent 55%);
}

.scene-veil.is-active {
  animation: veilSweep 1.3s var(--enchant-ease);
}

.scene-veil.is-bloom {
  background: radial-gradient(
    circle at 50% 50%,
    rgba(255, 246, 236, 0.95) 0%,
    rgba(var(--enchant-blush), 0.6) 30%,
    rgba(var(--enchant-gold), 0.2) 55%,
    transparent 75%
  );
  animation: sealBloom 2.4s var(--enchant-ease);
}

@keyframes veilSweep {
  0% {
    opacity: 0;
    transform: translate3d(-12%, 0, 0);
  }
  35% {
    opacity: 0.85;
  }
  100% {
    opacity: 0;
    transform: translate3d(12%, 0, 0);
  }
}

@keyframes sealBloom {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  25% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: scale(1.6);
  }
}

/* --------------------------------------------------------------------------
   Hero title shimmer after the invitation opens.
   -------------------------------------------------------------------------- */

body.hero-ready .hero-title em {
  animation: ampGlow 4.5s ease-in-out 1.6s infinite;
}

@keyframes ampGlow {
  0%,
  100% {
    text-shadow: 0 0 0 rgba(var(--enchant-gold), 0);
  }
  50% {
    text-shadow:
      0 0 18px rgba(var(--enchant-gold), 0.75),
      0 0 42px rgba(var(--enchant-blush), 0.55);
  }
}

@media (prefers-reduced-motion: reduce) {
  html[data-effects="off"] .scenes-enabled .word,
  html[data-effects="off"] .scenes-enabled .portrait-frame img,
  html[data-effects="off"] .scenes-enabled .gallery-item img,
  html[data-effects="off"] .scenes-enabled section:not(.scene-in) .portrait-frame img,
  html[data-effects="off"] .scenes-enabled section:not(.scene-in) .gallery-item img {
    opacity: 1;
    transform: none;
    transition: none;
  }

  html[data-effects="off"] .scene-veil {
    display: none;
  }
}

/* ==========================================================================
   Chibi couple
   ========================================================================== */

.chibi {
  position: absolute;
  pointer-events: none;
}

.chibi__rig {
  width: 100%;
  height: 100%;
  transform-origin: 50% 100%;
  transition:
    opacity 0.6s ease,
    transform 0.6s cubic-bezier(0.5, 0, 0.75, 0);
}

.chibi svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  /* A warm rim light keeps the dark tuxedo and hair readable on the dark gate. */
  filter:
    drop-shadow(0 0 1.2px rgba(255, 238, 205, 0.75))
    drop-shadow(0 0 10px rgba(255, 214, 150, 0.22))
    drop-shadow(0 10px 14px rgba(20, 10, 6, 0.3));
}

/* SVG transforms use user units, so origins are given in viewBox pixels. */
.chibi__upper { transform-origin: 60px 124px; }
.chibi__leg--l { transform-origin: 52px 118px; }
.chibi__leg--r { transform-origin: 67px 118px; }
.chibi__gown { transform-origin: 60px 108px; }
.chibi__eyes { transform-origin: 60px 64px; }
.chibi--groom .chibi__arm--l { transform-origin: 41px 98px; }
.chibi--groom .chibi__arm--r { transform-origin: 79px 98px; }
.chibi--bride .chibi__arm--l { transform-origin: 44px 99px; }
.chibi--bride .chibi__arm--r { transform-origin: 76px 99px; }

.chibi__happy {
  opacity: 0;
}

.chibi__eyes {
  animation: chibiBlink 4.2s infinite;
}

.chibi--groom .chibi__eyes {
  animation-delay: -1.7s;
}

/* Running in: legs, arms and gown swing, the body bobs and leans forward. */
.chibi[data-state="running"] .chibi__rig {
  animation: chibiBob 0.32s ease-in-out infinite;
}

.chibi--bride[data-state="running"] svg { transform: rotate(7deg); }
.chibi--groom[data-state="running"] svg { transform: rotate(-7deg); }

.chibi[data-state="running"] .chibi__leg--l { animation: chibiStride 0.32s ease-in-out infinite alternate; }
.chibi[data-state="running"] .chibi__leg--r { animation: chibiStride 0.32s ease-in-out infinite alternate-reverse; }
.chibi--bride[data-state="running"] .chibi__leg { animation-name: chibiPatter; }
.chibi[data-state="running"] .chibi__arm--l { animation: chibiArmSwing 0.32s ease-in-out infinite alternate; }
.chibi[data-state="running"] .chibi__arm--r { animation: chibiArmSwing 0.32s ease-in-out infinite alternate-reverse; }
.chibi--bride[data-state="running"] .chibi__arm--l { animation: none; }
.chibi[data-state="running"] .chibi__gown { animation: chibiSway 0.32s ease-in-out infinite alternate; }

/* A polite bow with closed, smiling eyes. */
.chibi[data-state="bowing"] .chibi__upper {
  animation: chibiBow 1.25s cubic-bezier(0.45, 0, 0.3, 1) both;
}

.chibi--groom[data-state="bowing"] .chibi__upper { animation-delay: 0.12s; }

.chibi[data-state="bowing"] .chibi__happy,
.chibi[data-state="celebrating"] .chibi__happy,
.chibi[data-state="waving"] .chibi__happy {
  opacity: 1;
}

.chibi[data-state="bowing"] .chibi__eyes,
.chibi[data-state="celebrating"] .chibi__eyes,
.chibi[data-state="waving"] .chibi__eyes {
  opacity: 0;
}

/* Inviting: the arm nearest the card points at it and waves now and then. */
.chibi--groom[data-state="inviting"] .chibi__arm--l {
  animation:
    groomInvite 1.4s cubic-bezier(0.3, 0.7, 0.3, 1) forwards,
    groomWave 3.4s ease-in-out 1.4s infinite;
}

.chibi--bride[data-state="inviting"] .chibi__arm--r {
  animation:
    brideInvite 1.4s cubic-bezier(0.3, 0.7, 0.3, 1) forwards,
    brideWave 3.4s ease-in-out 1.9s infinite;
}

.chibi[data-state="inviting"] .chibi__rig,
.chibi[data-state="waving"] .chibi__rig {
  animation: chibiBreathe 3s ease-in-out infinite;
}

/* Waving goodbye in the footer. */
.chibi--groom[data-state="waving"] .chibi__arm--l {
  transform: rotate(82deg);
  animation: groomWave 2.2s ease-in-out infinite;
}

.chibi--bride[data-state="waving"] .chibi__arm--r {
  transform: rotate(-82deg);
  animation: brideWave 2.2s ease-in-out -1.1s infinite;
}

.chibi[data-state="celebrating"] .chibi__rig {
  animation: chibiHop 0.62s cubic-bezier(0.3, 0.7, 0.4, 1);
}

.chibi[data-state="leaving"] .chibi__rig {
  opacity: 0;
  transform: translateY(14px) scale(0.86);
}

/* Speech bubbles lean toward the card so they never leave the screen. */
.chibi-bubble {
  position: absolute;
  bottom: 100%;
  margin-bottom: 4px;
  padding: 7px 13px 8px;
  border: 1px solid rgba(201, 161, 91, 0.45);
  border-radius: 999px;
  background: #fffaf2;
  box-shadow: 0 10px 24px rgba(20, 10, 6, 0.22);
  color: #8f5e56;
  font-family: var(--serif, serif);
  font-size: 15px;
  font-style: italic;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(8px) scale(0.6);
  transition:
    opacity 0.4s ease,
    transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.chibi--bride .chibi-bubble {
  left: 40%;
  transform-origin: 0 100%;
}

.chibi--groom .chibi-bubble {
  right: 40%;
  transform-origin: 100% 100%;
}

.chibi[data-state="inviting"] .chibi-bubble,
.chibi[data-state="waving"] .chibi-bubble {
  opacity: 1;
  transform: none;
  animation: bubbleFloat 3s ease-in-out 0.5s infinite;
}

.chibi--groom[data-state="inviting"] .chibi-bubble {
  transition-delay: 0.25s;
}

/* Below the card (narrow screens) the bubbles sit beside the heads, staggered
   like a short conversation, so they never cover the card.*/
.gate-couple.is-below .chibi-bubble {
  bottom: auto;
  margin: 0;
}

.gate-couple.is-below .chibi--bride .chibi-bubble {
  top: 14%;
  left: 100%;
  margin-left: 4px;
}

.gate-couple.is-below .chibi--groom .chibi-bubble {
  top: 50%;
  right: 100%;
  margin-right: 4px;
}

@keyframes chibiBlink {
  0%, 93%, 100% { transform: scaleY(1); }
  95.5% { transform: scaleY(0.12); }
}

@keyframes chibiBob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-7%); }
}

@keyframes chibiStride {
  from { transform: rotate(-30deg); }
  to { transform: rotate(30deg); }
}

@keyframes chibiPatter {
  from { transform: translateY(0); }
  to { transform: translateY(-5px); }
}

@keyframes chibiArmSwing {
  from { transform: rotate(-28deg); }
  to { transform: rotate(28deg); }
}

@keyframes chibiSway {
  from { transform: skewX(-6deg); }
  to { transform: skewX(6deg); }
}

@keyframes chibiBow {
  0% { transform: none; }
  35%, 62% { transform: translateY(12px) scaleY(0.86); }
  100% { transform: none; }
}

@keyframes chibiBreathe {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(1.018); }
}

@keyframes chibiHop {
  0%, 100% { transform: translateY(0); }
  40% { transform: translateY(-26%); }
  70% { transform: translateY(-4%); }
}

@keyframes groomInvite {
  0% { transform: rotate(0); }
  45% { transform: rotate(92deg); }
  70% { transform: rotate(74deg); }
  100% { transform: rotate(82deg); }
}

@keyframes groomWave {
  0%, 30%, 100% { transform: rotate(82deg); }
  10% { transform: rotate(66deg); }
  20% { transform: rotate(94deg); }
}

@keyframes brideInvite {
  0% { transform: rotate(0); }
  45% { transform: rotate(-92deg); }
  70% { transform: rotate(-74deg); }
  100% { transform: rotate(-82deg); }
}

@keyframes brideWave {
  0%, 30%, 100% { transform: rotate(-82deg); }
  10% { transform: rotate(-66deg); }
  20% { transform: rotate(-94deg); }
}

@keyframes bubbleFloat {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -4px; }
}

/* ==========================================================================
   Gate ceremony: chibis on stage, gatefold doors, push-through exit
   Every moving part animates only transform/scale/opacity so the opening
   runs on the compositor even while the page behind it is being restyled.
   ========================================================================== */

#invitationGate .gate-couple {
  position: absolute;
  inset: 0;
  z-index: 40;
  pointer-events: none;
}

/* Built ahead of time and kept faintly painted (not 0, which Chrome may skip
   rasterising) so swapping them in costs nothing. */
#invitationGate .gate-doors {
  position: absolute;
  z-index: 30;
  perspective: 2200px;
  pointer-events: none;
  opacity: 0.001;
  will-change: opacity;
}

#invitationGate.is-unfolding .gate-doors {
  opacity: 1;
}

#invitationGate.is-unfolding > .invitation-cover,
#invitationGate.is-unfolding > .invitation-cover * {
  visibility: hidden !important;
}

/* The couple's exit inside the gate also needs its motion back. */
html body #invitationGate .chibi__rig {
  transition:
    opacity 0.6s ease,
    transform 0.6s cubic-bezier(0.5, 0, 0.75, 0) !important;
}

html body #invitationGate .chibi[data-state="celebrating"] .chibi__rig {
  animation: chibiHop 0.62s cubic-bezier(0.3, 0.7, 0.4, 1) !important;
}

/* Warm light spilling from the seam between the doors. */
#invitationGate .gate-doors::before {
  content: "";
  position: absolute;
  inset: -14% -30%;
  background: radial-gradient(
    ellipse at 50% 50%,
    rgba(255, 246, 222, 0.82) 0%,
    rgba(255, 222, 160, 0.5) 20%,
    rgba(232, 182, 112, 0.18) 42%,
    transparent 64%
  );
  opacity: 0;
  transform: scaleX(0.04);
  will-change: transform, opacity;
}

#invitationGate .gate-doors.is-opening::before {
  animation: seamLight 2.6s cubic-bezier(0.3, 0, 0.2, 1) forwards !important;
}

#invitationGate .gate-door {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  will-change: transform;
}

/* styles.css stops every animation inside the gate once the hero is ready
   (html body.hero-ready .invitation-gate * { transition: none !important }).
   The hero is now readied as the seal is pressed, so the ceremony's own
   motion is restored here with an id-level !important. */
html body #invitationGate .gate-door {
  transition: transform 2.3s cubic-bezier(0.5, 0, 0.25, 1) 0.06s !important;
}

#invitationGate .gate-door--left {
  clip-path: inset(-2% 50% -2% -2%);
  transform-origin: 0 50%;
}

#invitationGate .gate-door--right {
  clip-path: inset(-2% -2% -2% 50%);
  transform-origin: 100% 50%;
}

#invitationGate .gate-doors.is-opening .gate-door--left {
  transform: rotateY(-100deg);
}

#invitationGate .gate-doors.is-opening .gate-door--right {
  transform: rotateY(100deg);
}

/* The copies are plain stills of the closed card. */
html body #invitationGate .gate-door .gate-door__card {
  position: absolute !important;
  inset: auto !important;
  top: 0 !important;
  left: 0 !important;
  margin: 0 !important;
  opacity: 1 !important;
  visibility: visible !important;
  transform: none !important;
  animation: none !important;
}

html body #invitationGate .gate-door .invitation-cover__paper {
  opacity: 1 !important;
  filter: none !important;
  transform: none !important;
  animation: none !important;
}

/* Each door darkens as it turns away, with a gilded edge along the seam. */
#invitationGate .gate-door__shade {
  position: absolute;
  inset: 0;
  opacity: 0;
}

html body #invitationGate .gate-door__shade {
  transition: opacity 2.3s ease 0.06s !important;
}

#invitationGate .gate-door--left .gate-door__shade {
  background: linear-gradient(90deg, rgba(40, 24, 14, 0.15), rgba(40, 24, 14, 0.6) 50%, transparent 50%);
}

#invitationGate .gate-door--right .gate-door__shade {
  background: linear-gradient(270deg, rgba(40, 24, 14, 0.15), rgba(40, 24, 14, 0.6) 50%, transparent 50%);
}

#invitationGate .gate-doors.is-opening .gate-door__shade {
  opacity: 1;
}

#invitationGate .gate-door::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(50% - 1.5px);
  width: 3px;
  background: linear-gradient(180deg, transparent, #f3d38f 18%, #fff3d0 50%, #f3d38f 82%, transparent);
  box-shadow: 0 0 18px 4px rgba(255, 218, 150, 0.75);
  opacity: 0;
  transition: opacity 0.3s ease !important;
}

#invitationGate .gate-doors.is-opening .gate-door::after {
  opacity: 1;
}

/* Settle: the card glides back from its hover tilt instead of snapping flat,
   and the seal is pressed (transform only; the old break animated a filter). */
html body #invitationGate.is-ceremony > .invitation-cover .invitation-cover__paper {
  transform: none !important;
  transition: transform 0.36s cubic-bezier(0.3, 0.7, 0.3, 1) !important;
}

html body #invitationGate.is-ceremony .seal-button {
  animation: sealPress 0.5s cubic-bezier(0.3, 0.7, 0.3, 1) forwards !important;
}

/* Older opening effects animated blur filters and backgrounds full-screen,
   repainting every frame. The doors and seam light replace them. */
html body #invitationGate.is-ceremony::before {
  animation: none !important;
}

html body #invitationGate.is-ceremony .cover-afterglow {
  display: none !important;
}

/* Keep the gate on screen while it opens; an older rule hides it outright
   the moment the hero is revealed. */
html body.hero-ready #invitationGate.is-ceremony:not([hidden]) {
  display: grid !important;
  opacity: 1 !important;
  visibility: visible !important;
  pointer-events: none !important;
}

/* Exit: the scene drifts toward the camera through the open doors and fades.
   `scale` composes with each layer's own positioning transform. */
html body #invitationGate.is-departing:not([hidden]) {
  background: transparent !important;
}

html body #invitationGate.is-departing > :not(.invitation-cover) {
  animation: gatePushThrough 1.5s cubic-bezier(0.45, 0, 0.2, 1) forwards !important;
}

@keyframes gatePushThrough {
  from {
    opacity: 1;
    scale: 1;
  }
  to {
    opacity: 0;
    scale: 1.14;
  }
}

@keyframes sealPress {
  0% { scale: 1; }
  40% { scale: 0.86; }
  100% { scale: 1.06; }
}

@keyframes seamLight {
  0% { opacity: 0; transform: scaleX(0.04); }
  15% { opacity: 1; transform: scaleX(0.12); }
  70% { opacity: 1; transform: scaleX(1); }
  100% { opacity: 0.85; transform: scaleX(1.25); }
}

/* ==========================================================================
   Footer couple
   ========================================================================== */

#thanks .footer-couple {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: 4px;
  height: clamp(110px, 12vw, 140px);
  margin: 0 auto clamp(14px, 2vw, 24px);
}

#thanks .footer-couple .chibi {
  position: relative;
  width: calc(clamp(110px, 12vw, 140px) * 0.706);
  height: 100%;
}

#thanks.has-couple .footer-petal {
  display: none !important;
}

/* ==========================================================================
   Hero names in gold foil
   ========================================================================== */

body.hero-ready #home .hero-title span {
  background: linear-gradient(
    100deg,
    #fff8ec 0%,
    #fff8ec 38%,
    #f6d99a 46%,
    #fffdf6 50%,
    #e9c27a 54%,
    #fff8ec 62%,
    #fff8ec 100%
  );
  background-size: 300% 100%;
  background-position: 100% 0;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  /* background-clip: text only paints inside the box; pad it so marks below
     the baseline (the dot in "Lựu") and tone marks above stay visible. */
  padding: 0.12em 0.06em 0.24em;
  margin: -0.12em -0.06em -0.24em;
  animation: foilSweep 7s ease-in-out 2.8s infinite;
}

@keyframes foilSweep {
  0% { background-position: 100% 0; }
  45%, 100% { background-position: 0% 0; }
}

@media (prefers-reduced-motion: reduce) {
  html[data-effects="off"] .chibi *,
  html[data-effects="off"] .chibi__rig,
  html[data-effects="off"] body.hero-ready #home .hero-title span {
    animation: none !important;
  }
}

/* ==========================================================================
   Chibi guide: the couple walks along in the corner and acts out each chapter
   ========================================================================== */

.chibi__prop,
.chibi__kneel {
  opacity: 0;
  transition: opacity 0.35s ease;
}

.chibi__head {
  transform-origin: 60px 88px;
}

.chibi-guide {
  --guide-h: 118px;
  --guide-w: calc(var(--guide-h) * 0.706);
  position: fixed;
  left: max(14px, env(safe-area-inset-left));
  bottom: 12px;
  z-index: 1090;
  width: calc(var(--guide-w) * 1.75);
  height: var(--guide-h);
  pointer-events: none;
  opacity: 0;
  transform: translateX(-140%);
  transition:
    transform 1.1s cubic-bezier(0.3, 0.7, 0.3, 1),
    opacity 0.5s ease;
}

.chibi-guide.is-shown {
  opacity: 1;
  transform: none;
}

.chibi-guide__stage {
  position: absolute;
  inset: 0;
}

@media (hover: hover) and (pointer: fine) {
  .chibi-guide.is-shown .chibi-guide__stage {
    pointer-events: auto;
    cursor: pointer;
  }
}

.chibi-guide .chibi {
  top: 0;
  width: var(--guide-w);
  height: var(--guide-h);
}

.chibi-guide .chibi--bride {
  left: 0;
}

/* Overlapping by a quarter puts the inner hands within reach of each other. */
.chibi-guide .chibi--groom {
  left: calc(var(--guide-w) * 0.75);
}

.chibi-guide .chibi__rig,
.chibi-guide .chibi__arm,
.chibi-guide .chibi__upper,
.chibi-guide .chibi__head {
  transition: transform 0.6s cubic-bezier(0.3, 0.7, 0.3, 1);
}

.chibi-guide .chibi__leg {
  transition: opacity 0.3s ease;
}

/* Speech bubble */
.chibi-guide__bubble {
  position: absolute;
  left: 6%;
  bottom: calc(var(--guide-h) * 1.24);
  width: max-content;
  max-width: min(300px, 72vw);
  padding: 8px 14px 9px;
  border: 1px solid rgba(201, 161, 91, 0.45);
  border-radius: 16px 16px 16px 4px;
  background: #fffaf2;
  box-shadow: 0 12px 28px rgba(20, 10, 6, 0.22);
  color: #8f5e56;
  font-family: var(--serif, serif);
  font-size: 15.5px;
  font-style: italic;
  font-weight: 600;
  line-height: 1.25;
  opacity: 0;
  transform: translateY(8px) scale(0.85);
  transform-origin: 0 100%;
  transition:
    opacity 0.25s ease,
    transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.chibi-guide__bubble.is-shown {
  opacity: 1;
  transform: none;
}

/* ── Walking while the page scrolls ───────────────────────────────── */

.chibi-guide.is-walking .chibi__rig {
  animation: chibiBob 0.34s ease-in-out infinite;
}

.chibi-guide.is-walking .chibi--groom .chibi__leg--l { animation: chibiStride 0.34s ease-in-out infinite alternate; }
.chibi-guide.is-walking .chibi--groom .chibi__leg--r { animation: chibiStride 0.34s ease-in-out infinite alternate-reverse; }
.chibi-guide.is-walking .chibi--bride .chibi__leg--l { animation: chibiPatter 0.34s ease-in-out infinite alternate; }
.chibi-guide.is-walking .chibi--bride .chibi__leg--r { animation: chibiPatter 0.34s ease-in-out infinite alternate-reverse; }
.chibi-guide.is-walking .chibi__gown { animation: chibiSway 0.34s ease-in-out infinite alternate; }

/* ── Poses ──────────────────────────────────────────────────────────
   Arm angles match the counter-rotation baked into each prop in enchant.js
   (umbrella 150°, ring 60°, envelope 40°, camera -115°, letter -40°). */

/* Happy closed eyes */
.chibi-guide:is([data-pose="home"], [data-pose="propose"], [data-pose="photo"], [data-pose="shy"]) .chibi--bride .chibi__happy,
.chibi-guide:is([data-pose="home"], [data-pose="date"]) .chibi__happy {
  opacity: 1;
}

.chibi-guide:is([data-pose="home"], [data-pose="propose"], [data-pose="photo"], [data-pose="shy"]) .chibi--bride .chibi__eyes,
.chibi-guide:is([data-pose="home"], [data-pose="date"]) .chibi__eyes {
  opacity: 0;
}

/* hello: both wave */
.chibi-guide[data-pose="hello"] .chibi--bride .chibi__arm--r,
.chibi-guide[data-pose="gift"] .chibi--bride .chibi__arm--r {
  animation: guideWave 1.5s ease-in-out infinite;
}

.chibi-guide[data-pose="hello"] .chibi--groom .chibi__arm--r,
.chibi-guide[data-pose="gift"] .chibi--groom .chibi__arm--r,
.chibi-guide[data-pose="shy"] .chibi--groom .chibi__arm--r {
  animation: guideWave 1.5s ease-in-out -0.5s infinite;
}

/* hand: holding hands, hearts rising between them */
.chibi-guide:is([data-pose="hand"], [data-pose="home"]) .chibi--bride .chibi__arm--r {
  transform: rotate(-55deg);
}

.chibi-guide:is([data-pose="hand"], [data-pose="home"]) .chibi--groom .chibi__arm--l {
  transform: rotate(55deg);
}

/* shy: first meeting, the bride tilts her head */
.chibi-guide[data-pose="shy"] .chibi--bride .chibi__head {
  transform: rotate(-7deg);
}

.chibi-guide[data-pose="shy"] .chibi--bride .chibi__arm--r {
  transform: rotate(-100deg);
}

/* home: leaning in */
.chibi-guide[data-pose="home"] .chibi--bride .chibi__rig {
  transform: rotate(5deg);
}

.chibi-guide[data-pose="home"] .chibi--groom .chibi__rig {
  transform: rotate(-5deg);
}

/* rain: the groom holds an umbrella over both of them */
.chibi-guide[data-pose="rain"] .chibi--groom .chibi__arm--l {
  transform: rotate(150deg);
}

.chibi-guide[data-pose="rain"] .chibi__prop--umbrella {
  opacity: 1;
}

.chibi-guide[data-pose="rain"] .chibi--bride .chibi__rig {
  transform: rotate(4deg);
}

/* propose: down on one knee with a ring, the bride's hand to her face */
.chibi-guide[data-pose="propose"] .chibi--groom .chibi__leg {
  opacity: 0;
}

.chibi-guide[data-pose="propose"] .chibi--groom .chibi__kneel,
.chibi-guide[data-pose="propose"] .chibi__prop--ring {
  opacity: 1;
}

.chibi-guide[data-pose="propose"] .chibi--groom .chibi__upper {
  transform: translateY(12px);
}

.chibi-guide[data-pose="propose"] .chibi--groom .chibi__arm--l {
  transform: rotate(60deg);
}

.chibi-guide[data-pose="propose"] .chibi--bride .chibi__arm--r {
  transform: rotate(-100deg);
}

.chibi-guide[data-pose="propose"] .chibi__sparkle {
  transform-box: fill-box;
  transform-origin: center;
  animation: guideSparkle 1.4s ease-in-out infinite;
}

/* date: cheering */
.chibi-guide[data-pose="date"] .chibi--bride .chibi__arm--r,
.chibi-guide[data-pose="date"] .chibi--groom .chibi__arm--r {
  transform: rotate(-150deg);
}

.chibi-guide[data-pose="date"] .chibi__arm--r {
  animation: none;
}

.chibi-guide[data-pose="date"] .chibi__rig {
  animation: guideCheer 1.6s cubic-bezier(0.3, 0.7, 0.4, 1) infinite;
}

.chibi-guide[data-pose="date"] .chibi--groom .chibi__rig {
  animation-delay: 0.12s;
}

/* invite: both point toward the event cards */
.chibi-guide[data-pose="invite"] .chibi--bride .chibi__arm--r,
.chibi-guide[data-pose="invite"] .chibi--groom .chibi__arm--r,
.chibi-guide[data-pose="wishes"] .chibi--groom .chibi__arm--r {
  transform: rotate(-82deg);
}

/* photo: the groom takes a picture, the bride poses */
.chibi-guide[data-pose="photo"] .chibi--groom .chibi__arm--r {
  transform: rotate(-115deg);
}

.chibi-guide[data-pose="photo"] .chibi__prop--camera {
  opacity: 1;
}

.chibi-guide[data-pose="photo"] .chibi__flash {
  animation: guideFlash 2.8s ease-out 0.6s infinite;
}

.chibi-guide[data-pose="photo"] .chibi--bride .chibi__arm--r {
  transform: rotate(-150deg);
}

.chibi-guide[data-pose="photo"] .chibi--bride .chibi__head {
  transform: rotate(6deg);
}

/* gift: waving, the groom holds a red envelope */
.chibi-guide[data-pose="gift"] .chibi--groom .chibi__arm--l {
  transform: rotate(40deg);
}

.chibi-guide[data-pose="gift"] .chibi__prop--envelope {
  opacity: 1;
}

/* wishes: the bride holds out a love letter */
.chibi-guide[data-pose="wishes"] .chibi--bride .chibi__arm--r {
  transform: rotate(-40deg);
}

.chibi-guide[data-pose="wishes"] .chibi__prop--letter {
  opacity: 1;
}

/* ── Effects ──────────────────────────────────────────────────────── */

.chibi-guide__fx {
  position: absolute;
  inset: -55% -12% 0;
  pointer-events: none;
}

.chibi-guide__rain,
.chibi-guide__hearts {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.5s ease;
}

.chibi-guide[data-pose="rain"] .chibi-guide__rain,
.chibi-guide:is([data-pose="hand"], [data-pose="home"]) .chibi-guide__hearts {
  opacity: 1;
}

.chibi-guide__rain i {
  position: absolute;
  top: 0;
  left: var(--x);
  width: 1.5px;
  height: 14px;
  border-radius: 2px;
  background: linear-gradient(180deg, transparent, rgba(160, 190, 215, 0.85));
  /* Named only while the pose shows it: an invisible infinite animation
     still costs a compositor commit every frame. */
  animation: none 0.9s linear var(--d) infinite;
}

.chibi-guide.is-shown[data-pose="rain"] .chibi-guide__rain i {
  animation-name: guideRain;
}

.chibi-guide.is-shown:is([data-pose="hand"], [data-pose="home"]) .chibi-guide__hearts i {
  animation-name: guideHeart;
}

.chibi-guide__hearts i {
  position: absolute;
  left: 50%;
  bottom: 52%;
  color: #e0817a;
  font-size: 14px;
  font-style: normal;
  opacity: 0;
  animation: none 2.6s ease-out infinite;
}

.chibi-guide__hearts i:nth-child(2) { animation-delay: 0.85s; margin-left: -12px; font-size: 11px; }
.chibi-guide__hearts i:nth-child(3) { animation-delay: 1.7s; margin-left: 9px; font-size: 12px; }

@keyframes guideWave {
  0%, 100% { transform: rotate(-138deg); }
  50% { transform: rotate(-168deg); }
}

@keyframes guideCheer {
  0%, 55%, 100% { transform: none; }
  20% { transform: translateY(-14%); }
  38% { transform: translateY(-3%); }
}

@keyframes guideFlash {
  0%, 82%, 100% { opacity: 0; }
  86% { opacity: 1; }
}

@keyframes guideSparkle {
  0%, 100% { opacity: 0.3; transform: scale(0.6) rotate(0); }
  50% { opacity: 1; transform: scale(1.15) rotate(45deg); }
}

@keyframes guideRain {
  from { transform: translateY(-20px); opacity: 0; }
  15% { opacity: 1; }
  to { transform: translateY(150px); opacity: 0; }
}

@keyframes guideHeart {
  0% { opacity: 0; transform: translate(-50%, 0) scale(0.6); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -60px) scale(1.1); }
}

@media (max-width: 720px) {
  .chibi-guide {
    --guide-h: 78px;
    bottom: 8px;
    left: 8px;
  }

  .chibi-guide__bubble {
    font-size: 13.5px;
    padding: 6px 11px 7px;
  }
}

@media (prefers-reduced-motion: reduce) {
  html[data-effects="off"] .chibi-guide *,
  html[data-effects="off"] .chibi-guide {
    animation: none !important;
  }
}

/* The bride's long hair hides a hand raised above shoulder height, so her
   cheer and pose angle stops where the hand clears the side strands. */
.chibi-guide:is([data-pose="date"], [data-pose="photo"]) .chibi--bride .chibi__arm--r {
  transform: rotate(-100deg);
}

/* ==========================================================================
   Theme picker (theme colours live in theme-<name>.css)
   ========================================================================== */

.theme-picker {
  position: fixed;
  top: max(12px, env(safe-area-inset-top));
  right: max(12px, env(safe-area-inset-right));
  z-index: 2100;
  display: flex;
  gap: 7px;
  padding: 5px;
  border: 1px solid rgba(201, 161, 91, 0.42);
  border-radius: 999px;
  background: rgba(255, 250, 242, 0.82);
  box-shadow: 0 8px 22px rgba(40, 20, 10, 0.16);
}

.theme-picker__swatch {
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.3s ease;
}

.theme-picker__swatch:hover {
  transform: scale(1.12);
}

.theme-picker__swatch[aria-checked="true"] {
  box-shadow: 0 0 0 2px #fffaf2, 0 0 0 3.5px #c9a15b;
}

.theme-picker__swatch--classic { background: linear-gradient(135deg, #fbf8f3 50%, #c4877c 50%); }
.theme-picker__swatch--red { background: linear-gradient(135deg, #fbf3f4 50%, #c8102e 50%); }
.theme-picker__swatch--traditional { background: linear-gradient(135deg, #a3141f 50%, #e0b25a 50%); }

html[data-theme="traditional"] .theme-picker {
  border-color: rgba(224, 178, 90, 0.55);
  background: rgba(96, 12, 20, 0.86);
}

html[data-theme="traditional"] .theme-picker__swatch[aria-checked="true"] {
  box-shadow: 0 0 0 2px #6a0d15, 0 0 0 3.5px #e0b25a;
}

@media (max-width: 720px) {
  .theme-picker {
    gap: 6px;
    padding: 4px;
  }

  .theme-picker__swatch {
    width: 19px;
    height: 19px;
  }
}

.theme-lanterns {
  display: none;
}

/* ==========================================================================
   Hero fireworks
   ========================================================================== */

.hero-fireworks {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Clear hero backdrop: the photo stays softly out of focus behind the arch,
   but bright and clean, with shade only behind the names. */
html body #home .hero-media {
  opacity: 1 !important;
  filter: blur(6px) saturate(1.05) brightness(0.8) !important;
}

html body #home::after {
  opacity: 0 !important;
}

html body #home::before {
  opacity: 0.1 !important;
}

html body #home .hero-grain {
  opacity: 0.04 !important;
}

html body #home .hero-photo-shell {
  opacity: 1 !important;
}

/* Music button: bottom-right, so it never covers the chibi guide (bottom-left). */
html body .music-button {
  left: auto;
  right: max(16px, env(safe-area-inset-right));
  bottom: 16px;
  z-index: 1095;
}

/* Phones: bottom corners are busy (chibi guide, page content), so the music
   button moves to the top-left, opposite the theme picker. */
@media (max-width: 720px) {
  html body .music-button {
    right: auto;
    left: max(12px, env(safe-area-inset-left));
    top: max(12px, env(safe-area-inset-top));
    bottom: auto;
    width: 38px;
    height: 38px;
  }
}

/* Portrait photos in landscape frames: keep the faces in view. */
html body #home .hero-media { background-position: 50% 88% !important; }
html body #home .hero-photo-shell__image { background-position: 50% 6% !important; }
html body #quote .quote-image { background-position: 50% 9% !important; }
html body #save-date .countdown-backdrop { background-position: 50% 78% !important; }
html body #gallery .gallery-item img { object-position: 50% 16%; }
html body #story .story-step__photo img { object-position: 50% 20%; }

/* Touch screens: a backdrop blur is recomputed on every scrolled frame for
   whatever moves underneath, so fixed and glass elements use solid tints. */
@media (pointer: coarse) {
  html body :is(.music-button, .theme-picker, .hero-eyebrow, .button--glass, .portrait-label) {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }

  html body .music-button {
    background: rgba(255, 250, 242, 0.94) !important;
  }
}

/* Lightbox: our swipe handling owns panning; pinch-zoom still works. */
#lightbox {
  touch-action: pinch-zoom;
  overscroll-behavior: contain;
}

#lightbox img {
  will-change: transform;
}

/* Song title, shown for a moment beside the music button. */
.music-toast {
  position: fixed;
  right: 76px;
  bottom: 26px;
  z-index: 1095;
  max-width: min(320px, 70vw);
  padding: 7px 14px;
  border: 1px solid rgba(201, 161, 91, 0.4);
  border-radius: 999px;
  background: rgba(255, 250, 242, 0.95);
  box-shadow: 0 10px 26px rgba(40, 20, 10, 0.18);
  color: #6d4a3e;
  font-family: var(--serif, serif);
  font-size: 15px;
  font-style: italic;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
  opacity: 0;
  transform: translateX(10px);
  transition: opacity 0.35s ease, transform 0.45s cubic-bezier(0.3, 0.7, 0.3, 1);
}

.music-toast.is-shown {
  opacity: 1;
  transform: none;
}

@media (max-width: 720px) {
  .music-toast {
    top: 18px;
    right: auto;
    bottom: auto;
    left: 60px;
    max-width: calc(100vw - 180px);
    font-size: 13.5px;
    transform: translateX(-10px);
  }
}

/* Touch screens: card tilt (desktop hover) is off, but its 3D contexts were
   still promoting dozens of layers that every scrolled frame had to commit. */
@media (pointer: coarse) {
  html body :is(.gallery-item, .person-card, .origin-place, .event-card, .wgift-card, .hero-photo-shell, .reveal, .story-camera, .story-panels, .wish-form, .wish-wall) {
    transform-style: flat !important;
  }

  html body :is(.story-step, .origin-route, .quote-break, .gallery-grid) {
    perspective: none !important;
  }

  html body .story-panel {
    backface-visibility: visible !important;
  }
}

/* Album beyond the first five: the mosaic above places five photos; the
   rest follow in rows of three (two on phones), each a full row height. */
html body #gallery .gallery-grid {
  grid-auto-rows: 300px;
}

html body #gallery .gallery-item:nth-child(n + 6) {
  grid-column: span 4;
  grid-row: auto;
}

@media (max-width: 680px) {
  html body #gallery .gallery-grid {
    grid-auto-rows: 240px;
  }

  html body #gallery .gallery-item:nth-child(n + 6) {
    grid-column: span 1;
  }

  /* An odd one out at the end takes the whole row. */
  html body #gallery .gallery-item:nth-child(n + 6):last-child:nth-child(even) {
    grid-column: 1 / -1;
  }
}

/* Gate on phones: the names were ~60px, crowding the card, and the couple's
   speech bubbles covered the "tap to open" hint pinned to the card's bottom.
   Smaller names; the hint follows the seal; the card's bottom stays clear for
   the couple standing below it (has-couple-below, set by enchant.js). */
@media (max-width: 560px) {
  html body .invitation-gate .invitation-cover .gate-names {
    font-size: clamp(34px, 10.4vw, 46px) !important;
  }
}

html body .invitation-gate.has-couple-below .invitation-cover .gate-content {
  padding-bottom: 96px !important;
}

html body .invitation-gate.has-couple-below .invitation-cover .gate-hint {
  position: relative !important;
  left: auto !important;
  bottom: auto !important;
  margin: 14px auto 0 !important;
  transform: none !important;
}

html body .invitation-gate.has-couple-below .invitation-cover .seal-button {
  margin-bottom: 0 !important;
}

/* Theme tour (enchant.js, initThemeTour): a slow dissolve between themes, the
   theme's name under the picker, and the ▶ replay button in the picker. */
html.theme-touring::view-transition-old(root),
html.theme-touring::view-transition-new(root) {
  animation-duration: 1.2s;
  animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
}

.theme-sweep {
  position: fixed;
  inset: 0;
  z-index: 2050;
  pointer-events: none;
  background: linear-gradient(100deg, transparent 25%, rgba(255, 228, 166, 0.5) 50%, transparent 75%);
}

.theme-picker__tour {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  color: #8a5a2b;
  background: rgba(201, 161, 91, 0.18);
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(201, 161, 91, 0.5);
}

.theme-picker__tour svg {
  width: 11px;
  height: 11px;
  fill: currentColor;
}

/* While touring, the button breathes; tapping it stops the tour. */
html body .theme-picker__tour[aria-pressed="true"] {
  color: #fffaf2;
  background: #c9a15b;
  animation: tourPulse 1.6s ease-in-out infinite;
}

@keyframes tourPulse {
  50% { box-shadow: 0 0 0 4px rgba(201, 161, 91, 0.25); }
}

html[data-theme="traditional"] .theme-picker__tour {
  color: #f3d58c;
  background: rgba(224, 178, 90, 0.16);
}

.theme-toast {
  position: fixed;
  top: calc(max(12px, env(safe-area-inset-top)) + 44px);
  right: max(12px, env(safe-area-inset-right));
  z-index: 2100;
  max-width: calc(100vw - 24px);
  padding: 7px 14px;
  border: 1px solid rgba(201, 161, 91, 0.42);
  border-radius: 999px;
  color: #5b4034;
  background: rgba(255, 250, 242, 0.92);
  box-shadow: 0 8px 22px rgba(40, 20, 10, 0.16);
  font-family: var(--serif, serif);
  font-size: 15px;
  font-style: italic;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity 0.4s ease, transform 0.4s ease;
}

.theme-toast.is-shown {
  opacity: 1;
  transform: none;
}

html[data-theme="traditional"] .theme-toast {
  border-color: rgba(224, 178, 90, 0.55);
  color: #f6e3b4;
  background: rgba(96, 12, 20, 0.9);
}

@media (max-width: 720px) {
  .theme-picker__tour {
    width: 19px;
    height: 19px;
  }

  .theme-toast {
    top: calc(max(12px, env(safe-area-inset-top)) + 36px);
    font-size: 14px;
  }
}
