/* ---------- Tokens (from Figma) ---------- */
:root {
  /* Full-screen height: capped at the mock's 852px only when the page is shown as a phone-sized
     column on a wide screen; on an actual phone it is the whole screen. */
  --full-h: clamp(640px, 100svh, 852px);
  --page: #eeeae3;
  --paper: #efebe4;
  --cream: #e2d9c8;
  --green: #28514a;
  --ink: #173c35;
  --ink-soft: #243c32;
  --sage: #8c967b;
  --gold: #ccb598;
  --field: #ede7df;
  --field-line: #bdc4b7;
  --muted: #69776c;

  --font-script: "Allura", "Snell Roundhand", cursive;
  --font-serif: "Abhaya Libre", Georgia, "Times New Roman", serif;

  /* Every section in the mock is one 393×852 phone screen; positions below are in those pixels. */
  --screen-w: 393px;
  --screen-h: 852px;
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }
html.is-locked { overflow: hidden; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-serif);
  -webkit-font-smoothing: antialiased;
}

h1, h2, p { margin: 0; font-weight: 400; }
img { display: block; max-width: 100%; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }

.app {
  position: relative;
  max-width: var(--screen-w);
  margin: 0 auto;
  overflow-x: clip;
}

.screen {
  position: relative;
  min-height: var(--screen-h);
  overflow: hidden;
  isolation: isolate;
}

/* Envelope and cover fill the phone screen instead of the fixed mock height. */
.screen--full {
  min-height: 0;
  height: var(--full-h);
}

/* On a phone the page fills the screen edge to edge instead of the 393px column of the mock. */
@media (max-width: 600px) {
  :root { --full-h: max(640px, 100svh); }
  .app { max-width: none; }
}

/* A few blocks lift into place the first time they are scrolled to, so the flat screens aren't
   dead still. `translate` rather than `transform`, because most of these are centred with
   translateX(-50%) and the two properties compose instead of overwriting each other. Nothing is
   hidden unless main.js has said it will bring them back. */
.is-animated .rise { opacity: 0; translate: 0 16px; }
.is-animated .rise.is-in {
  opacity: 1;
  translate: none;
  transition: opacity 0.7s ease var(--in, 0s), translate 0.7s cubic-bezier(0.22, 0.61, 0.36, 1) var(--in, 0s);
}

/* ---------- Type ---------- */
.t-script { font-family: var(--font-script); font-size: 56px; line-height: 60px; letter-spacing: -0.02em; }
.t-time   { font-size: 36px; line-height: 36px; letter-spacing: -0.02em; }
.t-lead   { font-size: 24px; line-height: 28px; letter-spacing: -0.01em; }
.t-body   { font-size: 20px; line-height: 24px; letter-spacing: -0.01em; }
.t-small  { font-size: 16px; line-height: 20px; letter-spacing: -0.01em; }

/* ---------- Shared pieces ---------- */

/* Full-height background that bleeds past the column like the 479px-wide art in the mock. */
.bg {
  position: absolute;
  z-index: -2;
  top: 0;
  left: 50%;
  height: 100%;
  aspect-ratio: 479.5 / 852;
  min-width: 100%;
  max-width: none;
  transform: translateX(calc(-50% + var(--dx, 0px)));
  object-fit: cover;
  pointer-events: none;
}

.shade {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.36) 0%, rgba(0, 0, 0, 0.67) 60.1%, rgba(0, 0, 0, 0.72) 100%);
}

.glass {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  border: 1px solid var(--gold);
  border-radius: 60px;
  background: rgba(255, 255, 255, 0.08);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  color: #fff;
  text-align: center;
}

.heading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  color: var(--ink);
  text-align: center;
  white-space: nowrap;
}

.ornament { width: 72px; height: 36px; object-fit: cover; }
.ornament--flip { transform: scaleY(-1); }
.divider { width: 72px; height: 4px; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px;
  border-radius: 8px;
  background: var(--sage);
  color: #fff;
  font-size: 20px;
  line-height: 20px;
  letter-spacing: -0.01em;
  text-decoration: none;
  white-space: nowrap;
}
.btn img { width: 20px; height: 20px; }
.btn--dark { width: 100%; background: var(--green); }

/* Frosted strip that melts illustrations into the cream background. */
.fade {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(180deg, rgba(226, 217, 200, 0), var(--cream));
}

