/* ══ حَفل زِفاف حَكيم و رشَا ════════════════════════════════════════════
   Palette and metrics come straight from the Canva designs:
   #443927 ink · #996240 / #a88f4c / #dca05b gold · #f0ddc7 / #ffe5c7 cream
   Each page is three real layers (bg / art / text) extracted from Canva,
   so they can parallax and animate independently.
   Overlay widgets are positioned as exact % of the 941×1672 artboard.

   Two kinds of motion run at once:
     • scroll parallax — JS writes the `translate` property
     • ambient drift   — CSS keyframes own `transform`
   They are separate properties, so they compose instead of overwriting one
   another. `.no-indep-transform` (set by app.js on engines without the
   independent properties) keeps the parallax and drops the drift.
   ══════════════════════════════════════════════════════════════════════ */

:root {
  color-scheme: light;
  --ink:      #443927;
  --gold:     #996240;
  --gold-lt:  #c69769;
  --gold-pale:#dca05b;
  --cream:    #f0ddc7;
  --cream-lt: #ffe5c7;
  --sand:     #efcba2;
  --paper:    #f1e7d8;
  --ar: 'Amiri', 'Noto Naskh Arabic', 'Times New Roman', serif;
  --la: 'Cormorant Garamond', 'Amiri', Georgia, serif;
  --shell: min(100vw, 560px);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: #2f2719;
  color: var(--ink);
  font-family: var(--ar);
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}
body.locked { overflow: hidden; }

img { display: block; max-width: 100%; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.i { width: 1.05em; height: 1.05em; flex: none; vertical-align: -0.16em; }

/* ── progress ─────────────────────────────────────────────────────── */
.progress {
  position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 40;
  background: rgba(68, 57, 39, .14);
  opacity: 0; transition: opacity .5s ease;
}
body.opened .progress { opacity: 1; }
.progress span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--gold-pale), var(--gold));
  transition: width .15s linear;
}

/* ── cover / envelope ─────────────────────────────────────────────── */
.cover {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4vh;
  background: radial-gradient(120% 80% at 50% 30%, #6b5a3f 0%, #4a3d2a 45%, #372d1f 100%);
  transition: opacity .9s ease, transform .9s ease, visibility .9s;
}
.cover__glow {
  position: absolute; width: 78vw; height: 78vw; max-width: 460px; max-height: 460px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(220, 160, 91, .30), transparent 68%);
  filter: blur(6px);
  animation: breathe 6s ease-in-out infinite;
}
@keyframes breathe { 0%, 100% { transform: scale(1); opacity: .85 } 50% { transform: scale(1.09); opacity: 1 } }

.cover__greeting {
  position: relative; margin: 0; padding: 0 8vw;
  font-size: clamp(17px, 4.6vw, 24px); color: var(--cream-lt); text-align: center;
  animation: rise .9s .15s both;
}
.cover__hint {
  position: relative; margin: 0;
  font-size: clamp(14px, 3.8vw, 18px); color: rgba(255, 229, 199, .72);
  animation: rise .9s .35s both, pulse 2.6s 1.2s ease-in-out infinite;
}
.cover.is-opening .cover__hint { opacity: 0; transition: opacity .35s ease; animation: none; }
@keyframes rise { from { opacity: 0; transform: translateY(14px) } to { opacity: 1; transform: none } }
@keyframes pulse { 0%, 100% { opacity: .6 } 50% { opacity: 1 } }

.envelope {
  position: relative; border: 0; background: none; padding: 0; cursor: pointer;
  width: min(68vw, 300px); aspect-ratio: 3 / 2;
  animation: rise .9s both;
  -webkit-tap-highlight-color: transparent;
  perspective: 900px;               /* without this the flap folds flat */
}
.envelope__body { position: absolute; inset: 0; display: block; transform-style: preserve-3d; }
.envelope__pocket, .envelope__flap, .envelope__card { position: absolute; display: block; }

