/* =========================================================================
   نسيم و أمل — نظام التصميم
   Design system taken from the printed card: cream paper, antique gold,
   near-black ink, a navy borrowed from the card's own QR, and one muted
   blue-grey accent. No emerald, no burgundy.
   ========================================================================= */

/* ---- 1. Tokens --------------------------------------------------------- */
:root {
  /* Paper */
  --paper:        #F8F3EA;
  --paper-deep:   #F1E8D9;
  --paper-edge:   #EADFC9;

  /* Ink — this is what body text uses. Never gold. */
  --ink:          #1B1B1D;
  --ink-soft:     #4E4A45;
  --ink-faint:    #8A827A;

  /* Navy, colour-picked from the QR on the printed card */
  --navy:         #1C2A35;
  --navy-soft:    #2C3E4C;

  /* Antique gold — ornament only */
  --gold-deep:    #8F6C22;
  /* Gold taken dark enough to READ. --gold-deep is about 4:1 on the cream and
     fails as body text; this is about 6:1. Use it wherever gold carries a fact
     a guest has to make out — a number, a name — rather than decoration. */
  --gold-ink:     #6E5115;

  /* The two textures, named once because paper is drawn in six places — the
     page grain and all four envelope panels — and every one of them must ask
     for the SAME file or the browser downloads both formats.

     The JPEGs are the value here; the WebP override below only applies where
     image-set is understood. WebP saves 68 KB of the 200 KB these two cost,
     and jasmine is the largest thing this page paints, so it is the LCP.
     A phone too old for image-set simply gets the JPEG. A phone too old for
     both still gets a readable invitation — these are decoration. */
  --img-paper:    url("../img/paper.jpg");
  --img-jasmine:  url("../img/jasmine.jpg");
  --gold:         #B8912F;
  --gold-mid:     #C9A227;
  --gold-light:   #E8D08A;
  --gold-pale:    #F0E3BE;
  --gold-line:    #C3A65C;

  /* The muted blue-grey beside the verse on the card */
  --accent:       #8FA2B0;

  /* Gold as a gradient, never a flat yellow */
  --gold-grad: linear-gradient(100deg,
                 var(--gold-deep) 0%,
                 var(--gold-mid) 28%,
                 var(--gold-light) 48%,
                 var(--gold-mid) 68%,
                 var(--gold-deep) 100%);

  /* Type */
  --font-display: 'Aref Ruqaa', 'Amiri', serif;
  --font-body:    'Cairo', 'Tajawal', system-ui, sans-serif;
  --font-latin:   'Cormorant Garamond', 'EB Garamond', Georgia, serif;
  /* For the N & A monogram only. Aref Ruqaa has no Latin letters, so the
     calligraphy of the Arabic closing line is matched with a formal Latin
     script: the same flowing strokes and thick-thin contrast.
     Pinyon Script, not Great Vibes: the latter's capital A is a looped form
     that reads as a lowercase a, and its N carries a swash. Pinyon's
     capitals are unambiguously capitals. */
  --font-script:  'Pinyon Script', 'Great Vibes', cursive;

  /* Rhythm */
  --gutter: clamp(1.25rem, 5vw, 2.5rem);
  --section-gap: clamp(3.5rem, 12vw, 7rem);
  --measure: 34rem;
}

/* The WebP override. Separate from :root above so that a browser which does
   not understand image-set() simply keeps the JPEG defined there — an unknown
   value inside a custom property is not caught until it is used, so the test
   has to happen here, at declaration time. */
@supports (background-image: image-set(url("../img/paper.webp") type("image/webp"))) {
  :root {
    --img-paper:   image-set(url("../img/paper.webp")   type("image/webp"),
                             url("../img/paper.jpg")    type("image/jpeg"));
    --img-jasmine: image-set(url("../img/jasmine.webp") type("image/webp"),
                             url("../img/jasmine.jpg")  type("image/jpeg"));
  }
}

/* ---- 2. Base ----------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* the jasmine corners deliberately hang past the layout edge; without this
     they add a sideways scrollbar. `clip` is preferred over `hidden` because
     it does not turn <html> into a scroll container. */
  overflow-x: hidden;
  overflow-x: clip;
}

body {
  margin: 0;
  /* so the jasmine can be placed against the whole document, not the viewport */
  position: relative;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  /* 17px floor — many guests are 50+ reading on a phone outdoors */
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.1875rem);
  line-height: 1.85;
  font-weight: 400;
  overflow-x: hidden;
  background-image:
    radial-gradient(ellipse at 20% 0%, rgba(200,170,100,.07), transparent 55%),
    radial-gradient(ellipse at 80% 100%, rgba(143,162,176,.07), transparent 55%);
}

/* Real laid-paper fibres. Multiplied over the cream so it darkens into the
   page rather than sitting on top of it as a grey film. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: .55;
  mix-blend-mode: multiply;
  /* One tile covering the fixed viewport — repeating at 620px left faint
     vertical seams wherever the tile edges landed. `cover` has no seams. */
  background: var(--img-paper) no-repeat center / cover;
}

h1, h2, h3 { font-family: var(--font-display); font-weight: 400; line-height: 1.5; margin: 0; }
p { margin: 0 0 1em; }

/* Latin venue names keep their own serif and stay left-to-right */
.latin {
  font-family: var(--font-latin);
  font-weight: 700;
  letter-spacing: .02em;
  direction: ltr;
  unicode-bidi: isolate;
}

/* Every number is isolated so RTL never reverses a time or a date */
bdi, .num { font-variant-numeric: tabular-nums lining-nums; unicode-bidi: isolate; }