/* ---------- Header ---------- */
.topbar {
  position: fixed;
  z-index: 10;
  top: 0;
  left: 50%;
  width: 100%;
  max-width: var(--screen-w);
  height: calc(72px + env(safe-area-inset-top));
  padding: calc(14px + env(safe-area-inset-top)) 24px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: rgba(0, 0, 0, 0.1);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: #fff;
  transform: translate(-50%, 0);
  transition: transform 0.35s ease, background-color 0.35s ease, color 0.35s ease;
}
.topbar.is-hidden { transform: translate(-50%, -100%); }
/* Edge to edge on a phone, like the page (declared after .topbar so it wins). */
@media (max-width: 600px) {
  .topbar { max-width: none; }
}
.topbar__title { font-size: 20px; line-height: 24px; letter-spacing: -0.01em; }

.sound {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  transition: border-color 0.35s ease;
}
.sound img { transition: filter 0.35s ease; }

.sound[aria-pressed="false"] img { opacity: 0.45; }

/* Over the cream screens white type disappears, so the bar flips to ink. */
.topbar.is-light { background: rgba(226, 217, 200, 0.6); color: var(--ink); }
.topbar.is-light .sound { border-color: rgba(23, 60, 53, 0.2); }
.topbar.is-light .sound img { filter: brightness(0) opacity(0.8); }

@media (prefers-reduced-motion: reduce) {
  .scroll-hint img { animation: none; }
  .topbar, .sound, .sound img { transition: none; }
}

/* ---------- 1. Envelope ---------- */
/* Sits on top of the cover until it has opened and slid away. */
.envelope {
  position: absolute;
  z-index: 5;
  top: 0;
  left: 0;
  right: 0;
  container-type: size;
}

/* Until the paper and the wax have loaded, the envelope is a plain sheet: the flaps are cut apart
   at the crack, so showing them early would let the cover glare through the gap. */
.envelope.is-loading { background: var(--paper); }
.envelope.is-loading .envelope__stage,
.envelope.is-loading .envelope__open { visibility: hidden; }

/* Darkens the cover while the envelope lies over it; lifts as the envelope slides away. */
.envelope__shade {
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 80% at 50% 45%, rgba(20, 16, 10, 0.15), rgba(20, 16, 10, 0.55));
}

/* The paper photo's own 479.5×852 box, covering the screen whatever its proportions,
   so the crease percentages in main.js always land on the creases. */
.envelope__stage {
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100cqw, 100cqh * 479.5 / 852);
  height: max(100cqh, 100cqw * 852 / 479.5);
  transform: translate(-50%, -50%);
  transform-style: preserve-3d;
  perspective: 1600px;
  perspective-origin: 50% 45%;
}

/* The glued body slides away as one piece; the top flap is a chain of paper strips built by
   main.js, each hinged on the one before it, so the sheet bends instead of turning like a board. */
.envelope__body,
.flap,
.band {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  pointer-events: none;
}
.envelope__body,
.band { will-change: transform; }