.envelope__pocket {
  inset: 0; border-radius: 6px; z-index: 2;
  background: linear-gradient(160deg, #f6e9d6, var(--cream) 55%, #e4cbad);
  box-shadow: 0 22px 44px rgba(0, 0, 0, .42), inset 0 0 0 1.5px var(--gold-lt);
}
.envelope__pocket::before, .envelope__pocket::after {
  content: ''; position: absolute; bottom: 0; width: 52%; height: 100%;
  background: linear-gradient(140deg, #eedcc2, #e0c6a5);
}
.envelope__pocket::before { left: 0;  clip-path: polygon(0 100%, 0 6%, 100% 100%); }
.envelope__pocket::after  { right: 0; clip-path: polygon(100% 100%, 100% 6%, 0 100%); }

.envelope__card {
  left: 7%; right: 7%; top: 6%; height: 84%; z-index: 1;
  background: linear-gradient(180deg, #fffaf1, #f7ecdb);
  border: 1px solid rgba(198, 151, 105, .55); border-radius: 3px;
  opacity: 0;
  transition: transform .85s cubic-bezier(.22, 1, .36, 1) .35s, opacity .4s .35s;
}
.envelope__flap {
  left: 0; right: 0; top: 0; height: 62%; z-index: 3;
  background: linear-gradient(175deg, #f8ecda, #e8d2b4);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  transform-origin: top center;
  transition: transform .8s cubic-bezier(.6, -0.25, .35, 1.25);
  filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .18));
}
.envelope__seal {
  position: absolute; left: 50%; top: 52%; width: 23%; aspect-ratio: 1; z-index: 4;
  transform: translate(-50%, -50%); border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--gold-pale), var(--gold) 60%, #6f4527);
  box-shadow: 0 3px 10px rgba(0, 0, 0, .35), inset 0 0 0 2px rgba(255, 229, 199, .35);
  display: grid; place-items: center;
  transition: transform .45s ease, opacity .45s ease;
}
.envelope__seal-initials {
  font-size: clamp(13px, 3.6vw, 17px); color: var(--cream-lt); line-height: 1;
}
.envelope__seal-initials i { font-style: normal; opacity: .65; margin: 0 .12em; font-size: .72em; }
.envelope:focus-visible { outline: 2px solid var(--gold-pale); outline-offset: 10px; border-radius: 8px; }

.cover.is-opening .envelope__seal { transform: translate(-50%, -50%) scale(.3) rotate(-25deg); opacity: 0; }
.cover.is-opening .envelope__flap { transform: rotateX(-165deg); }
.cover.is-opening .envelope__card { transform: translateY(-58%); opacity: 1; }
.cover.is-gone { opacity: 0; visibility: hidden; transform: scale(1.12); pointer-events: none; }

/* ── the deck ─────────────────────────────────────────────────────── */
.deck {
  width: var(--shell); margin-inline: auto;
  background: var(--paper);
  box-shadow: 0 0 60px rgba(0, 0, 0, .5);
  opacity: 0; transition: opacity .8s ease .1s;
}
body.opened .deck { opacity: 1; }

/* ── a page = three stacked layers ────────────────────────────────── */
.page {
  position: relative; display: block;
  container-type: inline-size;
  aspect-ratio: var(--w) / var(--h);
  overflow: hidden;
  background: var(--paper);
  isolation: isolate;
}

/* the 24px blurred preview from lqip.css: a page is never blank, even when
   the guest scrolls faster than the network can hand over the real layers */
.page::before {
  content: ''; position: absolute; inset: -5%; z-index: 0;
  background-image: var(--lqip); background-size: cover; background-position: center;
  filter: blur(16px) saturate(1.08);
}
/* Once the real layers cover it, the blur is invisible but still costs a
   full-page GPU filter on every page, forever. Take it out of the tree. */
.page.loaded::before { display: none; }

.lyr {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  backface-visibility: hidden;
}
/* Promote only the two layers that actually move, and only while the page is
   on screen. A composited layer costs width x height x dpr x 4 bytes, so on a
   3x phone each full-page layer is ~9 MB of GPU memory — promoting all three
   on several pages at once is enough for iOS to give up on accelerating any
   of it, which is how the animations end up frozen on a phone but fine on a
   laptop. The background never animates now, so it has no business here. */
.page.live .lyr--art,
.page.live .lyr--text { will-change: transform; }

/* No scale on any layer. Every Canva page is framed by a cream paper border,
   and scaling an image that exactly fills the page crops that frame away. */
.lyr--bg   { z-index: 1; }
.lyr--art  { z-index: 3; }
.lyr--text { z-index: 4; }

/* entrance: each layer arrives on its own beat, but only once its own bytes
   have landed — `.ready` is added by app.js on load */
/* Opacity only. This used to blur the art in from 6px, but transitioning a
   filter on a full-page image is the one thing here that iOS will quietly
   refuse to finish — and when it stalls the page sits behind a permanent
   blur until you reload. Not worth the flourish. */
.page .lyr--bg   { opacity: 0; transition: opacity 1.1s ease; }
.page .lyr--art  { opacity: 0; transition: opacity .9s ease .18s; }
.page .lyr--text { opacity: 0; transition: opacity .9s ease .42s; }
.page.in .lyr--bg.ready   { opacity: 1; }
.page.in .lyr--art.ready  { opacity: 1; }
.page.in .lyr--text.ready { opacity: 1; }

/* The couple portrait gets a touch more presence — but a drop-shadow on a
   941x1671 image is an expensive filter, and on a phone it is both invisible
   and the sort of thing that pushes iOS past its GPU budget. Desktop only. */
@media (min-width: 620px) {
  .page.in .lyr--art.lyr--hero.ready { filter: drop-shadow(0 12px 26px rgba(30, 22, 12, .34)); }
}

/* a gold halo blooms around the names once, when the page arrives.
   (brightness() would just wash the dark brown out — a shadow reads as gold.) */
.page.in .lyr--shimmer.ready { animation: shimmer 2.6s ease-out .55s 1 both; }
@keyframes shimmer {
  0%   { filter: drop-shadow(0 0 0    rgba(220, 160, 91, 0)) }
  40%  { filter: drop-shadow(0 0 12px rgba(220, 160, 91, .85)) }
  100% { filter: drop-shadow(0 0 0    rgba(220, 160, 91, 0)) }
}

/* ── ambient drift: the scene keeps breathing while you sit on a page ─ */
/* The background holds still so its paper border stays pixel-exact; the
   transparent layers above it carry the motion. */
.page.live .lyr--art  { animation: artSway 26s ease-in-out infinite; }
.page.live .lyr--text { animation: textFloat 17s ease-in-out infinite; }

/* stagger the pages so two never sway on the same beat */
.page[data-page="2"] .lyr--art { animation-delay: -4s }
.page[data-page="3"] .lyr--art { animation-delay: -9s }
.page[data-page="4"] .lyr--art { animation-delay: -14s }
.page[data-page="5"] .lyr--art { animation-delay: -19s }
.page[data-page="6"] .lyr--art { animation-delay: -23s }

/* translate only — a scale here would crop the border back off */
@keyframes artSway {
  0%, 100% { transform: translate3d( 0.30%,  0.00%, 0) rotate(-0.09deg) }
  50%      { transform: translate3d(-0.30%, -0.38%, 0) rotate( 0.09deg) }
}
@keyframes textFloat {
  0%, 100% { transform: translate3d(0,  0.00%, 0) }
  50%      { transform: translate3d(0, -0.42%, 0) }
}

/* JS owns `transform` on these engines, so the drift has to sit this one out */
.no-indep-transform .page.live .lyr { animation: none !important; }

/* ── the palm fronds on page 01 ───────────────────────────────────── */
/* Split out of p1-art by scripts/make-frond.py so they can move on their own.
   The origin sits where they attach at the top-right corner, so the tips
   travel and the join does not. */
.frond {
  position: absolute; z-index: 3;
  left: 69.926%; top: 0;
  width: 30.074%; height: 21.903%;
  object-fit: fill;
  transform-origin: 95% 3%;
  opacity: 0; transition: opacity .9s ease .18s;
  pointer-events: none;
}
.page.in .frond.ready { opacity: 1; }
.page.live .frond { animation: frondSway 7.5s ease-in-out infinite; will-change: transform; }

/* uneven on purpose — a frond in a breeze does not keep time */
@keyframes frondSway {
  0%   { transform: rotate(-0.85deg) }
  34%  { transform: rotate( 0.55deg) }
  58%  { transform: rotate(-0.25deg) }
  79%  { transform: rotate( 0.80deg) }
  100% { transform: rotate(-0.85deg) }
}

/* ── sun rays on page 01 ──────────────────────────────────────────── */
/* The fan is centred on the sun but lives inside a box that stops at the
   horizon, so the rays only ever reach up into the sky — clipping is far
   safer here than trying to intersect two masks, which Safari only learned
   recently. */
.rays {
  position: absolute; left: 0; right: 0; top: 0;
  height: var(--horizon);
  overflow: hidden; pointer-events: none; z-index: 2;
  mix-blend-mode: screen;
  opacity: 0;
}
.page.in .rays { opacity: 1; transition: opacity 2.4s ease 1s; }

.rays i {
  position: absolute; left: var(--x); top: 100%;
  width: 190%; aspect-ratio: 1;
  /* nothing right at the sun, nothing at the far end */
  -webkit-mask-image: radial-gradient(closest-side, transparent 9%, #000 32%, rgba(0,0,0,.55) 58%, transparent 76%);
          mask-image: radial-gradient(closest-side, transparent 9%, #000 32%, rgba(0,0,0,.55) 58%, transparent 76%);
  transform: translate(-50%, -50%);
  will-change: transform, opacity;
}

/* Three fans, all with a 24deg repeat but different ray shapes, offsets and
   speeds. Because they turn at different rates they slide across one another,
   so a ray brightens as two line up and thins out again as they part — rays
   appear and fade without any single one of them ever blinking. */
.rays i:nth-child(1) {
  background: repeating-conic-gradient(from 0deg at 50% 50%,
    rgba(255, 219, 165, 0)   0deg,
    rgba(255, 219, 165, .34) 1.8deg,
    rgba(255, 219, 165, 0)   5.2deg,
    rgba(255, 219, 165, 0)   24deg);
  animation: raySpin 34s linear infinite, rayFade 23s ease-in-out infinite;
}
.rays i:nth-child(2) {
  background: repeating-conic-gradient(from 9deg at 50% 50%,
    rgba(255, 231, 188, 0)   0deg,
    rgba(255, 231, 188, .22) 1deg,
    rgba(255, 231, 188, 0)   3.4deg,
    rgba(255, 231, 188, 0)   12deg,
    rgba(255, 231, 188, .16) 13.2deg,
    rgba(255, 231, 188, 0)   15.6deg,
    rgba(255, 231, 188, 0)   24deg);
  animation: raySpin 52s linear infinite, rayFade 17s ease-in-out infinite -7s;
}
.rays i:nth-child(3) {
  background: repeating-conic-gradient(from 15deg at 50% 50%,
    rgba(255, 208, 138, 0)   0deg,
    rgba(255, 208, 138, .30) 2.8deg,
    rgba(255, 208, 138, 0)   7.4deg,
    rgba(255, 208, 138, 0)   24deg);
  animation: raySpin 77s linear infinite, rayFade 31s ease-in-out infinite -13s;
}

/* Each fan repeats every 24deg, so turning by exactly that much lands the
   pattern back on itself. A full 360 would not divide evenly into 24 the way
   the eye expects and the loop point would show. */
@keyframes raySpin {
  from { transform: translate(-50%, -50%) rotate(0deg) }
  to   { transform: translate(-50%, -50%) rotate(24deg) }
}
@keyframes rayFade {
  0%, 100% { opacity: .28 }
  50%      { opacity: 1 }
}

/* ── the sea on page 01 ───────────────────────────────────────────── */
/* Two bands of light streaks crossing in opposite directions. Neither reads
   as anything on its own; together they read as water. */
.waves {
  position: absolute; left: 0; right: 0; z-index: 2;
  top: var(--top); height: var(--h);
  overflow: hidden; pointer-events: none; mix-blend-mode: screen;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 22%, #000 68%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 22%, #000 68%, transparent);
}
.waves__band {
  position: absolute; inset: 0 auto 0 0;
  width: 200%;
  background-repeat: repeat-x;
  background-size: 50% 100%;
  will-change: transform;
}
.waves__band--far  { background-image: url(layers/waves-far.webp);  opacity: .40; animation: waveDrift 46s linear infinite; }
.waves__band--near { background-image: url(layers/waves-near.webp); opacity: .30; animation: waveDrift 29s linear infinite reverse; }
@keyframes waveDrift { from { transform: translateX(0) } to { transform: translateX(-50%) } }

/* ── drifting clouds over the sky pages ───────────────────────────── */
.sky {
  position: absolute; left: 0; right: 0; z-index: 2;
  top: var(--top); height: var(--h);
  overflow: hidden; pointer-events: none;
  /* hold full strength across most of the band — fading it from 20% to 70%
     left so little of the cloud visible that it read as nothing at all */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 80%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 80%, transparent);
}
.sky__band {
  position: absolute; inset: 0 auto 0 0;
  width: 200%;
  /* the sprite tiles horizontally, and one tile is exactly the sky's width —
     so sliding by 50% of the band lands on the next tile and never seams */
  background-repeat: repeat-x;
  background-size: 50% 100%;
  will-change: transform;
}
/* Slow enough that you never catch them moving, strong enough that the sky
   is plainly different a minute later. */
.sky__band--far  { background-image: url(layers/clouds-far.webp);  opacity: .78; animation: cloudDrift 115s linear infinite; }
.sky__band--near { background-image: url(layers/clouds-near.webp); opacity: .58; animation: cloudDrift 74s linear infinite; }
@keyframes cloudDrift { from { transform: translateX(0) } to { transform: translateX(-50%) } }

/* `screen` over an already-bright sunset barely registers — the cloud has
   nothing left to lighten. Soft-light keeps them reading as cloud against
   the paint instead of washing out. The night sky is dark, so screen works
   there and stays subtle. */
.sky--dusk  { mix-blend-mode: soft-light; opacity: .95; }
.sky--night { mix-blend-mode: screen; opacity: .5; }
.sky--night .sky__band--far  { animation-duration: 150s; opacity: .42; }
.sky--night .sky__band--near { animation-duration: 98s;  opacity: .30; animation-direction: reverse; }

/* ── stars on the closing page ────────────────────────────────────── */
.stars {
  position: absolute; left: 0; right: 0; z-index: 2;
  top: var(--top); height: var(--h);
  pointer-events: none;
}
.star {
  position: absolute; border-radius: 50%;
  background: #fff8e8; box-shadow: 0 0 4px rgba(255, 244, 214, .9);
  opacity: 0;
  animation: twinkle var(--dur, 4s) ease-in-out var(--delay, 0s) infinite;
}
@keyframes twinkle {
  0%, 100% { opacity: .07; transform: scale(.65) }
  50%      { opacity: var(--peak, .7); transform: scale(1) }
}

/* ── a sweep of light across the water ────────────────────────────── */
.sheen {
  position: absolute; left: 0; right: 0; z-index: 2;
  top: var(--top); height: var(--h);
  overflow: hidden; pointer-events: none; mix-blend-mode: screen;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 45%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 45%, transparent);
}
.sheen::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 55%;
  background: linear-gradient(100deg, transparent, rgba(255, 228, 176, .28) 45%, transparent);
  animation: sheenSweep 11s ease-in-out infinite;
}
@keyframes sheenSweep {
  0%        { transform: translateX(-90%) }
  60%, 100% { transform: translateX(240%) }
}

