/* ------------------------------------------------------------------
   Youcef & Fatima — invitation card
   Art in assets/img is generated by scripts/build-assets.py.
   ------------------------------------------------------------------ */

@font-face {
  font-family: 'Thmanyah Serif';
  src: url('../fonts/thmanyahserifdisplay-Light.woff2') format('woff2');
  font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Thmanyah Serif';
  src: url('../fonts/thmanyahserifdisplay-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Thmanyah Serif';
  src: url('../fonts/thmanyahserifdisplay-Medium.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Thmanyah Serif';
  src: url('../fonts/thmanyahserifdisplay-Bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Great Vibes';
  src: url('../fonts/GreatVibes-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}

:root {
  /* The card keeps the artwork's 9:16 proportion on a roomy screen and simply
     grows taller than it on a phone — the frame bands are anchored, not stretched. */
  --stage-h: min(100dvh, 940px);
  --stage-w: min(100vw, calc(var(--stage-h) * 0.5625));

  /* Band heights follow from the generated crops: 652/1080 and 692/1080 of the width.
     `safe` is the part that is fully opaque, i.e. where text must never go. */
  --band-top: calc(var(--stage-w) * 0.6037);
  --band-bottom: calc(var(--stage-w) * 0.6407);
  --safe-top: calc(var(--stage-w) * 0.4000);
  --safe-bottom: calc(var(--stage-w) * 0.4370);

  --ink: #6f5439;
  --ink-soft: #8a6b4e;
  --script: #9c6d4e;
  --gold: #c9a97c;
  --rule: #dcc6aa;

  /* The layout unit. Normally a hundredth of the card's width, but a card that is
     short for its width would push the longest panel through the bottom ornaments,
     so the height the frame leaves free caps it. */
  --avail: calc(var(--stage-h) - var(--safe-top) - var(--safe-bottom));
  --u: min(calc(var(--stage-w) / 100), calc(var(--avail) / 125));

  /* The measure. Everything a guest reads sits in this one column, so a card turned
     sideways gets a narrow centred block of text rather than a full-width sprawl. */
  --col: calc(78 * var(--u));
  --ease: cubic-bezier(.22, .61, .36, 1);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 90% at 50% 0%, #4a3a2c 0%, #2a211a 55%, #1c1611 100%);
  font-family: 'Thmanyah Serif', 'Times New Roman', serif;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.stage {
  position: relative;
  width: var(--stage-w);
  height: var(--stage-h);
  overflow: hidden;
  isolation: isolate;
  perspective: 1500px;
  perspective-origin: 50% 42%;
}

@media (min-width: 620px) and (min-height: 640px) {
  .stage {
    border-radius: 10px;
    box-shadow:
      0 2px 6px rgba(0, 0, 0, .35),
      0 30px 70px -20px rgba(0, 0, 0, .65),
      0 0 0 1px rgba(255, 244, 228, .07);
  }
}

/* ---- the silk field the ornaments dissolve into --------------------------- */

.field {
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    /* the artwork darkens very slightly towards the outer edges */
    radial-gradient(115% 78% at 50% 50%, rgba(0, 0, 0, 0) 62%, rgba(150, 116, 78, .10) 100%),
    linear-gradient(to bottom, #f3ebe0 0%, #f3e9de 45%, #f3e8dc 72%, #f2e7da 100%);
}

/* ---- the ornamented edges, above the text -------------------------------- */

.frame {
  position: absolute;
  left: 0;
  width: 100%;
  z-index: 3;
  pointer-events: none;
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
.frame--top {
  top: 0;
  height: var(--band-top);
  background-image: url('../img/frame-top.png');
}
.frame--bottom {
  bottom: 0;
  height: var(--band-bottom);
  background-image: url('../img/frame-bottom.png');
}
.frame--ring { display: none; }

/* ---- the scrolling body -------------------------------------------------- */

.viewport {
  position: absolute;
  outline: none;
  inset: 0;
  z-index: 2;
  /* Scrolling is driven from JS, one panel per gesture — `hidden` takes the
     native scroller (and its momentum) out of the way while leaving scrollTop
     settable, which is what the pager animates. */
  overflow-y: hidden;
  overflow-x: hidden;
  overscroll-behavior: contain;
  touch-action: none;
  scrollbar-width: none;

  /* Text dissolves before it can reach the ornaments. The stops are the same
     measurements the bands were cut at, so the two always agree. */
  --veil: linear-gradient(to bottom,
      transparent 0,
      transparent var(--safe-top),
      #000 calc(var(--safe-top) + 7 * var(--u)),
      #000 calc(100% - var(--safe-bottom) - 7 * var(--u)),
      transparent calc(100% - var(--safe-bottom)),
      transparent 100%);
  -webkit-mask-image: var(--veil);
  mask-image: var(--veil);
}
.viewport::-webkit-scrollbar { width: 0; height: 0; }

.panel {
  /* An explicit length, not a percentage: the scroller's own height is auto,
     so `100%` would resolve against nothing and collapse the panel. */
  min-height: var(--stage-h);
  padding: calc(var(--safe-top) + 3 * var(--u)) calc(11 * var(--u))
           calc(var(--safe-bottom) + 3 * var(--u));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--u));
  text-align: center;
}
.panel > * { max-width: var(--col); }

/* ---- the invitee, named on the envelope and again in the letter ----------- */

.addressee {
  position: absolute;
  left: 0;
  right: 0;
  top: 15%;
  z-index: 11;
  margin: 0;
  display: grid;
  justify-items: center;
  gap: calc(1.6 * var(--u));
  text-align: center;
  padding-inline: calc(10 * var(--u));
  transition: opacity .5s ease;
}
.addressee-for {
  font-size: calc(2.9 * var(--u));
  letter-spacing: .34em;
  text-indent: .34em;
  text-transform: uppercase;
  color: var(--ink-soft);
  opacity: .7;
}
.addressee-name {
  font-size: calc(5.4 * var(--u));
  font-weight: 500;
  line-height: 1.3;
  color: var(--ink);
  text-wrap: balance;
}
[lang='ar'] .addressee-for { letter-spacing: .1em; text-indent: .1em; }
.is-open .addressee { opacity: 0; transition-duration: .4s; }

.greeting {
  margin: 0;
  font-family: 'Great Vibes', 'Thmanyah Serif', cursive;
  font-size: calc(8.4 * var(--u));
  line-height: 1.25;
  color: var(--script);
  text-wrap: balance;
}
[lang='ar'] .greeting {
  font-family: 'Thmanyah Serif', serif;
  font-size: calc(6.4 * var(--u));
  font-weight: 500;
}

/* ---- type ---------------------------------------------------------------- */

.overline {
  margin: 0;
  font-size: calc(3.4 * var(--u));
  font-weight: 400;
  letter-spacing: .42em;
  text-indent: .42em;
  text-transform: uppercase;
  color: var(--ink-soft);
  opacity: .8;
}

.names {
  margin: 0;
  font-family: 'Great Vibes', 'Thmanyah Serif', cursive;
  font-weight: 400;
  font-size: calc(16 * var(--u));
  line-height: 1.06;
  color: var(--script);
  display: grid;
  justify-items: center;
}
.names .amp {
  font-size: .62em;
  line-height: .9;
  color: var(--gold);
  margin-block: calc(-1.5 * var(--u));
}
[lang='ar'] .names {
  font-family: 'Thmanyah Serif', serif;
  font-size: calc(11 * var(--u));
  font-weight: 500;
  line-height: 1.35;
}
[lang='ar'] .names .amp { font-size: .74em; margin-block: 0; }

.invite {
  margin: 0;
  font-size: calc(5.1 * var(--u));
  font-weight: 500;
  line-height: 1.75;
  max-width: calc(66 * var(--u));
  text-wrap: balance;
}
[lang='ar'] .invite { font-weight: 400; line-height: 1.95; font-size: calc(5.3 * var(--u)); }

.title {
  margin: 0;
  font-size: calc(8.2 * var(--u));
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: .01em;
}
[lang='ar'] .title { font-weight: 500; }

.divider {
  display: block;
  width: calc(52 * var(--u));
  max-width: 100%;
  height: auto;
  opacity: .95;
}
.divider--under { width: calc(46 * var(--u)); margin-top: calc(-1.5 * var(--u)); }

/* ---- date & countdown ---------------------------------------------------- */

.wreath {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  width: 100%;
}
.wreath--wide {
  background-image: url('../img/wreath-wide.png');
  padding: calc(6 * var(--u)) calc(20 * var(--u));
  min-height: calc(48 * var(--u));
}
.wreath--tall {
  background-image: url('../img/wreath-tall.png');
  padding: calc(5 * var(--u)) calc(22 * var(--u));
  min-height: calc(33 * var(--u));
}

.panel--count { gap: calc(2 * var(--u)); }
.panel--count .title { font-size: calc(7 * var(--u)); }
.panel--count .numeral { font-size: calc(15.5 * var(--u)); }

.numeral {
  margin: 0;
  font-size: calc(19 * var(--u));
  font-weight: 400;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--ink);
}
.wreath--wide .numeral { margin-bottom: calc(2 * var(--u)); }

.date-line {
  margin: 0;
  font-size: calc(6 * var(--u));
  font-weight: 400;
  line-height: 1.55;
}
.date-line--time { font-variant-numeric: lining-nums tabular-nums; }

.unit {
  display: block;
  margin: 0;
  font-size: calc(3.5 * var(--u));
  font-weight: 500;
  letter-spacing: .3em;
  text-indent: .3em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
[lang='ar'] .unit { letter-spacing: .12em; text-indent: .12em; }
.wreath--tall .unit { margin-top: calc(1.5 * var(--u)); font-size: calc(4.2 * var(--u)); }

.clock {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: calc(2 * var(--u));
  width: 100%;
  direction: ltr;             /* a clock reads left-to-right in Arabic too */
}
.clock-cell {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(1.2 * var(--u));
}
.clock-num {
  font-size: calc(8.2 * var(--u));
  font-weight: 400;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
}
.clock-sep {
  font-size: calc(7 * var(--u));
  line-height: 1.2;
  color: var(--ink-soft);
  opacity: .6;
}

.closing {
  margin: 0;
  width: 100%;
  display: grid;
  justify-items: center;
  gap: calc(1.6 * var(--u));
}
.closing-orn { display: block; width: calc(50 * var(--u)); max-width: 100%; height: auto; }
.closing figcaption {
  font-size: calc(4.1 * var(--u));
  text-wrap: balance;
  font-weight: 500;
  line-height: 1.5;
  max-width: 30ch;
}

/* ---- direction ----------------------------------------------------------- */

/* The address line pushed this panel to its limit in Arabic, where it wraps to two
   lines — the compass gives back the room. */
.panel--direction { gap: calc(2.4 * var(--u)); }

.compass {
  display: block;
  width: calc(32 * var(--u));
  height: auto;
}

.venue {
  margin: 0;
  display: grid;
  gap: calc(1.2 * var(--u));
}
.venue-name { font-size: calc(5.6 * var(--u)); font-weight: 500; line-height: 1.4; }
.venue-sub {
  font-size: calc(4.9 * var(--u));
  font-weight: 400;
  line-height: 1.6;
  color: var(--ink-soft);
}
.venue-address {
  font-size: calc(4.1 * var(--u));
  font-weight: 400;
  line-height: 1.55;
  color: var(--ink-soft);
  opacity: .85;
  text-wrap: balance;
}

.maps {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(78 * var(--u));
  max-width: 100%;
  text-decoration: none;
  color: var(--ink);
  transition: transform .35s var(--ease), filter .35s var(--ease);
}
.maps img { display: block; width: 100%; height: auto; grid-area: 1 / 1; }
.maps span {
  grid-area: 1 / 1;
  font-size: calc(4.2 * var(--u));
  font-weight: 500;
  letter-spacing: .13em;
  text-indent: .13em;
  text-transform: uppercase;
  padding-bottom: calc(.4 * var(--u));
}
[lang='ar'] .maps span { letter-spacing: 0; text-indent: 0; font-size: calc(5 * var(--u)); }
.maps:hover, .maps:focus-visible {
  transform: translateY(-2px);
  filter: drop-shadow(0 6px 12px rgba(120, 90, 60, .22));
}
.maps:active { transform: translateY(0); }

/* ---- language row -------------------------------------------------------- */

.langs {
  display: flex;
  align-items: center;
  gap: calc(2.2 * var(--u));
  font-size: calc(3.4 * var(--u));
  color: var(--ink-soft);
  opacity: .72;
}
.langs a {
  color: inherit;
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease), color .3s var(--ease);
}
.langs a:hover { border-bottom-color: var(--rule); }
.langs a[aria-current='true'] { color: var(--ink); border-bottom-color: var(--gold); }

/* ---- scroll hint --------------------------------------------------------- */

.scroll-hint {
  position: absolute;
  left: 50%;
  bottom: calc(var(--safe-bottom) * .34);
  transform: translateX(-50%);
  z-index: 4;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(1.2 * var(--u));
  font-size: calc(3.1 * var(--u));
  letter-spacing: .32em;
  text-indent: .32em;
  text-transform: uppercase;
  color: var(--ink-soft);
  pointer-events: none;
  opacity: 0;
  transition: opacity .8s var(--ease);
}
.scroll-hint svg { animation: nudge 2.4s var(--ease) infinite; }
.is-open .scroll-hint { opacity: .62; transition-delay: 1.5s; }
.is-open.has-scrolled .scroll-hint { opacity: 0; transition-delay: 0s; }
[lang='ar'] .scroll-hint { letter-spacing: .1em; text-indent: .1em; }

@keyframes nudge {
  0%, 100% { transform: translateY(0); opacity: .55; }
  50%      { transform: translateY(4px); opacity: 1; }
}

/* ---- the sealed cover ---------------------------------------------------- */

.cover {
  position: absolute;
  inset: 0;
  z-index: 10;
  transform-style: preserve-3d;
}

.door {
  position: absolute;
  top: 0;
  width: 50%;
  height: 100%;
  backface-visibility: hidden;
  background-image: url('../img/cover.png');
  background-size: 200% 100%;
  background-repeat: no-repeat;
  transition: transform 2.1s cubic-bezier(.7, 0, .25, 1);
  will-change: transform;
}
.door--l { left: 0;  transform-origin: left center;  background-position: left center; }
.door--r { right: 0; transform-origin: right center; background-position: right center; }

/* The inner edge catches the light as the panel swings out. */
.door-shade {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 2.1s cubic-bezier(.7, 0, .25, 1);
}
.door--l .door-shade { background: linear-gradient(to left,  rgba(58, 40, 24, .55), rgba(58, 40, 24, 0) 62%); }
.door--r .door-shade { background: linear-gradient(to right, rgba(58, 40, 24, .55), rgba(58, 40, 24, 0) 62%); }

.is-open .door--l { transform: rotateY(-108deg); }
.is-open .door--r { transform: rotateY(108deg); }
.is-open .door-shade { opacity: 1; }

.seal {
  position: absolute;
  inset: 0;
  display: grid;
  justify-items: center;
  align-content: center;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--ink-soft);
  transition: transform 1s cubic-bezier(.34, 1.4, .5, 1), opacity .7s ease;
}
.seal img {
  display: block;
  width: calc(29 * var(--u));
  height: auto;
  filter: drop-shadow(0 calc(1.2 * var(--u)) calc(2 * var(--u)) rgba(120, 88, 52, .34));
  animation: breathe 4.5s ease-in-out infinite;
}
.seal-label {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 17%;
  font-size: calc(3.1 * var(--u));
  letter-spacing: .3em;
  text-indent: .3em;
  text-transform: uppercase;
  opacity: .78;
  animation: fade-up 1.4s var(--ease) .6s backwards;
}
[lang='ar'] .seal-label { letter-spacing: .08em; text-indent: .08em; }
.seal:focus-visible { outline: 1px solid var(--gold); outline-offset: calc(3 * var(--u)); border-radius: 4px; }

.is-open .seal {
  transform: scale(1.5);
  opacity: 0;
  transition-duration: .75s;
  pointer-events: none;
}

@keyframes breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.035); }
}
@keyframes fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: .78; transform: none; }
}

