/* ==========================================================================
   BASE ENGINE STYLES — shared by all templates.
   Theme look (colors/fonts/decorations) is defined per-template in its own
   style.css via the CSS custom properties declared below under :root.
   ========================================================================== */

:root{
  --color-bg: #fffaf5;
  --color-surface: #ffffff;
  --color-text: #3a2e2c;
  --color-text-soft: #7a6b64;
  --color-primary: #b98b73;
  --color-secondary: #e8c9b0;
  --color-accent: #8a5a44;
  --color-line: rgba(138,90,68,.25);
  --font-heading: 'Playfair Display', serif;
  --font-script: 'Great Vibes', cursive;
  --font-body: 'Cormorant Garamond', serif;
  --radius: 18px;
  --max-w: 560px;
  --section-pad: clamp(18px, 6vw, 30px);
  --shadow-soft: 0 20px 60px -20px rgba(0,0,0,.35);
}

*,*::before,*::after{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }
body{
  margin:0;
  font-family: var(--font-body);
  background: #1b1512;
  color: var(--color-text);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  overscroll-behavior-y: none;
}

/* No scrollbar chrome anywhere — scrolling itself still works everywhere. */
html, body, .cover, .main-content, .wishes-list, .lightbox{
  scrollbar-width: none;
  -ms-overflow-style: none;
}
::-webkit-scrollbar{ width: 0; height: 0; background: transparent; }

img{ max-width:100%; display:block; }
a{ color: inherit; text-decoration:none; }
button{ font-family: inherit; cursor:pointer; }
ul{ margin:0; padding:0; list-style:none; }

.frame{
  max-width: var(--max-w);
  margin: 0 auto;
  overflow-x: hidden;   /* fallback for older browsers */
  overflow-x: clip;     /* clips sideways bleed without making .frame a scroller */
  background: var(--color-bg);
  min-height: 100vh;
  min-height: 100dvh;
  position: relative;
  isolation: isolate;
  box-shadow: var(--shadow-soft);
}

/* ---------- Cover / Open Invitation ---------- */
.cover{
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 100vh;
  height: 100svh;      /* smallest viewport: fits even with the mobile URL bar shown */
  overflow: hidden;    /* the cover always fits — it never scrolls */
  max-width: var(--max-w);
  margin: 0 auto;
  z-index: 500;
  display:flex;
  flex-direction: column;
  align-items:center;
  justify-content:center;
  text-align:center;
  padding: clamp(14px, 4vh, 40px) clamp(16px, 5vw, 28px);
  background: var(--color-bg);
  transition: transform .9s cubic-bezier(.77,0,.18,1), opacity .9s ease;
}
.cover > *{ max-width: 100%; }
/* ...but not the scene illustrations. They are absolutely positioned with a
   matching left/margin-left pair (e.g. left:50%; margin-left:-52%; width:104%)
   so they bleed a little past both edges of the cover, which clips them. The
   guard above shrank the width while leaving the offset alone, which pushed
   every one of those scenes off-centre to the left. */
.cover > .deco-float{ max-width: none; }
/* ==========================================================================
   OPENING SEQUENCE — clicking "Buka Undangan" plays a short choreography
   instead of a single slide: the button presses in, the cover's lines lift
   away one after another, a themed wash sweeps the screen, the panel itself
   rises and blurs out, and the hero cascades in behind it. Templates theme
   the wash with --open-wash and can override any step.
   ========================================================================== */
.cover{
  --open-wash: radial-gradient(circle at 50% 55%, var(--color-secondary), transparent 62%);
  --cover-exit: translateY(-102%) scale(1.06);
}
.cover.is-closing{
  transform: var(--cover-exit);
  opacity: 0;
  filter: blur(7px);
  pointer-events:none;
  transition: transform 1.05s cubic-bezier(.7,0,.2,1), opacity .95s ease, filter .95s ease;
}

