/* ─────────────────────────────────────────────────────────────
   Dzhalil & Yasemin — wedding invitation
   Tokens → base → hero → sections → controls → motion → layouts → print
   ───────────────────────────────────────────────────────────── */

/* ── Fonts (self-hosted; unicode-range keeps each download to what the
      page actually uses — the hero needs three small files) ──────── */

/* cormorant italic cyrillic-ext */
@font-face { font-family: 'Cormorant Garamond'; font-style: italic; font-weight: 400; font-display: swap; src: url(fonts/cormorant-italic-cyrillic-ext.woff2) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; }
/* cormorant italic cyrillic */
@font-face { font-family: 'Cormorant Garamond'; font-style: italic; font-weight: 400; font-display: swap; src: url(fonts/cormorant-italic-cyrillic.woff2) format('woff2'); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
/* cormorant italic latin-ext */
@font-face { font-family: 'Cormorant Garamond'; font-style: italic; font-weight: 400; font-display: swap; src: url(fonts/cormorant-italic-latin-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
/* cormorant italic latin */
@font-face { font-family: 'Cormorant Garamond'; font-style: italic; font-weight: 400; font-display: swap; src: url(fonts/cormorant-italic-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
/* cormorant normal cyrillic-ext */
@font-face { font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/cormorant-cyrillic-ext.woff2) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; }
/* cormorant normal cyrillic */
@font-face { font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/cormorant-cyrillic.woff2) format('woff2'); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
/* cormorant normal latin-ext */
@font-face { font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/cormorant-latin-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
/* cormorant normal latin */
@font-face { font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/cormorant-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
/* manrope normal cyrillic-ext */
@font-face { font-family: 'Manrope'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/manrope-cyrillic-ext.woff2) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; }
/* manrope normal cyrillic */
@font-face { font-family: 'Manrope'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/manrope-cyrillic.woff2) format('woff2'); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
/* manrope normal latin-ext */
@font-face { font-family: 'Manrope'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/manrope-latin-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
/* manrope normal latin */
@font-face { font-family: 'Manrope'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/manrope-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
/* amiri normal text */
@font-face { font-family: 'Amiri'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/amiri-text.woff2) format('woff2'); unicode-range: U+fdfd; }
/* scheherazade normal text */
@font-face { font-family: 'Scheherazade New'; font-style: normal; font-weight: 400; font-display: swap; src: url(fonts/scheherazade-text.woff2) format('woff2'); unicode-range: U+20, U+623-624, U+627, U+62c, U+62e, U+632, U+642-646, U+648, U+64b, U+64e-64f, U+652, U+654; }

:root {
  color-scheme: light;

  /* Palette. --gold is for large display type only; --gold-text passes
     WCAG AA 4.5:1 on --paper and carries every small uppercase label. */
  --paper: #faf6ed;
  --ink: #574d40;
  --muted: #71675a;
  --gold: #967747;
  --gold-text: #856738;
  --gold-deep: #755a31;
  --gold-wash: #efe6d4;
  --hairline: #d6c7aa;
  --shadow-float:
    0 1px 2px rgb(87 77 64 / 0.06),
    0 18px 40px -16px rgb(87 77 64 / 0.28);

  --serif: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --sans: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
  --arabic-display: 'Amiri', 'Geeza Pro', 'Traditional Arabic', serif;
  --arabic-verse: 'Scheherazade New', 'Geeza Pro', serif;

  /* Space */
  --frame-inset: clamp(10px, 0.35rem + 0.8vw, 22px);
  --pad-x: clamp(24px, 0.5rem + 4.5vw, 104px);
  --rhythm: clamp(64px, 2.5rem + 5vw, 136px);

  /* Type */
  --text-body: clamp(1.25rem, 1.15rem + 0.42vw, 1.375rem);
  --text-copy: clamp(1.3125rem, 1.2rem + 0.48vw, 1.5rem);
  --text-greeting: clamp(2.5rem, 1.6rem + 3.4vw, 3.75rem);
  --text-detail: clamp(1.9rem, 1.6rem + 0.9vw, 2.125rem);
  --text-eyebrow: clamp(0.75rem, 0.69rem + 0.2vw, 0.875rem);
  --text-date: clamp(1.25rem, 1.05rem + 0.8vw, 1.75rem);
  --text-verse-ar: clamp(2.25rem, 1.95rem + 1.3vw, 2.875rem);
  --text-verse-ru: clamp(1.4375rem, 1.25rem + 0.8vw, 1.75rem);
  --text-verse-ref: clamp(1.1875rem, 1.05rem + 0.6vw, 1.4375rem);

  /* Motion. Critically damped curves only — nothing overshoots, the page
     settles like paper, it does not bounce. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-ink: cubic-bezier(0.65, 0, 0.35, 1);
  --fast: 180ms;
  --reveal: 1000ms;
  --rise: 18px;
  --reveal-group: 800ms;
  --rise-group: 12px;

  --radius: 4px;
}

/* ── Base ─────────────────────────────────────────────────── */

* { box-sizing: border-box }

html {
  background: var(--paper);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--text-body);
  line-height: 1.55;
  /* Cormorant defaults to old-style figures (4 dips, 6 rises); an invitation's
     dates read better set level, so every number uses lining figures. */
  font-variant-numeric: lining-nums;
  -webkit-font-smoothing: antialiased;
}

h1, h2 {
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

img { max-width: 100%; height: auto }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Sheet ────────────────────────────────────────────────── */

/* The paper is the whole window; the hairline frame keeps the stationery feel. */
.invitation {
  position: relative;
  isolation: isolate;
  min-height: 100dvh;
  padding:
    0
    max(var(--pad-x), env(safe-area-inset-right))
    max(var(--rhythm), env(safe-area-inset-bottom))
    max(var(--pad-x), env(safe-area-inset-left));
  background: var(--paper);
  overflow-x: clip;
}

.invitation::before {
  content: '';
  position: absolute;
  inset: var(--frame-inset);
  border: 1px solid var(--hairline);
  pointer-events: none;
  z-index: 2;
}

/* ── Hero: the front of the card, one screen tall ─────────── */

.hero {
  /* One set of numbers drives the whole card front. The lettering, the
     watercolour and the date share a single grid cell and are placed by
     fractions of the artwork, measured off the image itself:
       minaret tip  ≈ 5% of its height, x 77%
       dome finial  ≈ 24%
       clear ground between the flowers  ≈ 88–95%
     Every percentage here resolves against the same cell width, so the
     layers keep their relationship at any screen size. */
  --names-w: min(100% - 16px, 680px, 56svh, (100svh - 300px) * 0.85);
  --names-h: calc(var(--names-w) / 1.944);          /* lettering is 1394 × 717 */
  --art-w: min(100%, var(--names-w) * 1.8, 1260px);  /* minaret stands beside "Yasemin" */
  --art-h: calc(var(--art-w) / 1.5);                  /* watercolour is 1580 × 1054 */
  /* How deep into the art the lettering reaches, as a share of its height.
     0.225 stops the "Y" loop ~10px above the dome's crescent (at 24.4%). */
  --tuck: 0.225;
  /* Slides the lettering left just enough that the tail of "Yasemin"
     (98.4% across the lockup) clears the minaret (75.7% across the art)
     by 14px. Capped so it stays an optical nudge, never an off-centre. */
  --nudge: clamp(0px, var(--names-w) * 0.484 + 14px - var(--art-w) * 0.257, 40px);
  --foot: 0.885;   /* where the date begins: the ground between the flowers */
  --gap: clamp(10px, 2svh, 28px);
  --drop: max(0px, var(--names-h) - var(--art-h) * var(--tuck));

  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: 'mast' 'scene';
  align-content: center;
  justify-items: center;
  padding-block: calc(var(--frame-inset) + 44px) calc(var(--frame-inset) + 64px);
  text-align: center;
}

.hero > .masthead { grid-area: mast }

.hero > #couple,
.hero > .art,
.hero > .names-wrap {
  grid-area: scene;
  align-self: start;
}

.masthead {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.bismillah {
  margin: 0;
  padding: 0 0.1em;
  max-width: 100%;
  font-family: var(--arabic-display);
  font-size: min(clamp(1.35rem, 0.5rem + 4.2vw, 2rem), 4.2svh);
  line-height: 1.9;
  color: var(--gold);
}

.masthead-caption {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(10px, 3vw, 22px);
  max-width: 100%;
}

.rule {
  flex: 0 0 auto;
  width: clamp(22px, 7vw, 64px);
  height: 1px;
  background: var(--hairline);
}

.eyebrow,
.masthead-caption p {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--text-eyebrow);
  letter-spacing: 0.17em;
  line-height: 1.75;
  text-transform: uppercase;
  color: var(--gold-text);
}

/* Name lockup: sized against the viewport height as well as the width,
   so it never outgrows the card front on a short laptop screen.
   It sits above the mosque, which rises up behind it. */
#couple {
  position: relative;
  z-index: 2;
  width: var(--names-w);
  margin: var(--gap) 0 0;
  /* left, not translate: its percentages resolve against the column like
     every other size in the scene; translate's would use the box itself. */
  left: calc(var(--nudge) * -1);
  line-height: 0;
  overflow: clip;
}

#couple img {
  display: block;
  width: 100%;
}

.art {
  position: relative;
  z-index: 1;
  width: var(--art-w);
  margin-top: calc(var(--gap) + var(--drop));
  /* No blend mode here: the artwork's own paper is baked to exactly
     #faf6ed in the JPEG (4:4:4, so chroma is not smeared), which keeps the
     entrance on the compositor instead of re-blending every frame. */
}

.art img {
  display: block;
  width: 100%;
  /* Fades the artwork's own paper into ours on all four sides. */
  mask-image:
    linear-gradient(to bottom, transparent, #000 10%, #000 80%, transparent),
    linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-composite: intersect;
  -webkit-mask-image:
    linear-gradient(to bottom, transparent, #000 10%, #000 80%, transparent),
    linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-composite: source-in;
}

.names-wrap {
  position: relative;
  z-index: 3;
  margin-top: calc(var(--gap) + var(--drop) + var(--art-h) * var(--foot));
}

.names-wrap .eyebrow {
  margin-top: clamp(6px, 1.2svh, 14px);
  text-indent: 0.17em;
}

.wedding-date {
  margin: 0;
  font-family: var(--serif);
  font-size: var(--text-date);
  line-height: 1.2;
  color: var(--gold-text);
}

.wedding-date time {
  display: flex;
  align-items: center;
  justify-content: center;
  column-gap: 0.5em;
}

.wedding-date time > span {
  letter-spacing: 0.14em;
  text-indent: 0.14em;
}

.date-divider {
  flex: 0 0 1px;
  height: 1.05em;
  background: currentColor;
  opacity: 0.7;
}

/* A hairline that tells guests the card continues below. */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: calc(var(--frame-inset) + 18px);
  width: 1px;
  height: 40px;
  background: var(--hairline);
  overflow: hidden;
  translate: -50% 0;
}

.scroll-cue::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, transparent, var(--gold) 45%, transparent);
  transform: translateY(-100%);
}

/* ── Ornament ─────────────────────────────────────────────── */

/* Rub el hizb star between two hairlines — the one Islamic geometric note,
   reused as the section mark so the page reads as one system. */
.ornament {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: 0 0 clamp(22px, 3vw, 34px);
  color: var(--gold);
}

.ornament svg {
  width: 13px;
  height: 13px;
  fill: currentColor;
}

/* ── Message ──────────────────────────────────────────────── */

.message {
  max-width: 760px;
  /* Pull the greeting into one third of the hero's trailing space without resizing its artwork. */
  margin: calc((var(--frame-inset) + 64px) / -3) auto calc(var(--rhythm) * .8);
  padding-top: clamp(4px, .75vw, 12px);
  text-align: center;
}

.message h2 {
  text-wrap: balance;
  margin: 0 0 clamp(20px, 3vw, 30px);
  font-size: var(--text-greeting);
}

.message p {
  max-width: 38ch;
  margin: 0 auto 0.9em;
  font-size: var(--text-copy);
  line-height: 1.55;
  text-wrap: pretty;
}

/* ── Details ──────────────────────────────────────────────── */

.details {
  display: grid;
  grid-template-columns: 1fr 1px 1fr;
  align-items: start;
  gap: clamp(20px, 3vw, 40px);
  max-width: 880px;
  margin: 0 auto;
  padding: clamp(28px, 4vw, 44px) 0;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  text-align: center;
}

.detail {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.detail h2 {
  margin: 12px 0 10px;
  font-size: var(--text-detail);
}



.venue-subtitle {
  font-size: 0.625em;
  letter-spacing: 0;
}

.detail-copy {
  margin: 0;
  font-family: var(--sans);
  font-size: clamp(0.875rem, 0.82rem + 0.18vw, 1rem);
  font-style: normal;
  line-height: 1.7;
  color: var(--muted);
}

.detail-divider {
  align-self: stretch;
  background: var(--hairline);
}

/* ── Verse ────────────────────────────────────────────────── */

.verse {
  margin-top: clamp(40px, 5vw, 72px);
  text-align: center;
}

.verse p { margin: 0 }

.verse-arabic {
  font-family: var(--arabic-verse);
  font-size: var(--text-verse-ar);
  line-height: 2;
  color: var(--gold);
}

.verse-translation {
  margin: 4px 0 10px;
  font-size: var(--text-verse-ru);
  line-height: 1.4;
}

.verse-reference {
  font-size: var(--text-verse-ref);
  font-style: italic;
  line-height: 1.2;
}

/* ── Buttons ──────────────────────────────────────────────── */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  max-width: 100%;
  min-height: 44px;
  margin-top: 20px;
  padding: 11px 20px;
  border: 1px solid var(--gold);
  border-radius: var(--radius);
  background: transparent;
  color: var(--gold-deep);
  font: 400 0.875rem/1.5 var(--sans);
  letter-spacing: 0.02em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--fast) var(--ease-out),
    color var(--fast) var(--ease-out),
    transform 100ms var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}

/* Feedback lands on the press, not the release. */
.button:active { transform: scale(0.97) }

.button:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: 4px;
}

/* ── Floating panel (language) ────────────────────────────── */

.language { -webkit-tap-highlight-color: transparent }
.language summary { list-style: none }
.language summary::-webkit-details-marker { display: none }

.panel {
  margin: 0;
  padding: 6px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--paper);
  box-shadow: var(--shadow-float);
  list-style: none;
  text-align: left;
  z-index: 5;
}

/* Grows out of the button that opened it, and settles without overshoot. */
@media (prefers-reduced-motion: no-preference) {
  details[open] > .panel {
    transition: opacity 220ms var(--ease-out), transform 260ms var(--ease-out);

    @starting-style {
      opacity: 0;
      transform: translateY(-6px) scale(0.96);
    }
  }
}

.panel a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--gold-deep);
  font: 400 0.875rem/1.4 var(--sans);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--fast) var(--ease-out), color var(--fast) var(--ease-out);
}