/* ---- 3. Layout --------------------------------------------------------- */
.page {
  position: relative;
  z-index: 2;
  max-width: 46rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* content sits above the botanicals */
section, .footer, .welcome { position: relative; z-index: 1; }

section { padding-block: var(--section-gap); }

/* ---- Jasmine corners ---------------------------------------------------
   Tunisia's own flower. Drawn with multiply, so the white paper the
   illustration was painted on disappears into the cream and only the
   petals and leaves remain — no cut-out, no fringing.
   ---------------------------------------------------------------------- */
.botanical {
  position: absolute;
  /* above the paper grain (z-index 1, same level, later in DOM) and below
     the content (.page, z-index 2) */
  z-index: 1;
  width: min(62%, 330px);
  aspect-ratio: 1;
  background: var(--img-jasmine) no-repeat center / contain;
  mix-blend-mode: multiply;
  opacity: .92;
  pointer-events: none;
}
.botanical--tr { top: 2.5rem;  right: 0; }
.botanical--bl { bottom: 5rem; left: 0; transform: scale(-1); }

@media (max-width: 30rem) {
  .botanical { width: 72%; opacity: .8; }
}

.center { text-align: center; }
.measure { max-width: var(--measure); margin-inline: auto; }

/* ---- 4. The thin gold frame around the whole page ---------------------- */
.frame {
  position: fixed;
  inset: clamp(.5rem, 2vw, 1rem);
  pointer-events: none;
  z-index: 3;
  border: 1px solid transparent;
  border-image: var(--gold-grad) 1;
  opacity: .55;
}
.frame-corner {
  position: absolute;
  width: clamp(28px, 7vw, 48px);
  height: auto;
  color: var(--gold);
  opacity: .85;
}
.frame-corner--tr { top: -1px; right: -1px; }
.frame-corner--tl { top: -1px; left: -1px;  transform: scaleX(-1); }
.frame-corner--br { bottom: -1px; right: -1px; transform: scaleY(-1); }
.frame-corner--bl { bottom: -1px; left: -1px;  transform: scale(-1); }

/* ---- 5. Gold text ------------------------------------------------------ */
.gold {
  background: var(--gold-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* fallback for anything that cannot clip a gradient */
  -webkit-text-fill-color: transparent;
}
@supports not (background-clip: text) {
  .gold { color: var(--gold); -webkit-text-fill-color: var(--gold); }
}

/* Every section heading is set in real Aref Ruqaa Bold, not a faked one.
   The gold above is a gradient painted through the letterforms, so the usual
   thickening trick (-webkit-text-stroke) is not available here: a stroke is
   drawn in a flat colour and would outline each letter in a solid yellow the
   gradient never reaches. The bold weight is already in the font request at
   the top of index.html, but nothing used it until now, so this line is what
   makes the browser fetch it. Measured, not guessed: the bold Arabic subset is
   45,948 B and its Latin subset 14,468 B - the latter is pulled in by the plain
   space character, so it cannot be avoided. About 59 KB in total, and the bold
   face is genuinely larger than the regular one. That is the whole cost of the
   change, and it buys thicker strokes for the gradient to
   fill, which is what actually makes gold text legible on paper-coloured
   background. Grouped in one rule so the headings can never drift apart. */
.bismillah, .verse-sign, .countdown-label, .couple-title,
.night-title, .practical h2, .news-title, .rsvp-title,
.race-title, .wishes-title, .moments-title,
.gate-hello, .env-name {
  font-weight: 700;
}

/* Slow shimmer sweep across the couple's names */
.shimmer {
  background: linear-gradient(100deg,
    var(--gold-deep) 0%, var(--gold-mid) 30%,
    #FBF3D6 46%, var(--gold-light) 52%,
    var(--gold-mid) 68%, var(--gold-deep) 100%);
  background-size: 250% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: sweep 7s ease-in-out infinite;
}
@keyframes sweep {
  0%, 100% { background-position: 120% 0; }
  50%      { background-position: -20% 0; }
}

/* ---- 6. Ornaments ------------------------------------------------------ */
.rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .9rem;
  margin-block: clamp(1.75rem, 6vw, 3rem);
  color: var(--gold);
}
.rule::before, .rule::after {
  content: '';
  height: 1px;
  flex: 1;
  max-width: 9rem;
  background: linear-gradient(to var(--dir, left),
              transparent, var(--gold-line) 35%, var(--gold-line) 65%, transparent);
}
.rule svg { width: clamp(38px, 11vw, 62px); height: auto; flex: none; }

/* The card's double hairline */
.rule--double { flex-direction: column; gap: .3rem; }
.rule--double .lines { width: min(100%, 22rem); }

.ornament { color: var(--gold); display: block; margin-inline: auto; }

/* Torn paper edge, like the top of the printed card */
.torn {
  position: relative;
  height: 22px;
  margin-top: calc(var(--section-gap) * -.5);
  background: var(--paper-deep);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1200' height='22' preserveAspectRatio='none'%3E%3Cpath d='M0 22V6c60-4 120 5 180 2s120-9 180-6 120 10 180 8 120-8 180-5 120 7 180 5 120-6 180-4v16z' fill='%23000'/%3E%3C/svg%3E") no-repeat center/100% 100%;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1200' height='22' preserveAspectRatio='none'%3E%3Cpath d='M0 22V6c60-4 120 5 180 2s120-9 180-6 120 10 180 8 120-8 180-5 120 7 180 5 120-6 180-4v16z' fill='%23000'/%3E%3C/svg%3E") no-repeat center/100% 100%;
}

/* ---- 7. Opening: bismillah + verse ------------------------------------- */
.bismillah {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 7.8vw, 2.7rem);
  line-height: 1.9;
  margin-bottom: clamp(1.5rem, 6vw, 2.5rem);
}

.verse-block {
  position: relative;
  padding-inline: clamp(1.5rem, 8vw, 3.5rem);
}
.verse {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 4.6vw, 1.7rem);
  line-height: 2.15;
  color: var(--ink);
  margin-bottom: .75rem;
}
.verse-sign {
  font-family: var(--font-display);
  font-size: clamp(.92rem, 3.4vw, 1.12rem);
  letter-spacing: .04em;
}
/* the two muted blue-grey motifs flanking the verse on the card */
.verse-motif {
  position: absolute;
  top: 0;
  width: clamp(22px, 6vw, 34px);
  color: var(--accent);
  opacity: .8;
}
.verse-motif--start { inset-inline-start: 0; }
.verse-motif--end   { inset-inline-end: 0; transform: scaleX(-1); }

/* ---- 8. Families ------------------------------------------------------- */
.greeting {
  color: var(--ink-soft);
  font-size: clamp(.95rem, 3.4vw, 1.05rem);
  margin-bottom: clamp(1.5rem, 5vw, 2.25rem);
}

.families {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.5rem, 6vw, 2rem);
  margin-bottom: clamp(1.5rem, 5vw, 2.25rem);
}
@media (min-width: 40rem) {
  .families { grid-template-columns: 1fr auto 1fr; align-items: center; }
  .families .divider {
    width: 1px; height: 100%; min-height: 4.5rem;
    background: linear-gradient(to bottom, transparent, var(--gold-line), transparent);
  }
}
.family { text-align: center; }
.family p { margin: 0; line-height: 1.95; font-weight: 500; }
.family .mother { color: var(--ink-soft); font-weight: 400; }

.honour {
  color: var(--ink-soft);
  font-size: clamp(.95rem, 3.4vw, 1.05rem);
}

/* ---- 9. The names ------------------------------------------------------ */
.names {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(.5rem, 3vw, 1.5rem);
  margin-block: clamp(1.5rem, 6vw, 2.5rem);
  flex-wrap: nowrap;
}
.name {
  font-family: var(--font-display);
  font-size: clamp(3rem, 16vw, 6rem);
  line-height: 1.25;
  color: var(--ink);
  white-space: nowrap;
}
.amp {
  font-family: var(--font-latin);
  font-size: clamp(2.25rem, 11vw, 4.5rem);
  font-style: italic;
  line-height: 1;
  flex: none;
}