/* ── lamps, sun, moon ─────────────────────────────────────────────── */
.glow {
  position: absolute; z-index: 2;
  left: var(--x); top: var(--y);
  width: var(--r); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 226, 170, .85), rgba(255, 196, 120, .35) 42%, transparent 70%);
  mix-blend-mode: screen;
  opacity: 0; pointer-events: none;
}
.page.in .glow { animation: lamp 5.5s ease-in-out infinite 1s; }
.glow--sun  { background: radial-gradient(circle, rgba(255, 214, 150, .9), rgba(255, 160, 80, .32) 45%, transparent 70%); }
.glow--moon { background: radial-gradient(circle, rgba(226, 232, 255, .8), rgba(180, 200, 255, .25) 45%, transparent 70%); }
@keyframes lamp {
  0%, 100% { opacity: .5;  transform: translate(-50%, -50%) scale(1) }
  50%      { opacity: .95; transform: translate(-50%, -50%) scale(1.12) }
}

/* ── lanterns: a flame, not a pulsing disc ────────────────────────── */
/* Two parts, because that is what a real flame throws: a small hot core that
   dances, and a wide warm wash on the wall around it. They flicker on
   different clocks and neither is regular, which is what keeps it from
   reading as a blinking light. */
.lamp {
  position: absolute; z-index: 2;
  left: var(--x); top: var(--y);
  width: var(--r); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  mix-blend-mode: screen;
  pointer-events: none;
  opacity: 0;
}
.page.in .lamp { opacity: 1; transition: opacity 1.8s ease .5s; }

