/* ------------------------------------------------------------------
   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;
}

/* The Arabic faces. Amiri is a classical Naskh for reading; Noto Nastaliq Urdu, a flowing
   Nastaliq hand, carries the couple's names and the guest's greeting — the
   Arabic answer to Great Vibes on the Latin side. Aref Ruqaa stays declared but
   unused elsewhere on the page. All are only ever named inside an [lang='ar']
   rule, and the unicode-range confines them to Arabic, so a French or English
   guest never downloads a byte of any of them — a browser fetches a face only
   when it has to draw a glyph with it. Nothing here may be preloaded, or that
   promise breaks. */
@font-face {
  font-family: 'Amiri';
  src: url('../fonts/amiri-arabic-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: 'Amiri';
  src: url('../fonts/amiri-arabic-700-normal.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: 'Noto Nastaliq Urdu';
  src: url('../fonts/NotoNastaliqUrdu-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: 'Aref Ruqaa';
  src: url('../fonts/aref-ruqaa-arabic-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: 'Aref Ruqaa';
  src: url('../fonts/aref-ruqaa-arabic-700-normal.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

: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 {
  /* Nastaliq's strokes fall diagonally rather than sitting on a level baseline,
     so it wants a slightly larger size and a taller line than a Ruqaa hand did
     to keep its descenders clear of the text above and below it. */
  font-family: 'Noto Nastaliq Urdu', 'Great Vibes', 'Amiri', serif;
  font-size: calc(7.2 * var(--u));
  font-weight: 400;
  line-height: 2.05;
}

/* ---- 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;
}
/* Latin tracking pulls Arabic words apart; the script carries its own rhythm. */
[lang='ar'] .overline { letter-spacing: .1em; text-indent: .1em; }

.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));
}
/* Amiri sets smaller on the body than Thmanyah does, so the Arabic sizes step up
   a little across the board to hold the same presence on the page. */
[lang='ar'] body { font-family: 'Amiri', 'Thmanyah Serif', serif; }

/* Digits are the same glyphs in every language; they stay on the Latin face so
   the big numerals look identical whichever link a guest opened. */
[lang='ar'] .numeral,
[lang='ar'] .clock-num,
[lang='ar'] .date-line--time { font-family: 'Thmanyah Serif', serif; }

[lang='ar'] .names {
  /* Noto Nastaliq Urdu is Google's own Nastaliq — the flowing hand that sits on
     the names the way Great Vibes sits on the Latin ones. Its diagonal descent
     and tall loops need more line-height than a Ruqaa hand asks for. */
  font-family: 'Noto Nastaliq Urdu', 'Great Vibes', 'Amiri', serif;
  font-size: calc(16 * var(--u));
  font-weight: 400;
  line-height: 1.9;
}
[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: 2; font-size: calc(5.6 * 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: 700; font-size: calc(8 * var(--u)); }

.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)); }

/* A note the guest has to act on, so it is enclosed and labelled rather than
   whispered: a card of slightly deeper stock than the page, a hairline around
   it, and a gold label above the line. Quiet enough for the stationery, loud
   enough that the eye stops on it. */
.note {
  display: grid;
  justify-items: center;
  gap: calc(1.4 * var(--u));
  margin: calc(1 * var(--u)) 0 0;
  padding: calc(3.4 * var(--u)) calc(5 * var(--u));
  max-width: calc(66 * var(--u));
  border: 1px solid color-mix(in srgb, var(--rule) 78%, transparent);
  border-radius: calc(1.2 * var(--u));
  background: color-mix(in srgb, #fff 34%, transparent);
  box-shadow: 0 1px 0 rgba(255, 252, 245, .8) inset;
}

.note__label {
  font-size: calc(2.9 * var(--u));
  font-weight: 500;
  letter-spacing: .3em;
  text-indent: .3em;
  text-transform: uppercase;
  color: var(--gold);
}

.note__text {
  font-size: calc(3.9 * var(--u));
  font-weight: 500;
  line-height: 1.65;
  color: var(--ink);
  text-wrap: balance;
}

[lang='ar'] .note__label { letter-spacing: .1em; text-indent: .1em; font-size: calc(3.2 * var(--u)); }
[lang='ar'] .note__text { font-size: calc(4.3 * var(--u)); line-height: 1.9; }

/* The invitation remains warm and uninterrupted; the practical postscript sits
   quietly beneath the closing line on the final panel. */
.panel--invite { gap: calc(2.4 * var(--u)); }

.note--closing {
  /* This panel already carries a wreath, a clock and a closing figure, so the
     postscript has to earn its place in very little height: half the padding
     of the invitation's version, no internal gap between label and text, and
     a tighter line — still bordered and labelled, just compact about it. */
  gap: calc(.3 * var(--u));
  margin: 0;
  padding: calc(.7 * var(--u)) calc(4 * var(--u));
  border-color: color-mix(in srgb, var(--rule) 45%, transparent);
  background: color-mix(in srgb, #fff 18%, transparent);
  box-shadow: none;
}
.note--closing .note__label { font-size: calc(2.3 * var(--u)); }
.note--closing .note__text { font-size: calc(3.1 * var(--u)); line-height: 1.35; }
[lang='ar'] .note--closing .note__text { font-size: calc(3.5 * var(--u)); line-height: 1.55; }

/* ---- 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(4 * var(--u)) calc(22 * var(--u));
  min-height: calc(30 * var(--u));
}

.panel--count { gap: calc(1.5 * var(--u)); }
.panel--count .title { font-size: calc(7 * var(--u)); }
.panel--count .numeral { font-size: calc(14 * var(--u)); }
.panel--count .clock-num { font-size: calc(7.4 * 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 * var(--u));
}
.closing-orn { display: block; width: calc(36 * var(--u)); max-width: 100%; height: auto; }
.closing figcaption {
  font-size: calc(3.7 * 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 {
  /* Spanning the card rather than sitting at left:50% — an absolutely positioned
     box offset from the left can only ever be as wide as what is left of the
     card, which was wrapping the longer translations in half. */
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--safe-bottom) * .34);
  padding-inline: calc(6 * var(--u));
  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);
  }
}