/* ---- 10. Countdown ----------------------------------------------------- */
.countdown-label {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 5vw, 1.68rem);
  margin-bottom: 1.25rem;
}
.countdown {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(.4rem, 2vw, .9rem);
  max-width: 30rem;
  margin-inline: auto;
  direction: ltr; /* days | hours | minutes | seconds reads left to right */
}
.cd-cell {
  position: relative;
  padding: clamp(.6rem, 3vw, 1rem) .25rem;
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  box-shadow: inset 0 0 0 1px rgba(248,243,234,.7);
}
.cd-num {
  display: block;
  font-family: var(--font-latin);
  font-weight: 600;
  font-size: clamp(1.6rem, 8vw, 2.6rem);
  line-height: 1.1;
  color: var(--navy);
  font-variant-numeric: tabular-nums lining-nums;
}
.cd-unit {
  display: block;
  font-size: clamp(.68rem, 2.7vw, .82rem);
  color: var(--ink-soft);
  letter-spacing: .02em;
  margin-top: .15rem;
}
.countdown-note {
  margin-top: 1rem;
  font-size: clamp(.85rem, 3.2vw, .95rem);
  color: var(--ink-soft);
}

/* ---- 11. The three nights ---------------------------------------------- */
/* The cards are full width and opaque, so the thread is only ever seen in
   the gaps between them. A 1px hairline at half opacity in a 30px gap is
   invisible — it needs real weight and a node to land on. */
.timeline {
  position: relative;
  display: grid;
  /* the gaps are the only place the thread is ever seen, so they have to be
     wide enough to actually show line either side of each node */
  gap: clamp(2.6rem, 9vw, 3.6rem);
}
.timeline::before {
  content: '';
  position: absolute;
  inset-inline-start: 50%;
  /* runs INTO the first night and OUT of the last, so it reads as one
     continuous line passing behind the cards rather than stray segments */
  top: -2.75rem; bottom: -2.75rem;
  width: 2px;
  transform: translateX(50%);
  background: linear-gradient(to bottom,
              transparent, var(--gold-line) 5%, var(--gold-line) 95%, transparent);
  opacity: .85;
}

/* the node the thread runs through, between one night and the next */
.thread-node {
  position: relative;
  z-index: 1;
  justify-self: center;
  width: 11px; height: 11px;
  transform: rotate(45deg);
  background: var(--paper);
  border: 1px solid var(--gold);
  box-shadow: 0 0 0 4px var(--paper);
}

.night {
  position: relative;
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  padding: clamp(1.5rem, 6vw, 2.5rem) clamp(1.15rem, 5vw, 2rem);
  text-align: center;
  box-shadow: 0 1px 0 rgba(27,27,29,.04), inset 0 0 0 1px rgba(248,243,234,.65);
}
.night::before,
.night::after {
  content: '';
  position: absolute;
  width: 14px; height: 14px;
  border: 1px solid var(--gold);
  opacity: .7;
}
.night::before { top: 7px; inset-inline-start: 7px; border-width: 1px 0 0 1px; }
.night::after  { bottom: 7px; inset-inline-end: 7px; border-width: 0 1px 1px 0; }

/* The wedding night — largest, crowned with a gold arch */
.night--main {
  background: var(--paper);
  border-width: 2px;
  padding-top: clamp(2.5rem, 9vw, 3.75rem);
  /* room for the crowning arch, so it does not collide with the thread node
     sitting in the gap above it */
  margin-top: clamp(.75rem, 3vw, 1.25rem);
}
.night--main .night-title { font-size: clamp(1.78rem, 7.2vw, 2.6rem); }
.night-arch {
  position: absolute;
  top: 0; left: 50%;
  transform: translate(-50%, -48%);
  width: clamp(72px, 22vw, 108px);
  color: var(--gold);
  background: var(--paper);
  padding-inline: .5rem;
}

.night-icon { color: var(--gold); width: clamp(34px, 9vw, 46px); margin: 0 auto .75rem; display: block; }
.night-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 6.1vw, 2.1rem);
  margin-bottom: .5rem;
}
.night-date {
  font-size: clamp(1rem, 3.8vw, 1.1rem);
  font-weight: 600;
  color: var(--navy);
  margin-bottom: .35rem;
}
.night-time { color: var(--ink-soft); font-size: clamp(.92rem, 3.4vw, 1rem); margin-bottom: 1rem; }
.night-venue { font-size: clamp(1.3rem, 5.1vw, 1.62rem); margin-bottom: .1rem; }
.night-town { color: var(--ink-soft); font-size: clamp(.88rem, 3.2vw, .98rem); margin-bottom: 1.35rem; }
.night-town strong { color: var(--navy); font-weight: 600; }

/* ---- 12. Buttons ------------------------------------------------------- */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  justify-content: center;
}
.btn {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .7rem 1.15rem;
  font-family: var(--font-body);
  font-size: clamp(.88rem, 3.2vw, .95rem);
  font-weight: 600;
  color: var(--navy);
  background: transparent;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  text-decoration: none;
  cursor: pointer;
  transition: background .25s ease, color .25s ease, border-color .25s ease;
  min-height: 44px; /* thumb-sized */
}
.btn svg { width: 17px; height: 17px; flex: none; }
.btn:hover, .btn:focus-visible {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--paper);
}
.btn--gold { border-color: var(--gold); }
.btn--gold:hover, .btn--gold:focus-visible { background: var(--gold-deep); border-color: var(--gold-deep); }

:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* ---- 13. Practical info ------------------------------------------------ */
/* Paper, not a navy slab. The page is one material — a printed card is
   cream and gold and ink all the way through, and a solid dark block was
   the only element here that could never appear on the real card. Navy
   stays, but as ink, which is what it is on the card. */
.practical {
  position: relative;
  background: var(--paper-deep);
  color: var(--ink);
  padding: clamp(1.75rem, 7vw, 2.75rem) clamp(1.25rem, 5vw, 2.25rem);
  text-align: center;
  border: 1px solid var(--gold-line);
}
.practical::before, .practical::after {
  content: '';
  position: absolute;
  width: 14px; height: 14px;
  border: 1px solid var(--gold);
  opacity: .7;
}
.practical::before { top: 7px; inset-inline-start: 7px; border-width: 1px 0 0 1px; }
.practical::after  { bottom: 7px; inset-inline-end: 7px; border-width: 0 1px 1px 0; }

.practical h2 {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.8vw, 2.05rem);
  margin-bottom: 1rem;
}
.practical p { color: var(--ink-soft); }

/* the lighter second route to the calendar, deliberately not a button */
.alt-link {
  margin: .7rem 0 0;
  font-size: clamp(.82rem, 3vw, .9rem);
}
.alt-link a {
  color: var(--ink-soft);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--gold-line);
}
.alt-link a:hover, .alt-link a:focus-visible { color: var(--navy); }

/* The one line Android needs. Hidden everywhere by default and switched on
   by the .is-android class main.js puts on <html>, so an iPhone — where the
   .ics opens straight into the "add event" sheet — never sees it. Quiet: it
   is an instruction, not a warning. */
.cal-hint { display: none; }
.is-android .cal-hint {
  display: block;
  margin: .55rem 0 0;
  font-size: clamp(.8rem, 3vw, .88rem);
  line-height: 1.6;
  color: var(--ink-faint);
}