.lamp::before,
.lamp::after { content: ''; position: absolute; left: 50%; top: 50%; border-radius: 50%; }

/* the light it throws into the room */
.lamp::before {
  width: 100%; height: 100%; margin: -50% 0 0 -50%;
  background: radial-gradient(circle,
      rgba(255, 198, 116, .72) 0%,
      rgba(255, 162, 70, .32) 34%,
      rgba(255, 140, 50, .11) 58%,
      transparent 75%);
  animation: lampHalo 6.1s ease-in-out infinite;
}

/* the flame */
.lamp::after {
  width: 30%; height: 30%; margin: -15% 0 0 -15%;
  background: radial-gradient(circle,
      rgba(255, 249, 229, .95) 0%,
      rgba(255, 216, 145, .68) 40%,
      rgba(255, 172, 84, .24) 70%,
      transparent 86%);
  animation: lampCore 2.3s ease-in-out infinite;
}

/* no two lanterns in a room ever flicker together */
.lamp:nth-of-type(2)::before { animation-duration: 7.4s; animation-delay: -2.9s }
.lamp:nth-of-type(2)::after  { animation-duration: 3.1s; animation-delay: -1.3s }
.lamp:nth-of-type(3)::before { animation-duration: 5.3s; animation-delay: -4.1s }
.lamp:nth-of-type(3)::after  { animation-duration: 2.7s; animation-delay: -0.7s }
.lamp:nth-of-type(4)::before { animation-duration: 8.2s; animation-delay: -1.6s }
.lamp:nth-of-type(4)::after  { animation-duration: 1.9s; animation-delay: -2.2s }