.panel a:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: -2px;
}

/* Language switch — a small stationery mark in the corner of the card. */
.language {
  position: absolute;
  top: calc(var(--frame-inset) + 12px);
  right: calc(var(--frame-inset) + 12px);
  z-index: 4;
}

.language summary {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 34px;
  padding: 6px 12px 6px 10px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: rgb(250 246 237 / 0.86);
  color: var(--gold-text);
  font: 400 0.6875rem/1 var(--sans);
  letter-spacing: 0.16em;
  cursor: pointer;
  transition:
    border-color var(--fast) var(--ease-out),
    background-color var(--fast) var(--ease-out),
    transform 100ms var(--ease-out);
}

/* Keeps the mark small but the tap area a full 44px. */
.language summary::before {
  content: '';
  position: absolute;
  inset: -5px -4px;
}

.language summary::after {
  content: '';
  width: 5px;
  height: 5px;
  margin-left: 1px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 260ms var(--ease-out);
}

.language summary:active { transform: scale(0.96) }

.language[open] summary {
  border-color: var(--gold);
  background: var(--gold-wash);
  color: var(--gold-deep);
}

.language[open] summary::after { transform: translateY(1px) rotate(-135deg) }

.language summary:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: 3px;
}

.language-icon {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
}

.language-options {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 196px;
  transform-origin: 100% 0;
}