/* Not offered on a phone at all.

   Google Calendar has no mobile web page for creating an event. Whatever
   address you send a phone to — the old /calendar/render?action=TEMPLATE or
   the current /calendar/r/eventedit — it serves the full desktop editor: two
   columns, "Invités" beside the details, and the time zone clipped off the
   right edge. Confirmed on a real iPhone on 1 September 2026, after the
   endpoint had already been changed. The parameters arrive perfectly; it is
   the page itself that has no phone layout.

   So the link is only shown where it actually works. On a phone the gold
   «أضف إلى التقويم» button above is both the better route and the complete
   one: the hosted .ics is handed to whatever calendar the phone already uses,
   Google included, with no account and no browser page in the way.

   pointer: coarse rather than width alone, because what matters is that it is
   a touch device; the width ceiling keeps touch-screen laptops out of it. */
@media (pointer: coarse) and (max-width: 1024px) {
  .alt-link { display: none; }
}
.info-grid {
  display: grid;
  gap: 1rem;
  margin-block: 1.5rem;
  text-align: center;
}
@media (min-width: 34rem) { .info-grid { grid-template-columns: repeat(2, 1fr); } }
.info-item strong { display: block; color: var(--navy); font-weight: 600; margin-bottom: .15rem; }

/* Loud warning while the phone number is still the placeholder */
.placeholder-warn {
  background: #7A1F1F;
  color: #fff;
  padding: .85rem 1rem;
  text-align: center;
  font-weight: 700;
  font-size: .95rem;
  letter-spacing: .01em;
}

/* ---- 13b. RSVP --------------------------------------------------------- */
.rsvp {
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  padding: clamp(1.5rem, 6vw, 2.5rem) clamp(1.15rem, 5vw, 2rem);
  text-align: center;
  position: relative;
}
.rsvp::before, .rsvp::after {
  content: '';
  position: absolute;
  width: 14px; height: 14px;
  border: 1px solid var(--gold);
  opacity: .7;
}
.rsvp::before { top: 7px; inset-inline-start: 7px; border-width: 1px 0 0 1px; }
.rsvp::after  { bottom: 7px; inset-inline-end: 7px; border-width: 0 1px 1px 0; }

.rsvp-title {
  font-family: var(--font-display);
  font-size: clamp(1.66rem, 6.6vw, 2.33rem);
  margin-bottom: .35rem;
}
.rsvp-intro { color: var(--ink-soft); font-size: clamp(.92rem, 3.4vw, 1rem); margin-bottom: 1.5rem; }

/* "What you wrote is kept." Deliberately quiet: this is a reassurance, not a
   warning, so no red, no icon, no box that shouts. The gold hairline on the
   leading edge is the same one that edges the practical box, so it reads as
   part of the invitation and not as something the browser put there.
   text-align: start because it is a sentence, and .rsvp centres its children. */
.rsvp-draft {
  color: var(--ink-soft);
  font-size: clamp(.85rem, 3.2vw, .95rem);
  line-height: 1.75;
  text-align: start;
  background: var(--paper-deep);
  border-inline-start: 2px solid var(--gold-line);
  padding: .6rem .85rem;
  margin: 0 0 1.5rem;
}
.rsvp-draft[hidden] { display: none; }

.rsvp-form { display: grid; gap: 1rem; text-align: start; }
.rsvp-form[hidden] { display: none; }

.field-hint { display: block; font-size: .8rem; color: var(--ink-faint); margin-top: .25rem; }

.fs { border: 0; margin: 0; padding: 0; }
.fs legend {
  padding: 0;
  font-size: .85rem;
  color: var(--ink-soft);
  margin-bottom: .45rem;
}

/* yes / no */
.choice2 { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.choice {
  font-family: var(--font-body);
  font-size: clamp(.9rem, 3.4vw, 1rem);
  font-weight: 600;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  padding: .8rem .5rem;
  min-height: 48px;
  cursor: pointer;
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.choice[aria-pressed="true"] { background: var(--navy); border-color: var(--navy); color: var(--gold-light); }

/* which nights */
.nights-pick { display: grid; gap: .5rem; }
.night-pick {
  display: flex;
  align-items: center;
  gap: .65rem;
  background: var(--paper);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  padding: .7rem .8rem;
  cursor: pointer;
  min-height: 48px;
}
.night-pick input { width: 20px; height: 20px; accent-color: var(--navy); flex: none; }
.night-pick-txt { font-size: clamp(.88rem, 3.2vw, .97rem); line-height: 1.5; }
.night-pick-txt b { display: block; font-weight: 600; }
.night-pick-txt span { color: var(--ink-soft); font-size: .85em; }

/* adults / children */
.counts { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.counter {
  background: var(--paper);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  padding: .6rem .5rem;
  text-align: center;
}
.counter-label { display: block; font-size: .82rem; color: var(--ink-soft); margin-bottom: .35rem; }
.counter-ctl { display: flex; align-items: center; justify-content: center; gap: .35rem; }
.step {
  width: 40px; height: 40px;
  font-size: 1.35rem;
  line-height: 1;
  color: var(--navy);
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  cursor: pointer;
}
.step:disabled { opacity: .35; cursor: default; }
.counter-val {
  min-width: 2.2rem;
  font-family: var(--font-latin);
  font-weight: 600;
  font-size: 1.35rem;
  color: var(--navy);
  font-variant-numeric: tabular-nums lining-nums;
}

.check { display: flex; align-items: center; gap: .6rem; cursor: pointer; font-size: clamp(.88rem, 3.2vw, .97rem); min-height: 44px; }
.check input { width: 20px; height: 20px; accent-color: var(--navy); flex: none; }

.rsvp-form textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  padding: .7rem .85rem;
  resize: vertical;
}
.rsvp-form textarea:focus-visible { outline: 2px solid var(--navy); outline-offset: 1px; }

/* the answered state */
.rsvp-done[hidden] { display: none; }
.rsvp-done-msg {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 5vw, 1.6rem);
  color: var(--navy);
  margin-bottom: 1rem;
}

/* gold confetti (RSVP) and gold dust (the seal breaking) */
#confetti, .dust {
  position: fixed;
  inset: 0;
  pointer-events: none;
}
#confetti { z-index: 60; }
.dust     { z-index: 55; }   /* above the envelope, below the RSVP burst */