@keyframes lampHalo {
  0%   { opacity: .70; transform: scale(1.00) }
  17%  { opacity: .95; transform: scale(1.06) }
  29%  { opacity: .64; transform: scale(0.975) }
  46%  { opacity: 1;   transform: scale(1.09) }
  61%  { opacity: .77; transform: scale(1.02) }
  74%  { opacity: .92; transform: scale(1.05) }
  88%  { opacity: .68; transform: scale(0.99) }
  100% { opacity: .70; transform: scale(1.00) }
}
@keyframes lampCore {
  0%   { opacity: .84; transform: translate(0, 0) scale(1) }
  21%  { opacity: 1;   transform: translate(2%, -3%) scale(1.12) }
  38%  { opacity: .78; transform: translate(-1.5%, 1.5%) scale(.95) }
  55%  { opacity: .98; transform: translate(1.5%, -1.5%) scale(1.08) }
  72%  { opacity: .81; transform: translate(-2%, .5%) scale(.97) }
  100% { opacity: .84; transform: translate(0, 0) scale(1) }
}

/* generic reveal for the non-image sections */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity .9s ease, transform .9s cubic-bezier(.22, 1, .36, 1); }
.reveal.in { opacity: 1; transform: none; }

/* ── overlay: the map button on page 04 ───────────────────────────── */
.hot {
  position: absolute; z-index: 6;
  display: grid; place-items: center;
  text-decoration: none; color: var(--sand);
  font-family: var(--ar); line-height: 1;
  border-radius: 999px;
  background: var(--gold);
  transition: transform .18s ease, filter .18s ease;
  -webkit-tap-highlight-color: transparent;
}
.hot--map {
  left: 38.62%; width: 39.09%;
  top: 73.41%; height: 3.59%;
  font-size: 3.67cqw;
}
.hot::after {
  content: ''; position: absolute; inset: -6%;
  border-radius: inherit; border: 1px solid rgba(220, 160, 91, .55);
  opacity: 0; transform: scale(.94);
}
.page.in .hot::after { animation: halo 3.2s ease-out infinite 1.5s; }
@keyframes halo {
  0%   { opacity: .9; transform: scale(.94) }
  70%  { opacity: 0;  transform: scale(1.16) }
  100% { opacity: 0;  transform: scale(1.16) }
}
.hot:active { transform: scale(.97); filter: brightness(1.06); }

