/* ------------------------------------------------------------------
   Banana-leaf wedding invitation
   The whole scene is sized from --w, the width of the (square) card.
   ------------------------------------------------------------------ */
:root {
  --w: min(88vw, 58vh);
  --leaf-top: 4%;
  --leaf-h: 92%;
  --fw: 86;                         /* lobe width, % of the card */
  --lap: 3.5;                       /* how far a lobe overhangs its hinge, % of the card */
  --flap-w: calc(var(--fw) * 1%);

  --paper: #efe7d8;
  --paper-2: #e6dcc8;
  --ink: #8d1a1f;
  --ink-soft: #6b4a3a;

  --t-flap: 1.15s;
  --ease-fold: cubic-bezier(.45, .05, .2, 1);
}
@media (min-aspect-ratio: 5/4) {
  :root { --w: min(38vw, 66vh); --fw: 80; }
}
@media (min-aspect-ratio: 5/4) and (max-height: 520px) {
  :root { --w: min(38vw, 72vh); }
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  font-family: "Cormorant Garamond", "Iowan Old Style", Georgia, serif;
  color: var(--ink-soft);
  background-color: var(--paper);
  background-image:
    radial-gradient(120% 100% at 50% 40%, rgba(255, 252, 244, .9), rgba(255, 252, 244, 0) 60%),
    radial-gradient(90% 80% at 50% 60%, rgba(0, 0, 0, 0) 55%, rgba(80, 60, 30, .16) 100%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='220' height='220' filter='url(%23n)' opacity='.16'/></svg>");
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

.scene {
  position: fixed; inset: 0;
  display: grid;
  grid-template-rows: 1fr auto auto;
  justify-items: center;
  align-items: center;
  padding: 3vh 0 2vh;
  gap: 1.2vh;
}

/* ---------- stage: perspective + entrance ---------- */
.stage {
  position: relative;
  width: var(--w);
  height: calc(var(--w) * var(--ratio, 1));   /* --ratio = artwork height / width, set per route */
  perspective: calc(var(--w) * 3.2);
  perspective-origin: 50% 40%;
  opacity: 0;
  transform: translateY(4vh) scale(.94);
  animation: arrive 1.3s cubic-bezier(.2, .8, .2, 1) .15s forwards;
}
@keyframes arrive { to { opacity: 1; transform: none; } }

.shadow {
  position: absolute; left: 50%; top: 54%;
  width: 104%; height: 92%;
  transform: translate(-50%, -50%);
  border-radius: 50% / 40%;
  background: radial-gradient(ellipse at center, rgba(40, 30, 10, .42), rgba(40, 30, 10, .18) 55%, rgba(40, 30, 10, 0) 78%);
  filter: blur(calc(var(--w) * .035));
  transition: width var(--t-flap) var(--ease-fold) .35s, opacity .8s;
  pointer-events: none;
}
.open .shadow { width: 250%; opacity: .75; }

/* ---------- wrap: the 3D group ---------- */
.wrap {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(5deg);
  transition: transform 1s var(--ease-fold);
  cursor: pointer;
  outline: none;
}
.wrap:focus-visible { outline: 3px solid rgba(141, 26, 31, .5); outline-offset: 10px; }
.open .wrap { transform: rotateX(3deg); cursor: default; }

/* ---------- leaf ---------- */
.leaf {
  position: absolute;
  left: 0; right: 0;
  top: var(--leaf-top); height: var(--leaf-h);
  transform-style: preserve-3d;
}
.base {
  position: absolute; inset: 0;
  background: url("assets/base.jpg?v=2") center / cover no-repeat;
  transform: translateZ(0);
}
.flap {
  position: absolute;
  top: 0; height: 100%;
  width: calc((var(--fw) + var(--lap)) * 1%);         /* the lobe plus its overhang past the hinge */
  transform-style: preserve-3d;
  backface-visibility: visible;
  will-change: transform;
  transition: transform var(--t-flap) var(--ease-fold);
}
.flap img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  object-fit: fill;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .28));
  transition: filter var(--t-flap) ease;
  pointer-events: none;
}
/* open: the lobes lie flat on the base as one leaf, so no shadow along the hinge */
.open .flap img { filter: drop-shadow(0 0 0 rgba(0, 0, 0, 0)); }
/* left lobe: lies outside on the left when open, hinged on the card's left edge */
.flap-l {
  left: calc(-1 * var(--flap-w));
  transform-origin: calc(100% * var(--fw) / (var(--fw) + var(--lap))) 50%;   /* hinge exactly on the card's left edge */
  transform: translateZ(20px) rotateY(180deg);
  transition-delay: .55s;               /* closing: it lands last, on top */
}
/* right lobe: lies outside on the right when open, hinged on the card's right edge */
.flap-r {
  left: calc(100% - var(--lap) * 1%);
  transform-origin: calc(100% * var(--lap) / (var(--fw) + var(--lap))) 50%;  /* hinge exactly on the card's right edge */
  transform: translateZ(14px) rotateY(-180deg);
  transition-delay: 0s;
}
/* open: the lobes settle just above the base and BEHIND the card (card sits at 6px), so their
   overhang laps the base without covering the card's edges */