/* Step 1 — the cover's own lines leave in sequence, top line first. */
.cover__eyebrow, .cover__names, .cover__date, .cover__guest-box, .btn-open,
.cover__crest, .cover__seal, .cover__medallion{
  transition: opacity .45s ease, transform .6s cubic-bezier(.4,0,.2,1), translate .6s cubic-bezier(.4,0,.2,1);
}
.cover.is-opening .btn-open{ opacity: 0; transform: scale(.82); transition-duration: .3s; }
.cover.is-opening .cover__guest-box{ opacity: 0; transform: translateY(16px); transition-delay: 60ms; }
.cover.is-opening .cover__date{ opacity: 0; transform: translateY(14px); transition-delay: 120ms; }
.cover.is-opening .cover__names{ opacity: 0; transform: translateY(-20px) scale(1.07); transition-delay: 180ms; }
.cover.is-opening .cover__eyebrow{ opacity: 0; transform: translateY(-14px); transition-delay: 240ms; }
.cover.is-opening .cover__crest,
.cover.is-opening .cover__seal,
.cover.is-opening .cover__medallion{ opacity: 0; transform: scale(.7) rotate(-8deg); transition-delay: 200ms; }
/* the sprites scatter outward as the panel goes */
.cover.is-opening .deco-float{ opacity: 0; translate: 0 -26px; transition-duration: .7s; }
.cover.is-opening .cover__deco-top{ opacity: 0; transform: translateY(-40px); transition: all .7s ease; }
.cover.is-opening .cover__deco-bottom{ opacity: 0; transform: translateY(40px); transition: all .7s ease; }

/* Step 2 — a single themed wash sweeping over the hand-off. */
.open-wash{
  position: fixed;
  inset: 0;
  max-width: var(--max-w);
  margin: 0 auto;
  z-index: 480;
  pointer-events: none;
  background: var(--open-wash);
  opacity: 0;
  animation: openWash 1.25s cubic-bezier(.3,0,.2,1) forwards;
}
@keyframes openWash{
  0%{ opacity: 0; transform: scale(.4); }
  35%{ opacity: .85; }
  100%{ opacity: 0; transform: scale(2.4); }
}