/* ── overlay: RSVP on page 05 ─────────────────────────────────────── */
.rsvp { position: absolute; inset: 0; z-index: 6; margin: 0; }
.rsvp[hidden], .rsvp2[hidden] { display: none; }

.rsvp__names,
.rsvp__opt,
.rsvp__submit {
  position: absolute;
  font-family: var(--ar); color: var(--ink);
  border: 0.32cqw solid var(--gold-lt);
  background: var(--cream);
  font-size: 4.68cqw; line-height: 1.4;
  text-align: center;
  -webkit-tap-highlight-color: transparent;
  -webkit-appearance: none; appearance: none;
}

.rsvp__names {
  left: 19.10%; width: 61.49%;
  top: 38.50%; height: 12.22%;
  border-radius: 3.4cqw;
  /* top pad centres the single-line placeholder inside the 12.22% tall box */
  padding: 6.6cqw 3cqw 2cqw;
  resize: none; overflow-y: auto;
  transition: box-shadow .2s ease, border-color .2s ease;
}
.rsvp__names::placeholder { color: var(--ink); opacity: .41; }
.rsvp__names:focus {
  outline: 0; border-color: var(--gold);
  box-shadow: 0 0 0 0.5cqw rgba(153, 98, 64, .16);
}

.rsvp__choice { display: contents; }

.rsvp__opt {
  top: 58.63%; height: 6.29%; width: 29.86%;
  border-radius: 2.2cqw;
  display: grid; place-items: center; cursor: pointer;
  /* Amiri sets «أعتذر عن الحضور» wider than the original Canva face, so it
     wrapped to two lines and overflowed the fixed artboard height. */
  white-space: nowrap;
  font-size: 4.02cqw;
  transition: background-color .22s ease, color .22s ease, transform .18s ease, box-shadow .22s ease;
}
#optNo  { left: 19.10%; }
#optYes { left: 50.72%; }
.rsvp__opt:active { transform: scale(.98); }
.rsvp__opt[aria-checked="true"] {
  background: var(--gold); color: var(--cream-lt); border-color: var(--gold);
  box-shadow: 0 0.6cqw 1.6cqw rgba(68, 57, 39, .22);
}

.rsvp__submit {
  left: 19.10%; width: 61.49%;
  top: 68.41%; height: 6.29%;
  border-radius: 999px;
  background: var(--ink); border-color: var(--ink); color: var(--cream);
  cursor: pointer;
  transition: transform .18s ease, filter .18s ease, opacity .2s ease;
}
.rsvp__submit:active { transform: scale(.985); filter: brightness(1.12); }
.rsvp__submit[disabled] { opacity: .6; cursor: progress; }

.rsvp__msg {
  position: absolute; left: 19.10%; width: 61.49%; top: 75.8%;
  margin: 0; text-align: center; font-size: 3.4cqw; min-height: 4cqw;
  color: #8a3b2a;
}

/* ── step two: head count, phone, anything we should know ─────────── */
/* It replaces the printed card rather than sitting under it, so the page
   keeps its composition and the caterer still gets a number. */
.rsvp2 {
  position: absolute; z-index: 7;
  left: 13%; width: 74%;
  /* starts below the printed «هذه الدعوة خاصة…» line so the invitation's own
     words stay on the page while the form takes over the card */
  top: 31%; bottom: 5.5%;
  display: flex; flex-direction: column; gap: 2.2cqw;
  background: var(--cream);
  border: 0.32cqw solid var(--gold-lt); border-radius: 3.4cqw;
  padding: 4.4cqw 4cqw;
  overflow-y: auto;
  box-shadow: 0 1.4cqw 4cqw rgba(48, 38, 22, .2);
  animation: rise .5s both;
}
.rsvp2__title {
  margin: 0 0 .4cqw; text-align: center;
  font-size: 5.2cqw; color: var(--ink);
}

.field { display: flex; flex-direction: column; gap: 1.4cqw; }
.field__label { font-size: 3.6cqw; color: var(--ink); opacity: .86; }
.field__label i { font-style: normal; opacity: .55; font-size: .86em; }