/* One side of a strip, sized to the strip so its GPU layer stays small. */
.face {
  position: absolute;
  overflow: hidden;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.face img { position: absolute; max-width: none; }
/* Shading runs smoothly across each strip, from the tone of the fold before it to the fold after,
   so a bent sheet reads as one curved surface instead of stepped slats. */
.face::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(var(--shade-dir, to bottom), rgba(22, 14, 4, var(--shade-from, 0)), rgba(22, 14, 4, var(--shade-to, 0)));
  pointer-events: none;
}
/* The inside of the envelope: unprinted paper with a little fibre in it. */
.face--back {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.42 0 0 0 0 0.37 0 0 0 0 0.3 0 0 0 0.12 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
    linear-gradient(165deg, #f3ede3, #e0d6c5);
}

/* A soft shadow from the envelope onto the invitation as it slides away. Only while sliding: a filter
   flattens the body's 3D layers, which would put it over the top flap while that is still in view. */
.envelope.is-sliding .envelope__body { filter: drop-shadow(0 -4px 14px rgba(20, 14, 6, 0.3)); }

/* Wax seal in two halves along one crack: the upper rides the top flap, the lower stays. */
.seal-half {
  position: absolute;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.seal-half img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
}

/* The crack: a dark hairline with a faint lit lip, masked by the wax so it never runs onto paper. */
.seal-crack {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  -webkit-mask: url("../assets/img/envelope-seal.png") center / 100% 100% no-repeat;
  mask: url("../assets/img/envelope-seal.png") center / 100% 100% no-repeat;
}
.seal-crack path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.seal-crack__lip { stroke: rgba(255, 236, 190, 0.35); stroke-width: 0.6px; transform: translateY(-0.6px); }
.seal-crack__core { stroke: rgba(6, 20, 15, 0.95); stroke-width: 0.8px; }

/* Wax crumbs fly in screen space, above the paper. */
.envelope__fx {
  position: absolute;
  z-index: 2;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.chip {
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 45% 55% 60% 40%;
  background: radial-gradient(circle at 35% 30%, #4c8a72, #123f33 65%, #0a2a22);
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.35);
}

.envelope__open {
  position: absolute;
  z-index: 1;
  inset: 0;
  width: 100%;
}
.envelope.is-opening .envelope__open { pointer-events: none; }
.envelope__hint {
  position: absolute;
  top: calc(50% + 108px);
  left: 50%;
  transform: translateX(-50%);
  color: var(--ink-soft);
  white-space: nowrap;
}

/* ---------- 2–3. Cover → welcome ---------- */
/* The track is the pinned screen plus the scroll the clip plays over: --clip carries it from its
   first frame to its last, one to one, and --hold keeps that last frame up for a swipe or two while
   "Dear guest" is read. Keep JOURNEY_* in main.js in step. */
.journey {
  --stage-h: var(--full-h);
  --clip: 285svh;
  --hold: 95svh;
  position: relative;
  height: calc(var(--stage-h) + var(--clip) + var(--hold));
  background: #2e2f27;
}
.journey__stage {
  position: sticky;
  top: 0;
  height: var(--stage-h);
  overflow: hidden;
  isolation: isolate;
  display: grid;
  place-items: center;
}
.journey__stage > .glass { grid-area: 1 / 1; }
/* Frames and clip share one box, so the clip starts and ends exactly on them. */
.journey__frame,
.journey__video { aspect-ratio: 1152 / 2048; }
/* Stand-in for the last frame, only while the clip can't be shown. */
.journey__frame--last { opacity: 0; }
/* Anchor for "Scroll down": where the clip has finished and "Dear guest" is up. */
.journey__end {
  position: absolute;
  left: 0;
  top: calc(var(--clip) + 20svh);
  height: var(--stage-h);
  pointer-events: none;
}

.cover__card { padding: 24px 60px; }
.cover__group { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.cover__names { color: var(--cream); line-height: 50px; }

.scroll-hint {
  position: absolute;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
}
.scroll-hint img { width: 52px; height: 32px; animation: nudge 2.6s ease-in-out infinite; }
@keyframes nudge {
  0%, 62%, 100% { transform: translateY(0); }
  31% { transform: translateY(5px); }
}

.welcome__card { width: 266px; padding: 24px; opacity: 0; }
.welcome__title { color: var(--cream); line-height: 50px; white-space: nowrap; }

/* ---------- 4. Wedding date ---------- */
/* The date screen plus the scroll it holds still for, so there is time to notice the heart and rub
   it away before the page moves on. Nothing here is scrubbed — the track is pure dwell. */
.date-track {
  --hold: 150svh;
  /* At least the mock's height, and the whole screen on a taller phone so the cream covers it all. */
  --date-h: max(var(--screen-h), var(--full-h));
  position: relative;
  height: calc(var(--date-h) + var(--hold));
  background: var(--cream);
}
/* Pinned; on a screen shorter than the mock it pins with its bottom edge in view, since the date,
   the heart and the button all sit in the lower half. */
.date {
  position: sticky;
  top: min(0px, 100svh - var(--date-h));
  height: var(--date-h);
  background: var(--cream);
}

.date__frame,
.date__confetti {
  position: absolute;
  top: 0;
  left: 50%;
  height: 852px;
  max-width: none;
  transform: translateX(-50%);
}
.date__frame { width: 426px; object-fit: cover; }
.date__confetti { width: 479.505px; }

.date__hint {
  position: absolute;
  top: 700px;
  left: 50%;
  transform: translateX(-50%);
  color: var(--ink-soft);
  text-align: center;
  white-space: nowrap;
}
.date__heading {
  position: absolute;
  top: 160px;
  left: 50%;
  transform: translateX(-50%);
}

.date__heart,
.date__outline {
  position: absolute;
  left: 50%;
  overflow: hidden;
  transform: translateX(-50%);
}
.date__heart img,
.date__outline img {
  position: absolute;
  top: 0;
  height: 100%;
  max-width: none;
}
.date__heart { top: 346px; width: 252px; height: 252px; }
.date__heart img { left: -3.63%; width: 107.27%; }
.date__outline { top: 362px; width: 253px; height: 238px; pointer-events: none; }
.date__outline img { left: -6.06%; width: 112.12%; }

.date__when {
  position: absolute;
  top: 433.5px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  color: var(--ink);
  text-align: center;
  white-space: nowrap;
}
.date__when .t-lead { font-weight: 700; }

.date__calendar {
  position: absolute;
  top: 659px;
  left: 50%;
  transform: translateX(-50%);
}

.date__scratch {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: pointer;
}
.date__heart.is-ready img { visibility: hidden; }

.date__burst {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Untouched → scratching → revealed, following frames 675:444 → 675:638 → 675:660. */
.date__frame,
.date__hint { transition: opacity 0.6s ease; }
.date.is-scratching .date__frame { opacity: 0.5; }
.date.is-scratching .date__hint { opacity: 0.35; }
.date.is-revealed .date__frame,
.date.is-revealed .date__hint { opacity: 0; }
.date.is-revealed .date__heart { visibility: hidden; }

.date__confetti,
.date__when,
.date__calendar { opacity: 0; visibility: hidden; }
.date.is-revealed .date__when,
.date.is-revealed .date__calendar { opacity: 1; visibility: visible; transition: opacity 0.8s ease 0.2s; }
/* The static confetti settles in as the popper's pieces fall away. */
.date.is-revealed .date__confetti { opacity: 0.7; visibility: visible; transition: opacity 1.6s ease 0.8s; }

@media (prefers-reduced-motion: reduce) {
  .date__frame, .date__hint, .date__when, .date__calendar, .date__confetti { transition: none !important; }
}

/* ---------- 5. Program ---------- */
/* The programme screen plus the scroll the veil parts over, then the scroll its lines come in on.
   Keep PROGRAM_VEIL and PROGRAM_REVEAL in main.js in step. */
.program-track {
  --veil: 150svh;
  --reveal: 130svh;
  /* At least the mock's height, and the whole screen on a taller phone so the veil covers it all. */
  --program-h: max(var(--screen-h), var(--full-h));
  position: relative;
  height: calc(var(--program-h) + var(--veil) + var(--reveal));
  background: var(--green);
}
/* Pinned; on a screen shorter than the programme it pins with its bottom edge in view. */
.program {
  position: sticky;
  top: min(0px, 100svh - var(--program-h));
  height: var(--program-h);
  background: var(--green);
  color: var(--cream);
}
.program__veil {
  position: absolute;
  z-index: 2;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  mix-blend-mode: screen;
  pointer-events: none;
}
.program__title {
  position: absolute;
  top: 80px;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
}
.program__vine {
  position: absolute;
  top: 200px;
  left: 50%;
  width: 121px;
  height: 600px;
  max-width: none;
  object-fit: cover;
  transform: translateX(-50%) scaleX(-1);
}

.program__dot {
  position: absolute;
  top: var(--y);
  left: 50%;
  width: 15px;
  height: 15px;
  margin-left: -7.5px;
  overflow: hidden;
}
.program__dot img {
  position: absolute;
  left: -50.16%;
  top: -49.92%;
  width: 200.32%;
  height: 199.83%;
  max-width: none;
}

.program__list { margin: 0; padding: 0; list-style: none; }
.program__item {
  position: absolute;
  top: var(--y);
  width: 104px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.program__item .divider { margin-top: 12px; }
.program__item--left { left: 40px; }
.program__item--right { right: 40px; align-items: flex-end; text-align: right; }
.program__item--wide { width: 121px; }

/* ---------- 6. Location ---------- */
.location { background: var(--cream); }
.location__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  padding-top: 80px;
  color: var(--ink);
  text-align: center;
}
.location__hall {
  position: absolute;
  top: 320px;
  left: 50%;
  width: 360px;
  height: 240px;
  max-width: none;
  object-fit: cover;
  transform: translateX(-50%);
}
.location__fade {
  top: 520.4px;
  -webkit-backdrop-filter: blur(5.05px);
  backdrop-filter: blur(5.05px);
}
.location__cta {
  position: absolute;
  top: 592px;
  left: 50%;
  transform: translateX(-50%);
}
.location__ornament {
  position: absolute;
  top: 760px;
  left: 50%;
  width: 104px;
  height: 52px;
  object-fit: cover;
  transform: translateX(-50%) scaleY(-1);
}

/* ---------- 7. Dress code ---------- */
.dress { background: var(--cream); }

.dress__body {
  position: relative;
  width: 278px;
  margin: 0 auto;
  padding-top: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  text-align: center;
}
.dress__text { display: flex; flex-direction: column; gap: 20px; color: var(--ink); }
.dress__code { color: var(--ink-soft); letter-spacing: -0.02em; text-transform: uppercase; }
/* The SVG carries the swatch shadows, so it is larger than the 208×40 row. */
.dress__palette { width: 228px; height: 60px; max-width: none; margin: -6px -10px -14px; }

/* Both columns are crops of one arch image. */
.dress__column {
  position: absolute;
  top: 0;
  height: 852px;
  overflow: hidden;
  opacity: 0.4;
}
.dress__column img { position: absolute; top: 0; height: 101.26%; max-width: none; }
.dress__column--left { left: -62px; width: 144px; }
.dress__column--left img { left: 6.65%; width: 341.86%; }
.dress__column--right { right: -59px; width: 140px; }
.dress__column--right img { left: -271.26%; width: 368.85%; }

.dress__fade {
  top: 740.4px;
  -webkit-backdrop-filter: blur(2.5px);
  backdrop-filter: blur(2.5px);
}

.dress__guests {
  position: absolute;
  top: 560px;
  left: calc(50% + 7px);
  width: 317px;
  height: 250px;
  overflow: hidden;
  transform: translateX(-50%);
}
.dress__guests img {
  position: absolute;
  top: -3.42%;
  left: -19.07%;
  width: 123.73%;
  height: 105.03%;
  max-width: none;
}

/* ---------- 8. RSVP ---------- */
.rsvp {
  padding: 80px 32px 48px;
  background: var(--green);
}
.rsvp__head {
  width: 278px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 20px;
  color: var(--cream);
  text-align: center;
}
.rsvp__title { line-height: 50px; }

.rsvp__card {
  position: relative;
  isolation: isolate;
  max-width: 329px;
  margin: 36px auto 0;
  padding: 64px 28px 28px;
  border-radius: 28px;
  overflow: hidden;
  background: var(--paper);
}
.rsvp__paper {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
}
.rsvp__paper img {
  position: absolute;
  top: 0;
  left: -9.04%;
  width: 118.09%;
  height: 103.95%;
  max-width: none;
}
.rsvp__form { display: flex; flex-direction: column; gap: 20px; }

.field { display: flex; flex-direction: column; gap: 12px; }
.field__label { color: var(--ink-soft); }

.input {
  width: 100%;
  padding: 8px 16px;
  border: 1px solid var(--field-line);
  border-radius: 80px;
  background: var(--field);
  color: var(--ink-soft);
  font: 400 16px/20px var(--font-serif);
  letter-spacing: -0.01em;
}
.input::placeholder { color: var(--muted); }
.input--area { height: 90px; border-radius: 12px; resize: none; }
.input:focus-visible { outline: 2px solid var(--green); outline-offset: 1px; }

.choice {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px;
  border: 1px solid var(--field-line);
  border-radius: 80px;
  background: var(--field);
  color: var(--ink-soft);
  cursor: pointer;
}
.choice input {
  appearance: none;
  display: grid;
  place-items: center;
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 1px solid var(--ink-soft);
  border-radius: 50%;
}
.choice input:checked::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--green);
}
.choice:has(input:focus-visible) { outline: 2px solid var(--green); outline-offset: 2px; }

/* ---------- 9. Closing ---------- */
.closing {
  display: grid;
  place-items: center;
  background: var(--green);
  color: #fff;
  text-align: center;
}
.closing__media {
  position: absolute;
  z-index: -1;
  top: 0;
  left: 50%;
  width: 479px;
  height: 852px;
  overflow: hidden;
  transform: translateX(-50%);
}
.closing__media img {
  position: absolute;
  top: 0;
  left: -7.75%;
  width: 118.58%;
  height: 100%;
  max-width: none;
}
.closing__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--green) 0%, rgba(21, 41, 38, 0.3) 30.22%, rgba(21, 41, 38, 0.3) 100%);
}
.closing__text { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.closing__names { color: var(--cream); white-space: nowrap; }
.closing__note { width: 210px; }

.footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 72px;
  padding: 14px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: rgba(0, 0, 0, 0.1);
}
.to-top {
  position: relative;
  display: block;
  width: 40px;
  height: 40px;
  overflow: hidden;
}
.to-top img {
  position: absolute;
  left: -30.58%;
  top: -19.74%;
  width: 161.16%;
  height: 139.48%;
  max-width: none;
}

/*
 * No scroll bar, on any computer. The invitation is read as a phone reads
 * it, and a phone draws no bar - but Windows draws a grey gutter with a white
 * track down the side of the page, and in the constructor's phone that
 * gutter sat inside the screen. Scrolling itself is untouched.
 */
html,
body,
* {
  scrollbar-width: none;
}

html::-webkit-scrollbar,
body::-webkit-scrollbar,
*::-webkit-scrollbar {
  display: none;
}

/* "Design by Invitated" in words, the studio's name the link. */
.footer__brand {
  margin: 0;
  font: 400 16px/1.2 var(--font-serif);
  color: var(--cream);
}

.footer__brand a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