/* ---- 13b2. أخبار الحفل, the live feed during the three nights ---------- */
.newsbox {
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  padding: clamp(1.25rem, 5vw, 2rem) clamp(1.15rem, 5vw, 1.75rem);
  text-align: center;
}
.news-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.8vw, 2rem);
  margin-bottom: .9rem;
}
.news-list { list-style: none; margin: 0; padding: 0; text-align: start; }
.news-list li {
  padding: .65rem 0;
  border-top: 1px solid rgba(195,166,92,.45);
  display: flex;
  gap: .75rem;
  align-items: baseline;
  justify-content: space-between;
}
.news-list li:first-child { border-top: 0; }
.news-list li:first-child b { color: var(--navy); }
.news-list b { font-weight: 600; font-size: clamp(.95rem, 3.6vw, 1.05rem); }
.news-when {
  flex: none;
  font-family: var(--font-latin);
  font-size: .85rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* ---- 13b2. سباق الفريقين — the live team race --------------------------
   Bride and groom keep the card's own two colours: gold and navy. The
   fill is the bride's share and grows from the inline start, which in
   RTL is the right — the same side her team sits on at the gate. */
.race {
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  padding: clamp(1.25rem, 5vw, 2rem) clamp(1.15rem, 5vw, 1.75rem);
  text-align: center;
}
.race-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.8vw, 2rem);
  margin-bottom: 1rem;
}
.race-ends {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: .55rem;
  font-size: clamp(.92rem, 3.5vw, 1.02rem);
}
.race-team b {
  font-family: var(--font-latin);
  font-weight: 600;
  font-size: 1.35em;
  margin-inline-end: .3rem;
}
/* The bride's number was --gold-deep (#8F6C22) on --paper-deep, which measures
   about 3.99:1 — Lighthouse failed it, and it is a NUMBER, the one thing in
   this section a guest is meant to read. --gold-ink is the same gold taken
   dark enough to be legible (about 6:1) without leaving the palette. The
   groom's number is already navy and needs nothing. */
.race-team--arousa b { color: var(--gold-ink); }
.race-team--aris   b { color: var(--navy); }
.race-bar {
  position: relative;
  height: 14px;
  background: var(--navy);
  border: 1px solid var(--gold-line);
  overflow: hidden;
}
.race-fill {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 50%;
  background: var(--gold-grad);
  border-inline-end: 2px solid var(--paper);
  transition: width 1.4s cubic-bezier(.22, .8, .3, 1);
}
.race-note {
  margin: .7rem 0 0;
  font-size: .85rem;
  color: var(--ink-faint);
}

/* ---- 13b3. دفتر التهاني — the approved guest messages ------------------ */
.wishes {
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  padding: clamp(1.25rem, 5vw, 2rem) clamp(1.15rem, 5vw, 1.75rem);
  text-align: center;
}
.wishes-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.8vw, 2rem);
  margin-bottom: .9rem;
}
.wish-list { list-style: none; margin: 0; padding: 0; text-align: start; }
.wish {
  padding: .85rem 0;
  border-top: 1px solid rgba(195,166,92,.45);
}
.wish:first-child { border-top: 0; }
.wish-text {
  margin: 0 0 .25rem;
  font-size: clamp(.95rem, 3.6vw, 1.05rem);
  line-height: 1.8;
}
.wish-name {
  display: block;
  font-size: .85rem;
  color: var(--gold-deep);
}

/* ---- 13b3. من خطوبتنا — the couple's own photographs -------------------
   ONE frame around the whole set, not five. Five separately framed pictures
   read as five objects dropped on the page; one frame with the paper showing
   through the gaps reads as a page of an album, which is what this is. The
   frame and its two corner marks are the same as the practical box, so the
   album belongs to the same card. */
.couple-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.8vw, 2.05rem);
  text-align: center;
  margin-bottom: clamp(1rem, 4vw, 1.5rem);
}

.couple-grid {
  position: relative;
  max-width: min(30rem, 88vw);
  margin: 0 auto;
  padding: 8px;
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);

  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.couple-grid::before, .couple-grid::after {
  content: '';
  position: absolute;
  width: 14px; height: 14px;
  border: 1px solid var(--gold);
  opacity: .7;
}
.couple-grid::before { top: -7px; inset-inline-start: -7px; border-width: 1px 0 0 1px; }
.couple-grid::after  { bottom: -7px; inset-inline-end: -7px; border-width: 0 1px 1px 0; }

.cpic { margin: 0; }
.cpic--wide { grid-column: 1 / -1; }

.cpic img {
  display: block;
  width: 100%;
  height: auto;
  /* Every original is about 4:5. Declaring it here means the page reserves
     the right space before a lazy image lands, so nothing jumps under a
     reader's thumb on a slow connection. */
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center 32%;   /* their faces sit above centre */
}

/* ---- 13b4. لحظات — the published photos ------------------------------- */
.moments {
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  padding: clamp(1.25rem, 5vw, 2rem) clamp(1.15rem, 5vw, 1.75rem);
  text-align: center;
}
.moments-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.8vw, 2rem);
  margin-bottom: .9rem;
}
.moments-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .5rem;
}
.moment {
  position: relative;
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  border: 1px solid var(--gold-line);
  background: var(--paper);
}
.moment img { width: 100%; height: 100%; object-fit: cover; display: block; }
.moment-play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  color: #fff;
  text-shadow: 0 1px 6px rgba(0,0,0,.55);
}
/* a poster-less video: dark tile, just the play mark */
.moment--bare { background: var(--navy); }