.field__input {
  font-family: var(--ar); font-size: 4cqw; color: var(--ink);
  background: #fffaf1; border: 0.28cqw solid var(--gold-lt);
  border-radius: 2.2cqw; padding: 2.2cqw 2.6cqw;
  width: 100%; -webkit-appearance: none; appearance: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.field__input::placeholder { color: var(--ink); opacity: .38; }
.field__input:focus {
  outline: 0; border-color: var(--gold);
  box-shadow: 0 0 0 0.45cqw rgba(153, 98, 64, .15);
}

.field--count { flex-direction: row; align-items: center; justify-content: space-between; gap: 2cqw; }

.stepper {
  display: inline-flex; align-items: center; gap: 1cqw;
  /* − on the left, + on the right, as on a number line — the digits are
     Latin here too, so LTR is the readable order in both languages */
  direction: ltr;
  background: #fffaf1; border: 0.28cqw solid var(--gold-lt);
  border-radius: 999px; padding: 0.8cqw;
}
.stepper__btn {
  width: 8cqw; height: 8cqw; flex: none;
  display: grid; place-items: center; cursor: pointer;
  font-family: var(--la); font-size: 5cqw; line-height: 1;
  color: var(--cream-lt); background: var(--gold);
  border: 0; border-radius: 50%;
  -webkit-tap-highlight-color: transparent;
  transition: transform .15s ease, filter .15s ease;
}
.stepper__btn:active { transform: scale(.92); filter: brightness(1.1); }
.stepper__val {
  width: 11cqw; border: 0; background: none; text-align: center;
  font-family: var(--la); font-size: 5.4cqw; font-weight: 500; color: var(--gold);
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield; appearance: textfield;
}
.stepper__val::-webkit-outer-spin-button,
.stepper__val::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.stepper__val:focus { outline: 0; }

.rsvp2__submit {
  margin-top: auto;
  font-family: var(--ar); font-size: 4.4cqw; line-height: 1.4;
  color: var(--cream); background: var(--ink);
  border: 0; border-radius: 999px; padding: 2.6cqw;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease, filter .18s ease, opacity .2s ease;
}
.rsvp2__submit:active { transform: scale(.985); filter: brightness(1.12); }
.rsvp2__submit[disabled] { opacity: .6; cursor: progress; }

.rsvp__msg--step2 { position: static; width: auto; min-height: 0; font-size: 3.4cqw; }

.rsvp2__back {
  font-family: var(--ar); font-size: 3.4cqw;
  background: none; border: 0; color: var(--ink); opacity: .6;
  cursor: pointer; padding: .4cqw;
}

.thanks {
  position: absolute; z-index: 7;
  left: 19.10%; width: 61.49%;
  top: 38.50%; min-height: 36%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2.4cqw; text-align: center;
  background: var(--cream);
  border: 0.32cqw solid var(--gold-lt); border-radius: 3.4cqw;
  padding: 4cqw 3cqw;
  animation: rise .7s both;
}
.thanks[hidden] { display: none; }
.thanks__line { margin: 0; font-size: 6.4cqw; color: var(--ink); }
.thanks__sub  { margin: 0; font-size: 4.2cqw; color: var(--ink); opacity: .75; line-height: 1.5; }

/* ── countdown strip ──────────────────────────────────────────────── */
.strip { background: var(--paper); padding: clamp(28px, 8vw, 54px) clamp(18px, 6vw, 34px); }
.strip__inner { display: flex; flex-direction: column; align-items: center; gap: clamp(14px, 4vw, 22px); }
.strip__title { margin: 0; font-size: clamp(19px, 5.4vw, 26px); font-weight: 400; color: var(--ink); }
.strip__actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }

.rule { display: block; width: 46%; height: 1px; position: relative;
        background: linear-gradient(90deg, transparent, var(--gold-lt), transparent); }
.rule::after {
  content: '❖'; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: var(--paper); padding: 0 8px; color: var(--gold-lt); font-size: 10px;
}

.count {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(6px, 2.4vw, 14px); width: 100%; max-width: 420px;
  /* days first, reading left to right — the page is RTL, which would
     otherwise put the seconds on the left and the days on the right */
  direction: ltr;
}
.count__cell {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: clamp(8px, 2.6vw, 14px) 2px;
  background: var(--cream); border: 1px solid var(--gold-lt); border-radius: 12px;
}
.count__cell b {
  font-family: var(--la); font-weight: 500; color: var(--gold);
  font-size: clamp(24px, 8vw, 38px); line-height: 1; font-variant-numeric: tabular-nums;
}
.count__cell span { font-size: clamp(11px, 3.2vw, 14px); color: var(--ink); opacity: .72; }
.count__done { grid-column: 1 / -1; margin: 0; text-align: center; }

.ghost-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  font-family: var(--ar); font-size: clamp(14px, 4vw, 17px);
  color: var(--ink); background: transparent;
  border: 1px solid var(--gold-lt); border-radius: 999px;
  padding: .62em 1.5em; cursor: pointer; text-decoration: none;
  transition: background-color .2s ease, transform .18s ease;
  -webkit-tap-highlight-color: transparent;
}
.ghost-btn:active { transform: scale(.97); }
.ghost-btn:hover { background: var(--cream); }
.ghost-btn--sm { border-color: var(--gold); color: var(--gold); font-size: 3.6cqw; padding: .5em 1.4em; }