/* Step 3 — the invitation itself cascades in behind the leaving cover. */
.main-content.is-opening .hero__quote{ animation: openRise .9s .05s both cubic-bezier(.22,1,.36,1); }
.main-content.is-opening .hero__quote-src{ animation: openRise .9s .14s both cubic-bezier(.22,1,.36,1); }
.main-content.is-opening .hero__names{ animation: openRise 1s .22s both cubic-bezier(.22,1,.36,1); }
.main-content.is-opening .hero__amp{ animation: openRise .9s .3s both cubic-bezier(.22,1,.36,1); }
.main-content.is-opening .countdown{ animation: openRise .95s .38s both cubic-bezier(.22,1,.36,1); }
@keyframes openRise{
  from{ opacity: 0; transform: translateY(34px) scale(.96); }
  to{ opacity: 1; transform: none; }
}
.cover__eyebrow{
  font-size: clamp(9px, 2.6vw, 13px);
  letter-spacing: .35em;
  text-transform: uppercase;
  color: var(--color-text-soft);
  margin-bottom: clamp(8px, 2.2vh, 18px);
}
.cover__names{
  font-family: var(--font-script);
  font-size: clamp(34px, min(13.5vw, 10.5vh), 72px);
  line-height: 1.15;
  color: var(--color-accent);
  margin: clamp(2px, .6vh, 6px) 0 clamp(8px, 2.2vh, 18px);
  overflow-wrap: break-word;
}
.cover__date{
  font-family: var(--font-heading);
  font-size: clamp(13px, 3.2vw, 18px);
  letter-spacing: .12em;
  margin-bottom: clamp(14px, 3.4vh, 30px);
  color: var(--color-text);
}
.cover__guest-box{
  margin: clamp(4px, 1.2vh, 10px) 0 clamp(16px, 4vh, 34px);
  font-size: clamp(12px, 2.9vw, 15px);
  color: var(--color-text-soft);
}
.cover__guest-box .guest-name{
  display:block;
  margin-top: clamp(3px, .8vh, 6px);
  font-family: var(--font-heading);
  font-size: clamp(17px, 4.6vw, 22px);
  color: var(--color-text);
}
.btn-open{
  display:inline-flex;
  align-items:center;
  gap: clamp(6px, 1.8vw, 10px);
  padding: clamp(10px, 1.7vh, 14px) clamp(20px, 6vw, 34px);
  border-radius: 999px;
  border: 1px solid var(--color-accent);
  background: transparent;
  color: var(--color-accent);
  font-family: var(--font-heading);
  font-size: clamp(12px, 3vw, 15px);
  letter-spacing: .08em;
  white-space: nowrap;
  transition: all .35s ease;
  animation: pulse-btn 2.4s ease-in-out infinite;
}
.btn-open:hover{ background: var(--color-accent); color:#fff; }
@keyframes pulse-btn{
  0%,100%{ box-shadow: 0 0 0 0 rgba(138,90,68,.35); }
  50%{ box-shadow: 0 0 0 12px rgba(138,90,68,0); }
}
.cover__deco-top, .cover__deco-bottom{ position:absolute; left:0; right:0; pointer-events:none; max-height: 18vh; }
.cover__deco-top{ top:0; } .cover__deco-bottom{ bottom:0; }

/* ==========================================================================
   SPRITE ENTRANCE — the first time a sprite appears (cover on load, section
   sprites when scrolled into view) it drifts in from the side it sits on.
   Uses the standalone `translate` property so it composes with, rather than
   fights, each template's continuous sway `animation`. motion.js adds the
   direction class and .is-entered; the .js-motion guard keeps everything
   visible if that script never runs.
   ========================================================================== */
.js-motion .deco-float{
  opacity: 0;
  translate: 0 0;
  transition: opacity 1.9s cubic-bezier(.22,1,.36,1), translate 1.9s cubic-bezier(.22,1,.36,1);
}
.js-motion .deco-float.enter-left{ translate: -60px 10px; }
.js-motion .deco-float.enter-right{ translate: 60px 10px; }
.js-motion .deco-float.enter-top{ translate: 0 -50px; }
.js-motion .deco-float.enter-bottom{ translate: 0 50px; }
.js-motion .deco-float.is-entered{ opacity: 1; translate: 0 0; }
.js-motion .deco-float.is-far.is-entered{ opacity: .6; }
.js-motion .deco-float.is-back.is-entered{ opacity: .16; }

.js-motion .cover__names{
  opacity: 0;
  translate: 0 -46px;
  transition: opacity 2.1s cubic-bezier(.22,1,.36,1), translate 2.1s cubic-bezier(.22,1,.36,1);
}
.js-motion .cover__names.is-entered{ opacity: 1; translate: 0 0; }
.js-motion .cover.is-opening .cover__names{ opacity: 0; }

/* ---------- Orbiting accent ring around each portrait ---------- */
.couple__photo-wrap{
  position: relative;
  width: clamp(120px, 40vw, 160px);
  height: clamp(120px, 40vw, 160px);
  margin: 0 auto 18px;
}
.couple__photo-wrap .couple__photo{ margin: 0; }
.couple__photo-orbit{
  position: absolute;
  inset: -18px;
  animation: orbitSpin 17s linear infinite;
  pointer-events: none;
}
.couple__photo-orbit span{
  position: absolute;
  top: 50%; left: 50%;
  width: 8px; height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: var(--color-primary);
  box-shadow: 0 0 6px currentColor;
}
.couple__photo-orbit span:nth-child(1){ transform: rotate(0deg) translateY(-98px); }
.couple__photo-orbit span:nth-child(2){ transform: rotate(60deg) translateY(-98px); background: var(--color-secondary); width:6px; height:6px; margin:-3px 0 0 -3px; }
.couple__photo-orbit span:nth-child(3){ transform: rotate(120deg) translateY(-98px); background: var(--color-accent); width:5px; height:5px; margin:-2.5px 0 0 -2.5px; }
.couple__photo-orbit span:nth-child(4){ transform: rotate(180deg) translateY(-98px); }
.couple__photo-orbit span:nth-child(5){ transform: rotate(240deg) translateY(-98px); background: var(--color-secondary); width:6px; height:6px; margin:-3px 0 0 -3px; }
.couple__photo-orbit span:nth-child(6){ transform: rotate(300deg) translateY(-98px); background: var(--color-accent); width:5px; height:5px; margin:-2.5px 0 0 -2.5px; }
@keyframes orbitSpin{ from{ transform: rotate(0deg); } to{ transform: rotate(360deg); } }

/* ---------- Sprite depth layers ----------
   is-far sits slightly back (soft + dimmed), is-back is a large blurred motif
   behind the type entirely, so a busy cover still reads as layered rather
   than cluttered. Templates can retune blur/opacity for their own art. */
.deco-float.is-far{ opacity: .6; filter: blur(1.4px); }
.deco-float.is-back{ z-index: -1; opacity: .16; filter: blur(6px); }

/* Cards and portraits carry a cursor-tracked tilt (set inline by motion.js). */
.event-card, .gift-card, .wish-card, .couple__photo{
  transform-style: preserve-3d;
  will-change: transform;
}

/* ---------- Main content shell ---------- */
.main-content{ display:none; }
.main-content.is-visible{ display:block; }

.section{
  padding: clamp(56px, 11vh, 90px) var(--section-pad);
  text-align:center;
  position: relative;
}
.section__eyebrow{
  font-size: 12px;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin-bottom: 10px;
}
.section__title{
  font-family: var(--font-heading);
  font-size: clamp(24px, 7vw, 34px);
  color: var(--color-accent);
  margin: 0 0 26px;
}
.reveal{ opacity:0; transform: translateY(26px); transition: opacity .8s ease, transform .8s ease; }
.reveal.in{ opacity:1; transform: translateY(0); }

/* ---------- Hero ---------- */
.hero{ padding-top: 70px; }
.hero__quote{
  font-family: var(--font-body);
  font-style: italic;
  font-size: clamp(15px, 4vw, 18px);
  line-height: 1.8;
  color: var(--color-text-soft);
  max-width: 420px;
  margin: 0 auto 14px;
}
.hero__quote-src{ font-size: 13px; letter-spacing:.1em; color: var(--color-primary); }
.hero__names{
  font-family: var(--font-script);
  font-size: clamp(34px, 11vw, 52px);
  color: var(--color-accent);
  margin: 34px 0 4px;
}
.hero__amp{ font-size: 20px; color: var(--color-primary); margin: 6px 0; }

/* ---------- Countdown ---------- */
.countdown{
  display:flex;
  justify-content:center;
  gap: clamp(8px, 2.6vw, 14px);
  margin: 30px 0 10px;
  flex-wrap: wrap;
}
.countdown__item{
  width: clamp(58px, 17vw, 76px);
  padding: clamp(10px, 2.6vw, 14px) 0;
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: 14px;
}
.countdown__num{
  font-family: var(--font-heading);
  font-size: clamp(20px, 6vw, 26px);
  color: var(--color-accent);
  display:block;
}
.countdown__label{
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--color-text-soft);
}