/* ---- 13c. Tonight, and after the wedding ------------------------------- */
.tonight-bar {
  position: fixed;
  /* Above the gate overlay (50), not below it.
     At 40 this bar was painted UNDER the gate on the wedding nights: the big
     gold «الموقع» button rendered, but a tap on it hit the gate instead. A
     guest scanning the printed QR for the first time at 21:30, standing
     outside the wrong hall, was shown «من أي فريق أنتم؟» and could not reach
     a map until they found the faint «تخطي». That is the one moment of the
     whole three nights when the map matters more than anything else here. */
  z-index: 60;
  inset-inline: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .7rem clamp(.85rem, 4vw, 1.25rem);
  /* keep clear of the iPhone home bar */
  padding-bottom: calc(.7rem + env(safe-area-inset-bottom, 0px));
  background: var(--navy);
  border-top: 1px solid var(--gold);
  box-shadow: 0 -6px 18px rgba(27,27,29,.18);
}
.tonight-bar[hidden] { display: none; }
.tonight-txt { flex: 1; min-width: 0; line-height: 1.45; }
.tonight-kicker {
  display: inline-block;
  font-family: var(--font-display);
  font-size: .78rem;
  color: var(--navy);
  background: var(--gold-light);
  border-radius: 2px;
  padding: 0 .4rem;
  margin-bottom: .15rem;
}
.tonight-txt strong {
  display: block;
  color: var(--paper);
  font-size: clamp(.95rem, 3.6vw, 1.05rem);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tonight-place { display: block; color: #C6BCA9; font-size: .82rem; }
.tonight-bar .btn {
  flex: none;
  color: var(--navy);
  background: var(--gold-light);
  border-color: var(--gold-light);
  font-weight: 700;
}
.tonight-bar .btn:hover, .tonight-bar .btn:focus-visible {
  background: var(--paper); border-color: var(--paper); color: var(--navy);
}

/* the page needs room so the bar never covers the footer */
body.is-event-day { padding-bottom: 5.5rem; }

/* tonight's card, moved to the top of the timeline */
.night--tonight {
  border-color: var(--gold);
  border-width: 2px;
  box-shadow: 0 0 0 4px rgba(200,162,39,.14), inset 0 0 0 1px rgba(248,243,234,.65);
}
.night-tonight-flag {
  display: inline-block;
  font-family: var(--font-display);
  font-size: .85rem;
  color: var(--paper);
  background: var(--navy);
  border-radius: 2px;
  padding: .1rem .6rem;
  margin-bottom: .6rem;
}

/* after the last night, the RSVP has nothing left to ask — and neither
   does the race. The wishes stay: they become the guestbook of the memory. */
body.is-after #rsvp { display: none; }
body.is-after #race { display: none; }

/* ---- 14. Footer -------------------------------------------------------- */
.footer { padding-block: var(--section-gap) clamp(2.5rem, 8vw, 4rem); text-align: center; }
/* Latin initials, so the Latin serif — Aref Ruqaa is an Arabic face and
   would fall back to something arbitrary for N and A. */
.footer-monogram {
  font-family: var(--font-script);
  /* a script has a small x-height, so it needs more size than a serif to
     carry the same weight on the page */
  font-size: clamp(2.9rem, 12vw, 4.25rem);
  font-weight: 400;
  line-height: 1.35;          /* room for the descending flourishes */
  letter-spacing: .02em;
  direction: ltr;
  margin-bottom: .35rem;
}
.footer-date {
  font-family: var(--font-latin);
  font-size: clamp(1.05rem, 4.2vw, 1.35rem);
  letter-spacing: .3em;
  color: var(--navy);
  direction: ltr;
  margin-bottom: 1.25rem;
}
.footer-closing { font-family: var(--font-display); font-size: clamp(1.05rem, 4.2vw, 1.4rem); line-height: 1.9; }

/* «شارك الدعوة» sits under the closing line: may the same joy come to
   you — pass it on. Shown by JS only; it cannot work without it. */
.share-btn { margin-top: 1.3rem; }
.share-btn svg { width: 1.05em; height: 1.05em; }

/* =========================================================================
   14b. THE GATE AND THE ENVELOPE
   Both are overlays that start hidden in the HTML and are only ever shown
   by JavaScript. If a script fails, the guest lands on the invitation
   itself — an invitation must never be locked behind code.
   ========================================================================= */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: clamp(1.25rem, 6vw, 2.5rem);
  background: var(--paper);
  background-image:
    radial-gradient(ellipse at 50% 0%, rgba(200,170,100,.10), transparent 60%),
    radial-gradient(ellipse at 50% 100%, rgba(28,42,53,.06), transparent 60%);
  overflow-y: auto;
}
.overlay[hidden] { display: none; }
.overlay.is-leaving { opacity: 0; transition: opacity .6s ease; pointer-events: none; }

/* ---- The gate ---------------------------------------------------------- */
.gate-inner { width: min(100%, 27rem); text-align: center; }

.gate-hello {
  font-family: var(--font-display);
  font-size: clamp(1.95rem, 8.8vw, 2.85rem);
  margin-bottom: .35rem;
}
.gate-question {
  color: var(--ink-soft);
  font-size: clamp(1rem, 3.8vw, 1.1rem);
  margin-bottom: 1.5rem;
}

.teams {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem;
  margin-bottom: 1.5rem;
}
.team {
  appearance: none;
  font-family: var(--font-display);
  font-size: clamp(.98rem, 4vw, 1.2rem);
  color: var(--ink);
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  padding: clamp(1rem, 5vw, 1.5rem) .5rem;
  cursor: pointer;
  transition: background .3s ease, color .3s ease, border-color .3s ease, transform .3s ease;
  min-height: 88px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .5rem;
}
.team svg { width: 26px; height: 26px; color: var(--gold); transition: color .3s ease; }
.team:hover { transform: translateY(-2px); }
.team[aria-pressed="true"] {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--gold-light);
}
.team[aria-pressed="true"] svg { color: var(--gold-light); }

.gate-fields { display: grid; gap: .6rem; margin-bottom: 1.15rem; }
.field { text-align: start; }
.field label {
  display: block;
  font-size: .85rem;
  color: var(--ink-soft);
  margin-bottom: .25rem;
}
.field input {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1.0625rem; /* 16px+ stops iOS zooming the page on focus */
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  padding: .7rem .85rem;
  min-height: 46px;
}
.field input:focus-visible { outline: 2px solid var(--navy); outline-offset: 1px; }

.gate-error {
  color: #8C2020;
  font-size: .9rem;
  margin-bottom: .75rem;
  min-height: 1.2em;
}

.btn-open {
  width: 100%;
  justify-content: center;
  background: var(--navy);
  border-color: var(--navy);
  color: var(--gold-light);
  font-size: 1.05rem;
  padding-block: .85rem;
}
.btn-open:hover, .btn-open:focus-visible { background: var(--gold-deep); border-color: var(--gold-deep); color: var(--paper); }

.gate-skip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* a thumb needs 44px — this is the escape hatch for guests who do not
     want to type, so it must not be fiddly */
  min-height: 44px;
  padding-inline: 1rem;
  margin-top: .5rem;
  color: var(--ink-faint);
  font-size: .9rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  background: none;
  border: 0;
  cursor: pointer;
  font-family: inherit;
}
.gate-skip:hover { color: var(--ink-soft); }

/* ---- The envelope ------------------------------------------------------ */
.env-stage { width: min(100%, 27rem); text-align: center; }

.env {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 2;
  margin-inline: auto;
  perspective: 1400px;
  transform-style: preserve-3d;
}

/* One sheet of paper makes every panel. Same texture throughout, so the
   envelope reads as one real object; only the darkening changes, which is
   what tells the eye which face it is looking at. */
.env-back {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(160deg, rgba(40,30,10,.22), rgba(40,30,10,.30)),
    var(--img-paper) center / cover;
  border: 1px solid var(--gold-line);
  border-radius: 3px;
}

/* the card that slides out */
.env-letter {
  position: absolute;
  left: 4%; right: 4%; top: 6%;
  /* must stay INSIDE the envelope while closed — any taller and the card
     hangs out below the bottom edge, where nothing covers it */
  height: 92%;
  z-index: 2;
  background:
    linear-gradient(rgba(255,252,244,.55), rgba(255,252,244,.55)),
    var(--img-paper) center / cover;
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  box-shadow: 0 6px 20px rgba(27,27,29,.12);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding-top: 8%;
  gap: .35rem;
  transform: translateY(0);
  transition: transform 1s cubic-bezier(.3,.7,.3,1);
}
.env-letter-mono {
  font-family: var(--font-script);
  font-size: clamp(1.9rem, 8vw, 2.6rem);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: .02em;
  direction: ltr;
}
.env-letter-names { font-family: var(--font-display); font-size: clamp(1rem, 4vw, 1.3rem); color: var(--ink); }
.env-letter-date {
  font-family: var(--font-latin); letter-spacing: .22em; direction: ltr;
  font-size: clamp(.8rem, 3vw, .95rem); color: var(--ink-soft);
}

/* the front pocket — its top edge is the V the flap sits in */
.env-front {
  position: absolute; inset: 0; z-index: 3;
  background:
    linear-gradient(200deg, rgba(255,255,255,.30), rgba(180,150,90,.10)),
    var(--img-paper) center / cover;
  border-radius: 3px;
  clip-path: polygon(0 0, 50% 44%, 100% 0, 100% 100%, 0 100%);
  box-shadow: inset 0 0 0 1px var(--gold-line);
}