/* ── outro ────────────────────────────────────────────────────────── */
.outro {
  background: var(--paper);
  padding: clamp(30px, 9vw, 60px) clamp(18px, 6vw, 34px) calc(clamp(30px, 9vw, 60px) + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: center; gap: clamp(14px, 4vw, 22px);
  text-align: center;
}
.outro__names { margin: 0; font-size: clamp(28px, 9vw, 42px); color: var(--ink); line-height: 1.3; }
.outro__names i { font-style: normal; color: var(--gold-pale); }
.outro__meta { margin: 0; font-size: clamp(14px, 4vw, 17px); color: var(--ink); opacity: .78; line-height: 1.9; }
.outro__actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.outro__tag { margin: 0; font-size: clamp(13px, 3.8vw, 16px); color: var(--gold); letter-spacing: .02em; }

/* only ever seen with scripting off */
.nojs { display: none; background: var(--cream); padding: clamp(24px, 7vw, 40px) clamp(18px, 6vw, 34px);
        text-align: center; font-size: clamp(14px, 4vw, 17px); line-height: 1.9; border-top: 1px solid var(--gold-lt); }
.nojs a { color: var(--gold); }
.nojs__contacts { margin: .6em 0 1.2em; }

/* ── ambience ─────────────────────────────────────────────────────── */
.sound {
  position: fixed; inset-block-start: calc(12px + env(safe-area-inset-top));
  z-index: 45; height: 40px; border-radius: 999px;
  display: grid; place-items: center; cursor: pointer;
  color: var(--ink); background: rgba(241, 231, 216, .85);
  border: 1px solid var(--gold-lt); backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .6s ease .6s, transform .2s ease;
  -webkit-tap-highlight-color: transparent;
}
.sound { inset-inline-start: 12px; width: 40px; overflow: hidden; }
/* the class sets display:grid, which would otherwise beat the UA [hidden] rule */
.sound[hidden] { display: none; }
body.opened .sound { opacity: 1; }
.sound:active { transform: scale(.94); }

/* ── the music button: five dancing bars ──────────────────────────── */
.eq {
  display: flex; align-items: flex-end; justify-content: center;
  gap: 2px; height: 17px;
}
.eq i {
  display: block; width: 2.5px; height: 100%;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--gold-pale), var(--gold));
  transform-origin: bottom center;
  transform: scaleY(.18);
  transition: transform .45s cubic-bezier(.22, 1, .36, 1);
}

/* playing: each bar runs at its own tempo, so they never move as a block */
.sound[aria-pressed="true"] .eq i { animation: eq 1s ease-in-out infinite alternate; }
.sound[aria-pressed="true"] .eq i:nth-child(1) { animation-duration: .82s; animation-delay: -.42s }
.sound[aria-pressed="true"] .eq i:nth-child(2) { animation-duration: .57s; animation-delay: -.18s }
.sound[aria-pressed="true"] .eq i:nth-child(3) { animation-duration: .95s; animation-delay: -.64s }
.sound[aria-pressed="true"] .eq i:nth-child(4) { animation-duration: .68s; animation-delay: -.31s }
.sound[aria-pressed="true"] .eq i:nth-child(5) { animation-duration: .88s; animation-delay: -.07s }

@keyframes eq {
  from { transform: scaleY(.20) }
  to   { transform: scaleY(1) }
}

/* muted: the bars settle, and a hairline strikes through them */
.sound[aria-pressed="false"] .eq i { animation: none; transform: scaleY(.18); opacity: .5; }
.sound[aria-pressed="false"]::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 24px; height: 1.5px; border-radius: 2px;
  background: var(--gold);
  transform: translate(-50%, -50%) rotate(-45deg);
  opacity: .75;
}

.scroll-hint {
  position: fixed; inset-block-end: calc(16px + env(safe-area-inset-bottom)); left: 50%;
  z-index: 45; width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center; color: var(--cream-lt);
  background: rgba(68, 57, 39, .55); border: 1px solid rgba(220, 160, 91, .5);
  backdrop-filter: blur(4px); text-decoration: none;
  opacity: 0; pointer-events: none; transition: opacity .5s ease;
  animation: bob 2.4s ease-in-out infinite;
}
body.opened .scroll-hint.show { opacity: 1; pointer-events: auto; }
@keyframes bob { 0%, 100% { transform: translate(-50%, 0) } 50% { transform: translate(-50%, 6px) } }

/* ── motion & print ───────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .page .lyr { opacity: 1 !important; filter: none !important; }
  .glow { opacity: .55; }
  .sky, .stars, .sheen, .waves, .rays { display: none; }
  .frond { animation: none !important; }
  .lamp::before, .lamp::after { animation: none !important; }
  .sound[aria-pressed="true"] .eq i { transform: scaleY(.62) !important; }
  .eq i:nth-child(2) { transform: scaleY(.9) !important }
  .eq i:nth-child(4) { transform: scaleY(.78) !important }
}

@media print {
  .cover, .sound, .scroll-hint, .progress, .ghost-btn,
  .sky, .stars, .sheen, .waves, .rays, .rsvp2 { display: none !important; }
  .deck { opacity: 1; box-shadow: none; width: 100%; }
  .reveal, .page .lyr { opacity: 1 !important; transform: none !important; filter: none !important; }
  .page::before { display: none; }
}