/* ---------- Couple profiles ---------- */
.couple{ display:flex; flex-direction:column; gap:46px; margin-top: 10px; }
.couple__person{ text-align:center; }
.couple__photo{
  width: clamp(120px, 40vw, 160px); height: clamp(120px, 40vw, 160px);
  border-radius: 50%;
  object-fit: cover;
  margin: 0 auto 18px;
  border: 4px solid var(--color-surface);
  box-shadow: 0 10px 30px rgba(0,0,0,.15);
}
.couple__name{
  font-family: var(--font-heading);
  font-size: 24px;
  color: var(--color-accent);
  margin-bottom: 6px;
}
.couple__parents{ font-size: 14px; color: var(--color-text-soft); line-height:1.6; max-width: 320px; margin: 0 auto 8px; }
.couple__ig{ font-size: 13px; color: var(--color-primary); }
.couple__divider{ font-family: var(--font-script); font-size: 30px; color: var(--color-primary); }

/* ---------- Events ---------- */
.events{ display:flex; flex-direction:column; gap: 22px; }
.event-card{
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius);
  padding: clamp(20px, 6vw, 30px) clamp(16px, 5vw, 24px);
  text-align:center;
}
.event-card__name{ font-family: var(--font-heading); font-size: 22px; color: var(--color-accent); margin-bottom: 10px; }
.event-card__time{ font-size: 15px; margin-bottom: 4px; }
.event-card__place{ font-size: 15px; font-weight:600; margin-top: 6px; }
.event-card__addr{ font-size: 13px; color: var(--color-text-soft); margin: 4px 0 16px; line-height:1.6; }
.event-card__map{ width:100%; height: 200px; border:0; border-radius: 12px; filter: saturate(.25) contrast(1.05); }
.btn-outline{
  display:inline-block;
  margin-top: 14px;
  padding: 10px 22px;
  border-radius: 999px;
  border: 1px solid var(--color-accent);
  /* .btn-outline is used on <button> as well as <a>, and a button with no
     background of its own falls back to the browser's own light button face
     — a white pill under the theme's own accent-coloured label. */
  background: transparent;
  color: var(--color-accent);
  font-size: 13px;
  letter-spacing: .05em;
  transition: all .3s;
}
.btn-outline:hover{ background: var(--color-accent); color:#fff; }

/* ---------- Story ---------- */
.story{ text-align:left; position:relative; margin-top: 10px; }
.story::before{
  content:'';
  position:absolute; left: 19px; top: 6px; bottom: 6px; width:1px;
  background: var(--color-line);
}
.story__item{ position:relative; padding-left: 50px; margin-bottom: 34px; }
.story__item:last-child{ margin-bottom:0; }
.story__dot{
  position:absolute; left: 10px; top: 3px;
  width: 20px; height:20px; border-radius:50%;
  background: var(--color-bg);
  border: 2px solid var(--color-primary);
}
.story__date{ font-size: 12px; letter-spacing:.1em; text-transform:uppercase; color: var(--color-primary); margin-bottom: 4px; }
.story__title{ font-family: var(--font-heading); font-size: 19px; color: var(--color-accent); margin-bottom: 6px; }
.story__text{ font-size: 15px; color: var(--color-text-soft); line-height: 1.7; }

/* ---------- Rundown (susunan acara) ----------
   A clock-face timeline: the hour sits in its own left column, the activity in
   a card, both hung off one vertical spine. --spine, --time-w and --gap are the
   only numbers involved; the dot offset is derived from them, so narrowing the
   layout is a matter of changing the three variables and nothing else. */
.rundown{
  --spine: 60px;
  --time-w: 50px;
  --gap: 24px;
  text-align:left; position:relative; margin-top: 10px;
}
.rundown::before{
  content:'';
  position:absolute; left: var(--spine); top: 8px; bottom: 8px; width:1px;
  background: var(--color-line);
}
.rundown__item{ display:flex; gap: var(--gap); align-items:flex-start; margin-bottom: 18px; }
.rundown__item:last-child{ margin-bottom:0; }
.rundown__item.reveal{ transition-delay: calc(var(--i, 0) * 90ms); }
.rundown__time{
  flex: 0 0 var(--time-w);
  padding-top: 14px;
  text-align:right;
  font-family: var(--font-heading);
  font-size: 15px;
  color: var(--color-primary);
}
.rundown__body{
  position:relative;
  flex: 1 1 auto;
  min-width: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius);
  padding: 13px 16px;
}
/* Pulls the 12px dot back from the card's left edge far enough for its centre
   to land exactly on the spine. */