/* the guest's own name, written on the envelope */
.env-name {
  position: absolute;
  z-index: 4;
  left: 8%; right: 8%;
  top: 64%;               /* clear of the enlarged seal and its glow */
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 6.2vw, 1.92rem);
  line-height: 1.4;
  text-align: center;
  pointer-events: none;
}
.env-name::after {
  content: '';
  display: block;
  width: 45%;
  height: 1px;
  margin: .5rem auto 0;
  background: linear-gradient(to left, transparent, var(--gold-line), transparent);
}

/* the flap */
.env-flap {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 44%;
  z-index: 6;
  background:
    linear-gradient(180deg, rgba(255,255,255,.18), rgba(120,95,45,.10)),
    var(--img-paper) center / cover;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  transform-origin: top center;
  transform: rotateX(0deg);
  transition: transform .9s cubic-bezier(.6,.05,.3,1),
              filter .9s ease;
  /* a real flap casts a shadow onto the pocket while it is still closed */
  filter: drop-shadow(0 5px 7px rgba(40,30,12,.22));
  box-shadow: inset 0 0 0 1px var(--gold-line);
}

/* The inner face of a folded flap is shadowed. Without this the flap reads
   as a flat triangle spinning, not as paper turning over. */
.env-flap::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(52,38,14,0);
  transition: background .9s ease;
}

/* the wax seal */
.seal {
  position: absolute;
  z-index: 7;
  left: 50%;
  top: 44%;
  /* the seal is the hero of this screen — it was too small to read as one */
  width: clamp(76px, 22vw, 108px);
  height: clamp(76px, 22vw, 108px);
  transform: translate(-50%, -50%);
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  border-radius: 50%;
  filter: drop-shadow(0 3px 6px rgba(27,27,29,.28));
  animation: seal-breathe 3.2s ease-in-out infinite;
}
@keyframes seal-breathe {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50%      { transform: translate(-50%, -50%) scale(1.045); }
}
/* Both halves show the SAME seal image, each clipped to its own side. That
   is what makes them look like one seal until the moment it breaks. */
.seal-half {
  position: absolute;
  inset: 0;
  background-image: url("../img/seal.png");
  background-image: image-set(url("../img/seal.webp") type("image/webp"),
                              url("../img/seal.png")  type("image/png"));
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
  /* Wax shatters — it leaves fast and slows down. The earlier curve had a
     negative control point, which made the halves wind up backwards first
     like elastic. Wrong material, and the detector was right to flag it. */
  transition: transform .55s cubic-bezier(.16,.84,.44,1), opacity .55s ease;
}
.seal-half--r { clip-path: inset(0 0 0 50%); }
.seal-half--l { clip-path: inset(0 50% 0 0); }
/* ن & أ, stamped into the seal's recessed centre. Real type, never a
   generated image — image tools mangle Arabic letterforms. */
.seal-mark {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-script);
  /* Sized to the seal's RECESSED CENTRE, not the octagon. That recess is
     about 62% of the seal's width; at 23px the script's ink measured 64px
     against a 57px recess and spilled onto the bevelled rim. */
  font-size: clamp(1.02rem, 4.3vw, 1.42rem);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0;
  direction: ltr;
  color: rgba(74, 50, 8, .9);   /* thin script strokes need the extra contrast on gold */
  /* pressed into the wax: dark above, a light lip below */
  text-shadow: 0 -1px 0 rgba(60,40,6,.35), 0 1px 0 rgba(255,232,170,.55);
}

/* ---- the light that travels around the seal ---------------------------
   A glowing arc orbiting just outside the wax, with a soft halo. This is
   the moment the reference site sells, and it is only CSS — no video.
   ---------------------------------------------------------------------- */