.language-code {
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  color: var(--muted);
}

.language-options a[aria-current='page'] {
  background: var(--gold-wash);
  color: var(--ink);
}

/* On the wash, muted grey drops under 4.5:1 — deepen the code with it. */
.language-options a[aria-current='page'] .language-code { color: var(--gold-deep) }

.language-options a[aria-current='page'] .language-code::before {
  content: '';
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--gold);
  vertical-align: 1px;
}

@media (hover: hover) {
  .button:hover { background: var(--gold-wash); color: #57452a }
  .panel a:hover { background: var(--gold-wash) }
  .panel a:hover .language-code { color: var(--gold-deep) }
  .language summary:hover { border-color: var(--gold) }
}

/* ── Motion ───────────────────────────────────────────────── */

/* Hidden states exist only when JS is present to undo them and the guest
   has not asked for less motion — otherwise everything is simply there. */
@media (prefers-reduced-motion: no-preference) {
  .js [data-reveal] {
    opacity: 0;
    transform: translate3d(0, var(--rise), 0);
    transition:
      opacity var(--reveal) var(--ease-out) var(--delay, 0ms),
      transform var(--reveal) var(--ease-out) var(--delay, 0ms);
  }

  /* Fade each text section as a single stable surface, without moving lines. */
  .js [data-reveal-group] {
    opacity: 0;
    transition: opacity 500ms ease-out;
  }

  .js [data-reveal-group].is-visible { opacity: 1 }

  /* The names are written in, left to right, like ink off a pen.
     A counter-slide, not clip-path: the frame slides in from the left
     while the lettering slides the opposite way inside it, so the ink
     stays put and only the clip edge travels. Both are transforms, so the
     SVG is rasterised once and the GPU does the rest — clip-path made
     phones re-render the whole vector path on every frame. */
  .js [data-reveal='ink'] {
    opacity: 1;
    transform: translate3d(-100%, 0, 0);
    transition: transform 1900ms var(--ease-ink) var(--delay, 0ms);
  }

  .js [data-reveal='ink'] > img {
    transform: translate3d(100%, 0, 0);
    transition: transform 1900ms var(--ease-ink) var(--delay, 0ms);
  }

  /* The mosque rises into place from below. */
  .js [data-reveal='art'] {
    transform: translate3d(0, 28px, 0);
    transition:
      opacity 1300ms var(--ease-out) var(--delay, 0ms),
      transform 1800ms var(--ease-out) var(--delay, 0ms);
  }

  .js .hero .masthead { --delay: 0ms }
  .js .hero #couple { --delay: 250ms }
  .js .hero .art { --delay: 650ms }
  .js .hero .names-wrap { --delay: 1100ms }

  .js .hero.is-ready [data-reveal] {
    opacity: 1;
    transform: none;
  }

  .js .hero.is-ready [data-reveal='ink'] > img { transform: none }

  .js .scroll-cue {
    opacity: 0;
    transition: opacity 800ms var(--ease-out) 2000ms;
  }

  .js .hero.is-ready .scroll-cue { opacity: 1 }

  .js .hero.is-ready .scroll-cue::after {
    animation: cue 2400ms var(--ease-ink) 2400ms 3 both;
  }

  @keyframes cue {
    from { transform: translateY(-100%) }
    to { transform: translateY(100%) }
  }

  /* Failsafe: if app.js never runs (blocked, slow network, old in-app
     browser), show everything anyway instead of leaving a blank page.
     5s is past the slowest normal reveal (2.5s timeout + 2.45s motion). */
  .js [data-reveal],
  .js [data-reveal] > img,
  .js [data-reveal-group] {
    animation: reveal-failsafe 0s 5s forwards;
  }

  @keyframes reveal-failsafe {
    to { opacity: 1; transform: none }
  }
}

/* ── Layouts ──────────────────────────────────────────────── */

/* Phones: stack the two detail columns, let the art reach the frame. */
@media (max-width: 650px) {
  /* Phones: the art bleeds to the frame, so it cannot be 1.8× the names;
     sit the lettering higher so only the "Y" loop meets the dome. */
  .hero {
    --art-w: calc(100% + var(--pad-x) * 2 - var(--frame-inset) * 2 - 8px);
    --tuck: 0.17;
    --nudge: 0px;
    /* The date's digits sit between the two flower sprays, just below the
       mosque steps (value chosen by eye on an iPhone 16 Pro Max). */
    --foot: 0.87;
    padding-top: calc(var(--frame-inset) + 56px);
    /* Let the content set the height instead of leaving a full-screen gap. */
    min-height: 0;
    padding-bottom: 24px;
  }

  .message { margin-top: 0; padding-top: 0 }
  .message p { max-width: 22em }
  .desktop-break { display: none }

  .details {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 24px;
  }

  .detail-divider { align-self: center; width: 42px; height: 1px }
}

/* Tablets held upright: the art is capped by the width, so hold the
   lettering back too — otherwise the names outweigh the mosque. */
@media (min-width: 651px) and (orientation: portrait) {
  .hero {
    --names-w: min(100% - 16px, 560px, 56svh);
    --tuck: 0.17;
    --nudge: 0px;
  }
}

/* Phones on their side: very little height, so tighten the front. */
@media (orientation: landscape) and (max-height: 520px) {
  .hero { padding-block: calc(var(--frame-inset) + 44px) calc(var(--frame-inset) + 24px) }
  .bismillah { line-height: 1.6 }
  .hero { --names-w: min(100% - 40px, 60svh) }
  .scroll-cue { display: none }
}

@media (prefers-contrast: more) {
  :root {
    --gold: var(--gold-deep);
    --gold-text: var(--gold-deep);
    --muted: var(--ink);
    --hairline: #a89372;
  }
}

/* ── Print ────────────────────────────────────────────────── */

@media print {
  .hero { min-height: 0; padding-block: 24px }

  [data-reveal],
  [data-reveal] > img,
  [data-reveal-group] > * {
    opacity: 1 !important;
    transform: none !important;
  }

  .message,
  .details,
  .verse { break-inside: avoid }

  .button,
  .language,
  .scroll-cue { display: none }

  /* Buttons are gone on paper, so the address has to carry the venue. */
  .detail-copy { color: var(--ink) }
}