.rundown__body::before{
  content:'';
  position:absolute;
  left: calc(var(--spine) - var(--time-w) - var(--gap) - 6px);
  top: 16px;
  width: 12px; height: 12px; border-radius:50%;
  background: var(--color-bg);
  border: 2px solid var(--color-primary);
}
.rundown__title{ font-family: var(--font-heading); font-size: 17px; color: var(--color-accent); }
.rundown__desc{ font-size: 13px; color: var(--color-text-soft); line-height: 1.7; margin-top: 4px; }

@media (max-width: 360px){
  .rundown{ --spine: 48px; --time-w: 40px; --gap: 18px; }
  .rundown__time{ font-size: 14px; }
  .rundown__body{ padding: 12px 13px; }
}

/* ---------- Gallery ----------
   Every photo is on screen at once: a mosaic grid where each sixth tile opens
   up to 2x2, so the spread reads like a printed photo page instead of a flat
   contact sheet. Tapping a tile still opens the lightbox, which is where
   prev/next lives. Row heights fall out of the square tiles, so a 2x2 feature
   lines up with the two rows beside it without any fixed track sizing. */
.gallery{
  display:grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-flow: row dense;
  gap: 10px;
}
.gallery__item{
  aspect-ratio: 1/1;
  overflow:hidden;
  border-radius: 10px;
  cursor: pointer;
  position:relative;
}
/* Phone rhythm: every fifth photo runs the full width as a feature strip, so
   the column reads hero / pair / pair rather than as one long ladder. */
.gallery__item:nth-child(5n+1){ grid-column: span 2; aspect-ratio: 4/3; }
/* A photo left alone on the last row stretches across it, so the grid never
   ends on a ragged half-empty line. */