.seal::before {
  content: '';
  position: absolute;
  inset: -14%;
  border-radius: 50%;
  background: conic-gradient(from 0deg,
              transparent 0 62%,
              rgba(255,236,178,.55) 76%,
              rgba(255,250,228,.95) 84%,
              rgba(255,236,178,.45) 90%,
              transparent 96%);
  -webkit-mask: radial-gradient(closest-side, transparent 72%, #000 78%, #000 96%, transparent 100%);
          mask: radial-gradient(closest-side, transparent 72%, #000 78%, #000 96%, transparent 100%);
  filter: blur(1.5px);
  animation: seal-orbit 3.6s linear infinite;
  pointer-events: none;
}
@keyframes seal-orbit { to { transform: rotate(360deg); } }

/* No halo behind the seal. A warm glow reads as light on a dark screen, but
   on cream paper it just looks like a washed-out patch. The travelling arc
   above carries the whole effect; the seal's own drop-shadow does the rest. */

.env-hint {
  margin-top: clamp(1.25rem, 5vw, 2rem);
  color: var(--ink-soft);
  font-size: clamp(.9rem, 3.4vw, 1rem);
  transition: opacity .4s ease;
}

/* ---- the opening sequence, driven by classes from gate.js -------------- */
.env.is-cracking .seal { animation: none; }
.env.is-cracking .seal::before { opacity: 0; transition: opacity .3s ease; }
.env.is-cracking .seal-half--r { transform: translateX(16px) rotate(14deg); opacity: 0; }
.env.is-cracking .seal-half--l { transform: translateX(-16px) rotate(-14deg); opacity: 0; }

.env.is-open .env-flap {
  transform: rotateX(-172deg);
  z-index: 0;
  /* the shadow shrinks as the flap lifts away from the pocket — a fixed
     shadow is what makes CSS paper look pasted on */
  filter: drop-shadow(0 1px 2px rgba(40,30,12,.10));
  transition: transform .9s cubic-bezier(.6,.05,.3,1),
              filter .9s ease,
              z-index 0s .45s;
}
/* and its underside darkens as it turns over */
.env.is-open .env-flap::after { background: rgba(52,38,14,.30); }

.env.is-out .env-letter { transform: translateY(-70%) scale(1.02); }

/* The opening runs 3.5s, so each beat gets room to land instead of
   overlapping the next. Durations here match the timings in gate.js. */
.env-letter { transition-duration: 1.2s; }
.env.is-open .env-flap,
.env-flap { transition-duration: 1.1s, 1.1s, 0s; }
.seal-half { transition-duration: .7s, .7s; }

/* the arc flares and accelerates the instant the seal is tapped */
.env.is-flaring .seal::before {
  animation-duration: .5s;
  filter: blur(2.5px) brightness(1.5);
}

.env-stage.is-quiet .env-hint { opacity: 0; }

/* If the guest asked for less motion, do not animate the envelope at all. */
@media (prefers-reduced-motion: reduce) {
  .seal { animation: none; }
  .env-letter, .env-flap, .seal-half { transition: none; }
}

/* ---- the small personal greeting on the invitation --------------------- */
.welcome {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  flex-wrap: wrap;
  margin-top: clamp(1.5rem, 6vw, 2.5rem);
  padding: .6rem 1rem;
  background: var(--paper-deep);
  border: 1px solid var(--gold-line);
  border-radius: 2px;
  font-size: clamp(.92rem, 3.4vw, 1rem);
}
.welcome[hidden] { display: none; }
.welcome-team {
  font-family: var(--font-display);
  color: var(--navy);
  border-inline-start: 1px solid var(--gold-line);
  padding-inline-start: .55rem;
}

/* ---- 15. Scroll reveal -------------------------------------------------
   Scoped to .js on purpose. If JavaScript is blocked, broken or slow,
   nothing is hidden and the invitation still reads. An invitation must
   never depend on a script to be visible.
   ---------------------------------------------------------------------- */
.js .reveal { opacity: 0; transform: translateY(22px); }
.js .reveal.in { opacity: 1; transform: none; transition: opacity .9s ease, transform .9s cubic-bezier(.22,.61,.36,1); }
.js .reveal.d1.in { transition-delay: .1s; }
.js .reveal.d2.in { transition-delay: .2s; }
.js .reveal.d3.in { transition-delay: .3s; }

/* =========================================================================
   15b. THE MORPH — the envelope becomes the invitation
   نسيم & أمل is written small on the card inside the envelope, and large on
   the page. The View Transitions API carries the SAME element between the
   two, so the names grow out of the envelope instead of the page cutting to
   a new screen. Unsupported browsers get the plain fade; nothing breaks.
   ========================================================================= */
::view-transition-group(couple) {
  animation-duration: .85s;
  animation-timing-function: cubic-bezier(.22,.72,.16,1);
}
::view-transition-old(couple),
::view-transition-new(couple) { animation-duration: .85s; }

::view-transition-old(root) { animation: vt-fade-out .5s ease both; }
::view-transition-new(root) { animation: vt-fade-in  .6s ease both; }
@keyframes vt-fade-out { to   { opacity: 0; } }
@keyframes vt-fade-in  { from { opacity: 0; } }

/* =========================================================================
   15c. ILLUMINATED SCROLL
   CSS-only, driven by scroll position. Each KIND of element gets its own
   entrance — one identical fade repeated down the page is what makes a site
   feel templated. Everything here needs animation-timeline; where that is
   missing the JavaScript reveal in main.js still runs.
   ========================================================================= */
@supports (animation-timeline: view()) {

  /* the JS reveal stands down; CSS owns the entrances now */
  .js .reveal { opacity: 1; transform: none; transition: none; }

  @media (prefers-reduced-motion: no-preference) {

    /* Sections rise, with a little blur pulling them into focus.

       The end of the range is `entry`, not `cover`, and that matters.

       A `cover` range is measured over the element's whole pass across the
       screen — arriving at the bottom, crossing, leaving at the top. The LAST
       section on the page never gets to finish that pass: the document ends,
       scrolling stops, and the animation freezes wherever it happened to be.
       Measured on the live site, 31 Aug 2026: تأكيد الحضور sat permanently at
       70% — `opacity: .7`, `blur(0.9px)` — because the race, the guestbook and
       لحظات are all hidden until they have content, which left the RSVP as the
       last block on the page. The most important thing on the site was
       half-faded and slightly out of focus for every guest.

       An `entry` range is measured only over the element ARRIVING, so it
       completes as the element comes on screen and never depends on there
       being more page underneath. Same feel, one less thing to go wrong. */
    .reveal:not(.night) {
      animation: lift linear both;
      animation-timeline: view();
      animation-range: entry 2% entry 65%;
    }
    @keyframes lift {
      from { opacity: 0; transform: translateY(26px); filter: blur(3px); }
      to   { opacity: 1; transform: none;             filter: blur(0); }
    }

    /* the gold rules draw themselves outward from the centre ornament.
       `entry` end, for the same reason as .reveal above. */
    .rule::before, .rule::after {
      animation: ink linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 55%;
    }
    .rule::before { transform-origin: right center; }
    .rule::after  { transform-origin: left center; }
    @keyframes ink { from { transform: scaleX(0); } to { transform: scaleX(1); } }

    /* the diamond ornament. It was stuck at 23% above the RSVP — same cause. */
    .rule svg {
      animation: bloom linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 60%;
    }
    @keyframes bloom {
      from { opacity: 0; transform: scale(.45) rotate(-20deg); }
      to   { opacity: 1; transform: none; }
    }

    /* the verse lights up as it arrives */
    .verse {
      animation: illuminate linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 32%;
    }
    @keyframes illuminate {
      from { opacity: .3; color: var(--ink-faint); }
      to   { opacity: 1;  color: var(--ink); }
    }
    .verse-motif {
      animation: motif-in linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 28%;
    }
    @keyframes motif-in {
      from { opacity: 0; transform: translateY(12px) scale(.8); }
      to   { opacity: .8; transform: none; }
    }

    /* the jasmine drifts at its own rate — depth, not decoration */
    .botanical--tr { animation: drift-tr linear both; animation-timeline: scroll(); }
    .botanical--bl { animation: drift-bl linear both; animation-timeline: scroll(); }
    @keyframes drift-tr {
      from { transform: translateY(-3vh); }
      to   { transform: translateY(10vh); }
    }
    @keyframes drift-bl {
      from { transform: scale(-1) translateY(-7vh); }
      to   { transform: scale(-1) translateY(4vh); }
    }

    /* the gold thread traces itself down through the three nights */
    .timeline::before {
      transform-origin: top center;
      animation: thread linear both;
      animation-timeline: view();
      animation-range: entry 25% exit 25%;
    }
    @keyframes thread {
      from { transform: translateX(50%) scaleY(0); }
      to   { transform: translateX(50%) scaleY(1); }
    }

    /* each night settles into place; the wedding card takes a beat longer */
    .night {
      animation: night-in linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 30%;
    }
    @keyframes night-in {
      from { opacity: 0; transform: translateY(34px) scale(.965); }
      to   { opacity: 1; transform: none; }
    }
    .night--main { animation-range: entry 2% cover 38%; }

    /* each node lights up as the thread reaches it */
    .thread-node {
      animation: node-in linear both;
      animation-timeline: view();
      animation-range: entry 18% cover 30%;
    }
    @keyframes node-in {
      from { opacity: 0; transform: rotate(45deg) scale(.2); }
      to   { opacity: 1; transform: rotate(45deg) scale(1); }
    }

    .night-arch {
      animation: arch-in linear both;
      animation-timeline: view();
      animation-range: entry 8% cover 34%;
    }
    @keyframes arch-in {
      from { opacity: 0; transform: translate(-50%, -18%) scale(.78); }
      to   { opacity: 1; transform: translate(-50%, -48%) scale(1); }
    }
  }
}

/* ---- 16. Respect the user's settings ----------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .js .reveal, .js .reveal.in { opacity: 1; transform: none; }
}

/* ---- 17. Print --------------------------------------------------------- */
@media print {
  .frame, .torn, body::before { display: none; }
  body { background: #fff; }
  .btn { border: 1px solid #999; }
  .countdown { display: none; }
}