.open .flap-l { transform: translateZ(2px) rotateY(0deg);  transition-delay: 0s; }
.open .flap-r { transform: translateZ(3px) rotateY(0deg);  transition-delay: .6s; }

/* slight shading so the folded lobes read as the underside catching less light */
.flap::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(0, 0, 0, .18), rgba(0, 0, 0, 0) 45%);
  opacity: 1;
  transition: opacity var(--t-flap) ease;
  pointer-events: none;
  -webkit-mask: url("assets/lobe.webp") center / 100% 100% no-repeat;
          mask: url("assets/lobe.webp") center / 100% 100% no-repeat;
}
.flap-r::after {
  background: linear-gradient(270deg, rgba(0, 0, 0, .18), rgba(0, 0, 0, 0) 45%);
  -webkit-mask-image: url("assets/lobe_r.webp");
          mask-image: url("assets/lobe_r.webp");
}
.open .flap::after { opacity: 0; }

/* ---------- card ---------- */
.card {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: translateZ(6px);
  border-radius: 6px;
  cursor: default;
}
.open .card { cursor: pointer; }
.face {
  position: absolute; inset: 0;
  border-radius: 6px;
  overflow: hidden;
  background: #fbf6ec;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25), 0 10px 30px -12px rgba(0, 0, 0, .35);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.face img { display: block; width: 100%; height: 100%; object-fit: cover; }
.face.front { transform: translateZ(1px); }
.face.back  { transform: rotateY(180deg) translateZ(1px); }

/* the hanging garlands: a masked copy of the page, hinged at the top, swaying gently */
.face .sway {
  position: absolute; inset: 0;
  background: center / 100% 100% no-repeat;
  -webkit-mask: center / 100% 100% no-repeat;      /* image set per page by main.js */
          mask: center / 100% 100% no-repeat;
  transform-origin: 50% 0;
  animation: dangle 4.4s ease-in-out infinite;
  animation-play-state: paused;
  will-change: transform;
  pointer-events: none;
}
.open .face .sway { animation-play-state: running; }
.face.back .sway { animation-delay: -1.1s; }
@keyframes dangle {
  0%, 100% { transform: skewX(-1.3deg); }
  50%      { transform: skewX(1.3deg); }
}

/* ---------- thread ---------- */
.tie {
  position: absolute;
  top: 0; height: 100%;
  left: -30%; width: 160%;
  overflow: visible;
  transform: translateZ(32px);
  pointer-events: none;
  transition: opacity .45s ease, transform 0s linear 0s;
}
/* untied: the cord has slipped behind the leaf. It fades as it slides, then drops behind the base */
.cord-hidden .tie { opacity: 0; transform: translateZ(-2px); transition: opacity .45s ease, transform 0s linear .45s; }
.tie .hit { fill: transparent; pointer-events: all; cursor: pointer; }
.open .tie .hit, .untied .tie .hit { pointer-events: none; }

.rope path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
/* stroke widths are in viewBox units (1000 = card width) so the cord scales with the card */
.rope .rim   { stroke: #5e120c; stroke-width: 13; opacity: .85; }
.rope .red   { stroke: #c22a1c; stroke-width: 9.5; }
.rope .twist { stroke: #f3c23a; stroke-width: 3.6; stroke-dasharray: 6 11; opacity: .95; }
.rope .twist2 { stroke: #8e1c12; stroke-width: 3.2; stroke-dasharray: 5 12; stroke-dashoffset: 8; opacity: .8; }
.fray path { stroke: #c22a1c; stroke-width: 2.6; opacity: .9; }
.fray path:nth-child(1) { stroke: #f3c23a; }


/* ---------- hint + controls ---------- */
.hint {
  font-size: clamp(16px, 2.2vh, 22px);
  font-style: italic;
  letter-spacing: .02em;
  color: var(--ink);
  opacity: 0;
  animation: fadein .8s ease 1.4s forwards;
  transition: opacity .4s ease;
  min-height: 1.4em;
  text-align: center;
  padding: 0 16px;
}
@keyframes fadein { to { opacity: .85; } }
.hint.is-hidden { opacity: 0 !important; }

.controls {
  display: grid;
  grid-template-columns: 1fr 1fr;          /* Previous | Next: fixed slots, so labels changing never move anything */
  grid-template-areas: "prev next" "dots dots" "wrap wrap" "note note";
  gap: 10px 12px;
  width: min(92vw, 420px);
  justify-items: stretch;
  opacity: 0; transform: translateY(6px);
  transition: opacity .6s ease, transform .6s ease;
}
.controls.is-visible { opacity: 1; transform: none; }
#prevBtn { grid-area: prev; }
#nextBtn { grid-area: next; }
#dots    { grid-area: dots; justify-self: center; }
#closeBtn { grid-area: wrap; justify-self: center; min-width: 60%; }
.note    { grid-area: note; }
/* an invisible Previous keeps its slot so Next never shifts */
.btn.is-ghosted { visibility: hidden; }
.controls[hidden] { display: none; }
.btn {
  font: inherit;
  white-space: nowrap;
  text-align: center;
  font-size: clamp(15px, 2vh, 19px);
  font-weight: 600;
  letter-spacing: .04em;
  color: #fff8ee;
  background: linear-gradient(180deg, #a5221f, #7f1414);
  border: 1px solid rgba(255, 220, 160, .45);
  border-radius: 999px;
  padding: .55em 1em;
  cursor: pointer;
  box-shadow: 0 6px 16px -8px rgba(90, 10, 10, .7), inset 0 1px 0 rgba(255, 255, 255, .25);
  transition: transform .15s ease, box-shadow .15s ease;
}
.btn:hover { transform: translateY(-1px); box-shadow: 0 10px 20px -10px rgba(90, 10, 10, .8), inset 0 1px 0 rgba(255, 255, 255, .25); }
.btn:active { transform: translateY(0); }
.btn.ghost {
  color: var(--ink);
  background: rgba(255, 255, 255, .35);
  border-color: rgba(141, 26, 31, .35);
  box-shadow: none;
}
.btn:focus-visible { outline: 3px solid rgba(141, 26, 31, .45); outline-offset: 3px; }

/* the zoom reminder: large and plain, for guests who are not used to phones */
.note {
  flex-basis: 100%;
  text-align: center;
  font-size: clamp(19px, 2.6vh, 26px);
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--ink);
  margin-top: .2em;
}
.note span { font-size: .9em; margin-right: .15em; }

/* page dots for invitations with more than two pages */
.dots { display: flex; gap: 8px; align-items: center; padding: 0 6px; min-height: 8px; }
.dots[hidden] { display: none; }
.dots i { width: 8px; height: 8px; border-radius: 50%; background: rgba(141, 26, 31, .28); transition: background .3s, transform .3s; }
.dots i.on { background: var(--ink); transform: scale(1.25); }

/* ---------- petals (rain when the leaf unfolds) ---------- */
#petals { position: fixed; inset: 0; z-index: 5; pointer-events: none; overflow: hidden; perspective: 600px; }
/* outer: falls and sways; inner: the petal itself, tumbling in 3D */
.petal {
  position: absolute; top: -8vh;
  will-change: transform, opacity;
  animation: fall var(--dur, 8s) linear var(--delay, 0s) forwards;
  filter: blur(var(--blur, 0px));
  opacity: 0;
}
.petal > i {
  display: block;
  width: 100%; height: 100%;
  background: var(--img) center / 100% 100% no-repeat;
  transform-style: preserve-3d;
  animation: tumble var(--spin, 2s) ease-in-out var(--delay, 0s) infinite alternate;
  filter: drop-shadow(0 1px 1px rgba(60, 20, 0, .25));
}
@keyframes fall {
  0%   { opacity: 0; transform: translate3d(0, -10vh, 0) rotate(0deg); }
  6%   { opacity: var(--o, .95); }
  25%  { transform: translate3d(calc(var(--dx) * .25 + var(--sway)), 22vh, 0) rotate(calc(var(--rot) * .25)); }
  50%  { transform: translate3d(calc(var(--dx) * .5 - var(--sway)), 50vh, 0) rotate(calc(var(--rot) * .5)); }
  75%  { transform: translate3d(calc(var(--dx) * .75 + var(--sway) * .7), 80vh, 0) rotate(calc(var(--rot) * .75)); }
  92%  { opacity: var(--o, .95); }
  100% { opacity: 0; transform: translate3d(var(--dx), 112vh, 0) rotate(var(--rot)); }
}
@keyframes tumble {
  0%   { transform: rotateX(var(--tx0)) rotateY(var(--ty0)) rotateZ(0deg); }
  100% { transform: rotateX(var(--tx1)) rotateY(var(--ty1)) rotateZ(var(--tz1)); }
}

/* ---------- music toggle ---------- */
.sound {
  position: fixed; top: 14px; right: 14px; z-index: 6;
  width: 50px; height: 50px; border-radius: 50%;
  font-size: 24px; line-height: 1; cursor: pointer;
  color: var(--ink);
  background: rgba(255, 255, 255, .6);
  border: 1px solid rgba(141, 26, 31, .35);
  box-shadow: 0 4px 14px -6px rgba(60, 30, 10, .45);
  transition: transform .15s ease, opacity .4s ease;
}
.sound:hover { transform: scale(1.06); }
.sound:focus-visible { outline: 3px solid rgba(141, 26, 31, .45); outline-offset: 3px; }
.sound[hidden] { display: none; }
.sound.is-off { opacity: .75; }

/* ---------- motion preferences ---------- */
@media (prefers-reduced-motion: reduce) {
  .stage { animation-duration: .01s; animation-delay: 0s; }
  .flap, .shadow, .wrap { transition-duration: .01s !important; transition-delay: 0s !important; }
  .hint { animation-delay: 0s; animation-duration: .01s; }
  .petal { display: none; }
  .face .sway { animation: none; }
}