.gallery__item:last-child:nth-child(odd){ grid-column: span 2; aspect-ratio: 16/9; }
.gallery__item img{ width:100%; height:100%; object-fit:cover; transition: transform .5s ease; }
.gallery__item:hover img{ transform: scale(1.08); }

/* ---------- Video ---------- */
.video-box{
  position:relative;
  border-radius: var(--radius);
  overflow:hidden;
  aspect-ratio: 16/9;
  background:#000;
  cursor:pointer;
}
.video-box img{ width:100%; height:100%; object-fit:cover; opacity:.75; }
.video-box video{ width:100%; height:100%; object-fit:cover; display:none; background:#000; }
.video-box.is-playing img{ display:none; }
.video-box.is-playing video{ display:block; }
.video-box__play{
  position:absolute; inset:0; margin:auto;
  width: 68px; height: 68px; border-radius:50%;
  background: rgba(255,255,255,.9);
  display:flex; align-items:center; justify-content:center;
  color: var(--color-accent);
  font-size: 22px;
}
.video-box.is-playing .video-box__play{ display:none; }

/* ---------- Gift ---------- */
.gift{ display:flex; flex-direction:column; gap:14px; }
.gift-card{
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: 14px;
  padding: 18px 20px;
  display:flex;
  align-items:center;
  justify-content:space-between;
  text-align:left;
}
.gift-card__bank{ font-size: 12px; letter-spacing:.1em; text-transform:uppercase; color: var(--color-primary); }
.gift-card__num{ font-family: var(--font-heading); font-size: 19px; color: var(--color-accent); margin: 3px 0; }
.gift-card__name{ font-size: 13px; color: var(--color-text-soft); }
.btn-copy{
  border: 1px solid var(--color-accent);
  background: transparent;
  color: var(--color-accent);
  border-radius: 999px;
  padding: 8px 16px;
  font-size: 12px;
  white-space: nowrap;
}
.btn-copy.copied{ background: var(--color-accent); color:#fff; }
.gift__addr{ margin-top: 10px; font-size: 14px; color: var(--color-text-soft); line-height:1.7; }

/* ---------- RSVP / Wishes ---------- */
.rsvp-form{ display:flex; flex-direction:column; gap:12px; text-align:left; }
.rsvp-form input, .rsvp-form select, .rsvp-form textarea{
  width:100%;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--color-line);
  background: var(--color-surface);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 15px;
}
.rsvp-form textarea{ resize: vertical; min-height: 80px; }
.btn-solid{
  padding: 13px 20px;
  border-radius: 999px;
  border: none;
  background: var(--color-accent);
  color:#fff;
  font-family: var(--font-heading);
  letter-spacing: .05em;
  font-size: 15px;
}
.btn-solid:hover{ opacity:.9; }
.wishes-list{ margin-top: 30px; display:flex; flex-direction:column; gap:14px; text-align:left; max-height: 320px; overflow-y:auto; padding-right:4px; }
.wish-card{ background: var(--color-surface); border:1px solid var(--color-line); border-radius: 12px; padding: 14px 16px; }
.wish-card__head{ display:flex; justify-content:space-between; align-items:baseline; margin-bottom:4px; }
.wish-card__name{ font-weight:600; font-size:14px; color: var(--color-accent); }
.wish-card__status{ font-size: 11px; color: var(--color-primary); text-transform:uppercase; letter-spacing:.05em; }
.wish-card__msg{ font-size: 14px; color: var(--color-text-soft); line-height:1.6; }

/* ---------- Footer ---------- */
.footer{ padding: clamp(50px, 9vh, 70px) var(--section-pad) 40px; text-align:center; }
.footer__names{ font-family: var(--font-script); font-size: clamp(30px, 9vw, 40px); color: var(--color-accent); margin-bottom: 10px; }
.footer__thanks{ font-size: 14px; color: var(--color-text-soft); max-width: 340px; margin: 0 auto 18px; line-height:1.8; }
.footer__hashtag{ font-size: 13px; letter-spacing:.06em; color: var(--color-primary); }
.footer__credit{ margin-top: 40px; font-size: 11px; color: var(--color-text-soft); opacity:.6; }

/* ---------- Nav dots ---------- */
.navdots{
  position: fixed;
  right: max(14px, calc(50% - var(--max-w)/2 + 14px));
  top: 50%;
  transform: translateY(-50%);
  z-index: 400;
  display:flex;
  flex-direction:column;
  gap: 10px;
}
.navdots a{
  width: 9px; height: 9px; border-radius:50%;
  background: var(--color-line);
  display:block;
  transition: background .3s, transform .3s;
}
.navdots a.active{ background: var(--color-accent); transform: scale(1.35); }

/* ---------- Music toggle ---------- */
.music-toggle{
  position: fixed;
  left: max(14px, calc(50% - var(--max-w)/2 + 14px));
  bottom: 18px;
  z-index: 400;
  width: 42px; height: 42px;
  border-radius: 50%;
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  display:flex; align-items:center; justify-content:center;
  color: var(--color-accent);
  box-shadow: 0 6px 18px rgba(0,0,0,.18);
}
.music-toggle .icon-note{ animation: spin 4s linear infinite; }
.music-toggle.is-paused .icon-note{ animation-play-state: paused; }
@keyframes spin{ from{ transform: rotate(0);} to{ transform: rotate(360deg);} }

/* ---------- Lightbox (built by JS) ---------- */
.lightbox{
  position: fixed; inset:0; z-index: 900;
  background: rgba(10,8,6,.92);
  display:none;
  align-items:center; justify-content:center;
  flex-direction:column;
  padding: 30px;
}
.lightbox.is-open{ display:flex; }
.lightbox img{ max-width: 100%; max-height: 70vh; border-radius: 8px; }
.lightbox__close, .lightbox__prev, .lightbox__next{
  position:absolute;
  color:#fff;
  background: rgba(255,255,255,.12);
  border: none;
  width: 40px; height:40px;
  border-radius:50%;
  font-size: 18px;
  display:flex; align-items:center; justify-content:center;
}
.lightbox__close{ top: 20px; right: 20px; }
.lightbox__prev{ left: 20px; top:50%; transform:translateY(-50%); }
.lightbox__next{ right:20px; top:50%; transform:translateY(-50%); }

/* ---------- Toast ---------- */
.toast{
  position: fixed;
  bottom: 70px;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: #2b2320;
  color:#fff;
  padding: 12px 22px;
  border-radius: 999px;
  font-size: 13px;
  z-index: 999;
  opacity:0;
  pointer-events:none;
  transition: all .35s ease;
}
.toast.is-visible{ opacity:1; transform: translateX(-50%) translateY(0); }

@media (min-width: 460px){
  /* Wider screens trade the phone feature strip for a 3-column mosaic whose
     every sixth tile opens up to 2x2. */
  .gallery{ grid-template-columns: repeat(3, 1fr); gap: 12px; }
  .gallery__item:nth-child(5n+1),
  .gallery__item:last-child:nth-child(odd){ grid-column: auto; aspect-ratio: 1/1; }
  .gallery__item:nth-child(6n+1){ grid-column: span 2; grid-row: span 2; }
  /* A feature tile with nothing beside it becomes a panoramic closer instead. */
  .gallery__item:nth-child(6n+1):last-child{ grid-column: span 3; grid-row: auto; aspect-ratio: 21/9; }
}

/* ==========================================================================
   SCENE ASSETS — the storybook illustrations (the venue, the couple, birds,
   cherubs, garlands, rose vines) that make the cover and each section read
   like a printed illustrated invitation rather than a plain page. They ride
   on the same .deco-float entrance the small sprites use; only the layer and
   the continuous motion differ, so each template's own anim-a..h keyframes
   stay reserved for its little sprites.

   The big illustrations sit on the negative layer: above the panel's own
   background but below every line of copy, so a scene can sweep straight
   across the page without ever competing with the text on top of it.
   ========================================================================== */
.deco-float.is-scene{
  z-index: -1;
  filter: drop-shadow(0 8px 18px rgba(0,0,0,.10));
  animation: sceneBreathe 22s ease-in-out infinite;
}
.deco-float.is-scene.is-entered{ opacity: .9; }
.deco-float.is-scene.is-soft.is-entered{ opacity: .55; }   /* mid-ground */
.deco-float.is-scene.is-ghost.is-entered{ opacity: .1; }   /* far background */
.deco-float.is-scene.is-ghost{ filter: blur(3px); }
@keyframes sceneBreathe{
  0%, 100%{ transform: translateY(0) scale(1); }
  50%{ transform: translateY(-8px) scale(1.015); }
}

/* Birds cross their patch of sky on a long, lazy loop; the -b variant flies
   the other way (mirrored) so a pair never moves in lockstep. */
.deco-float.is-bird{ animation: birdGlide 15s ease-in-out infinite; }
.deco-float.is-bird.is-bird-b{ animation: birdGlideB 19s ease-in-out infinite; }
@keyframes birdGlide{
  0%, 100%{ transform: translate(0,0) rotate(-5deg); }
  30%{ transform: translate(18px,-14px) rotate(4deg); }
  60%{ transform: translate(32px,4px) rotate(-3deg); }
  85%{ transform: translate(13px,12px) rotate(5deg); }
}
@keyframes birdGlideB{
  0%, 100%{ transform: translate(0,0) rotate(4deg) scaleX(-1); }
  35%{ transform: translate(22px,-11px) rotate(-4deg) scaleX(-1); }
  70%{ transform: translate(9px,13px) rotate(6deg) scaleX(-1); }
}

.deco-float.is-cherub{ animation: cherubHover 11s ease-in-out infinite; }
@keyframes cherubHover{
  0%, 100%{ transform: translateY(0) rotate(-3deg); }
  50%{ transform: translateY(-15px) rotate(3deg); }
}

.deco-float.is-garland{ animation: garlandSway 13s ease-in-out infinite; }
@keyframes garlandSway{
  0%, 100%{ transform: rotate(-1.1deg); }
  50%{ transform: rotate(1.1deg); }
}

.deco-float.is-vine{ animation: vineSway 17s ease-in-out infinite; }
@keyframes vineSway{
  0%, 100%{ transform: translateX(0) rotate(-.7deg); }
  50%{ transform: translateX(7px) rotate(.7deg); }
}

/* Very short screens (landscape phones): tighten the cover further. */
@media (prefers-reduced-motion: reduce){
  .open-wash, .couple__photo-orbit{ animation: none !important; }
  .main-content.is-opening .hero__quote, .main-content.is-opening .hero__quote-src,
  .main-content.is-opening .hero__names, .main-content.is-opening .hero__amp,
  .main-content.is-opening .countdown{ animation-duration: .01ms !important; }
  .cover, .cover.is-closing, .js-motion .deco-float, .js-motion .cover__names{
    transition-duration: .01ms !important;
  }
  .deco-float.is-scene, .deco-float.is-bird, .deco-float.is-cherub,
  .deco-float.is-garland, .deco-float.is-vine{ animation: none !important; }
}

/* The cover has to fit its own copy first — the storybook layer is what goes
   when the viewport gets short, biggest illustrations first. */
@media (max-height: 700px){
  .cover .deco-float.is-scene.is-ghost{ display: none; }
}
@media (max-height: 620px){
  .cover .deco-float.is-scene, .cover .deco-float.is-cherub{ display: none; }
}

@media (max-height: 460px){
  .cover__eyebrow{ letter-spacing: .28em; }
  .cover__deco-top, .cover__deco-bottom{ display: none; }
  .cover .deco-float.is-garland, .cover .deco-float.is-bird{ display: none; }
}

/* ==========================================================================
   iPHONE MEMORY GUARD — Safari on iOS kills the tab ("A problem repeatedly
   occurred" / black screen) when a fast flick has it rasterising the whole
   long page at once and every decorative layer is still alive.

   1. Sections far from the viewport put their sprites to sleep (main.js
      toggles .is-asleep), so only the panels around the screen hold layers.
   2. On touch devices the sprites drop their filters and permanent
      will-change: each filtered/promoted sprite is its own GPU texture.
      Declared !important because each template's style.css loads after
      this file and sets both on .deco-float and .petal.
   ========================================================================== */
.is-asleep .deco-float,
.is-asleep .couple__photo-orbit{ display: none !important; }

@media (hover: none), (pointer: coarse){
  .deco-float, .petal{ will-change: auto !important; filter: none !important; }
  .event-card, .gift-card, .wish-card, .couple__photo{ will-change: auto; transform-style: flat; }
  .petal:nth-child(3n){ display: none; }
}