/* Once the doors are out of the way, stop compositing them. */
.cover.is-gone { display: none; }

/* ---- reveal on scroll ---------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(calc(3.4 * var(--u)));
  transition:
    opacity .95s var(--ease) calc(var(--i, 0) * 110ms),
    transform .95s var(--ease) calc(var(--i, 0) * 110ms);
}
.panel.is-seen .reveal { opacity: 1; transform: none; }

/* ---- reduced motion ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .viewport { scroll-behavior: auto; scroll-snap-type: none; }
  .seal img, .scroll-hint svg { animation: none; }
  .seal-label { animation: none; opacity: .78; }
  .door { transition: opacity .6s linear; }
  .is-open .door { transform: none; opacity: 0; }
  .reveal { transition-duration: .01ms; transition-delay: 0ms; opacity: 1; transform: none; }
}


/* ------------------------------------------------------------------
   Turned sideways — the landscape cut of the same artwork.

   Its ornaments sit in the four corners rather than in bands, so the card
   locks to the 1376x768 proportion of the art and the covering layer is the
   whole picture with a soft elliptical hole punched where the text lives.
   ------------------------------------------------------------------ */

@media (min-aspect-ratio: 1/1) {
  :root {
    --stage-w: min(100vw, 1440px, calc(100dvh * 1.79167));
    --stage-h: calc(var(--stage-w) / 1.79167);

    /* Measured off the artwork: the corner ornaments leave the middle clear
       from 28% down, and the bottom pair only closes in below 92%. */
    --safe-top: calc(var(--stage-h) * 0.28);
    --safe-bottom: calc(var(--stage-h) * 0.08);
  }

  .field {
    background: url('../img/frame-pc.jpg') center / 100% 100% no-repeat;
  }

  .frame--top,
  .frame--bottom { display: none; }

  .frame--ring {
    display: block;
    top: 0;
    height: 100%;
    background-image: url('../img/frame-pc.jpg');
    /* Opaque everywhere the ornaments are, dissolving to nothing over the text.
       Same picture, same size as the layer beneath, so the edge is invisible. */
    --hole: radial-gradient(ellipse 30% 42% at 50% 60%,
        transparent 0, transparent 58%, #000 100%);
    -webkit-mask-image: var(--hole);
    mask-image: var(--hole);
  }

  .door { background-image: url('../img/cover-pc.jpg'); }

  /* Text is a narrow column here, so it is only ever the top and bottom that
     need veiling — the ring takes care of the corners. */
  .viewport {
    --veil: linear-gradient(to bottom,
        transparent 0,
        transparent calc(var(--safe-top) - 4 * var(--u)),
        #000 calc(var(--safe-top) + 4 * var(--u)),
        #000 calc(100% - var(--safe-bottom) - 4 * var(--u)),
        transparent calc(100% - var(--safe-bottom) + 2 * var(--u)),
        transparent 100%);
  }

  .panel {
    padding: calc(var(--safe-top) + 2 * var(--u)) calc(11 * var(--u))
             calc(var(--safe-bottom) + 2 * var(--u));
  }

  .stage {
    border-radius: 10px;
    box-shadow:
      0 2px 6px rgba(0, 0, 0, .35),
      0 30px 70px -20px rgba(0, 0, 0, .65),
      0 0 0 1px rgba(255, 244, 228, .07);
  }
}
