/* ============================================================================
   Golden Journey — आयुष और निकिता (the Hindi edition of template-3)
   ----------------------------------------------------------------------------
   The same design, set in Hindi. It started from template-3-guj, which had
   already reworked template-3's typography for an Indic script, so the
   notes below that say "Gujarati" in that file say "Devanagari" here. Three
   things had to move for the script rather than for taste, and each is
   marked below where it occurs:

   - Display sizes change. The English page sets its titles and names in
     Great Vibes and Mussica Swash, scripts that carry very little ink per em,
     so a 4rem Great Vibes title is visually about 2.7rem of Eczar bold. Each
     display rule is set to the size that fills the same space as on the
     English page.
   - Line heights go up and letter-spacing comes down. Devanagari hangs
     matras above and below the shirorekha, which a line-height under 1.3
     clips, and the wide tracking that suits Cinzel's capitals only pulls a
     Devanagari word into loose syllables — and breaks the headline the
     letters hang from. Tracked labels keep roughly a third of their English
     value. text-transform: uppercase is left in place — it does nothing to
     Devanagari.
   - Italics go. Neither font draws a Devanagari italic, and a slanted
     Devanagari word reads as a mistake rather than an accent, so the italic
     accents are set upright at a heavier weight instead.

   Two families stand in for the five Latin faces — see the note above the
   font tokens below and assets/fonts/fonts.css.

   ----------------------------------------------------------------------------
   One stylesheet for the whole page, in the order the sections appear:

     1.  Tokens and resets
     2.  Shared pieces        cards, section titles, reveal-on-scroll
     3.  Preloader
     4.  Hero
     5.  Music player
     6.  Invitation
     7.  Scratch card
     8.  Countdown
     9.  Our story
     10. Wedding events
     11. The journey          Ahmedabad to Udaipur
     12. With blessings from
     12a. बाल मनुहार          the children's plea to come
     13. RSVP
     14. Footer

   Sizes follow the original design's own breakpoints rather than scaling
   smoothly, because several of them deliberately go the other way: the tap
   logo, the aeroplane and the revealed date are all *larger* on a phone than
   on a desktop. Each block keeps its media queries at its foot.
   ========================================================================== */


/* ==========================================================================
   1. Tokens and resets
   ========================================================================== */

:root {
  --maroon:      #6e1f2f;
  --gold:        #c9a227;
  --gold-soft:   #e8c978;
  --gold-deep:   #b38728;
  --cream:       #faf5eb;
  --ink:         #2f2f2f;
  --ink-soft:    #6b6b6b;

  --rule-gold:   1px solid rgba(201, 162, 39, .3);
  --shadow:      0 10px 30px rgba(0, 0, 0, .05);
  --shadow-card: 0 10px 40px rgba(0, 0, 0, .05);

  /* The five roles are kept as five tokens so every rule below still says
     what it is for. Eczar, a festive display serif, carries the four display
     roles and Martel, open and tall in the x-height, carries the text; the
     display roles are told apart from each other by weight and size. Martel
     backs Eczar up, since the display rules carry the dates and a fallback
     without ०-९ would show boxes. See assets/fonts/fonts.css. */
  --font-heading: "Eczar", "Martel", ui-serif, Georgia, serif;
  --font-body:    "Martel", ui-serif, Georgia, serif;
  --font-names:   "Eczar", "Martel", ui-serif, Georgia, serif;
  --font-title:   "Eczar", "Martel", ui-serif, Georgia, serif;
  --font-script:  "Eczar", "Martel", ui-serif, Georgia, serif;
}

*, *::before, *::after { box-sizing: border-box; }

body, h1, h2, h3, h4, p, figure, blockquote { margin: 0; padding: 0; }

html, body {
  width: 100%;
  min-height: 100vh;
  overflow-x: hidden;
  -webkit-tap-highlight-color: transparent;
}

body {
  font-family: var(--font-body);
  line-height: 1.6;
  color: var(--ink);
  background: var(--cream) linear-gradient(135deg, #faf5eb 0%, #f5efe0 100%) fixed;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Held still while the preloader is up and the opening film is running, so the
   page cannot be scrolled past a cover that is still covering it.

   This has to name the root element as well as the body. The viewport takes
   its scrolling from <html>, and only falls back to <body> when <html> is
   `overflow: visible` — which it is not here, because of the `overflow-x:
   hidden` above. On <body> alone this rule does nothing at all. */
html.is-locked,
body.is-locked { overflow: hidden; }

/* Devanagari matras and conjuncts need more room than a heading's default line
   box gives them; anything with its own line-height below overrides this. */
h1, h2, h3, h4 {
  font-family: var(--font-heading);
  color: var(--maroon);
  font-weight: 500;
  line-height: 1.35;
}

img, video { max-width: 100%; display: block; }

input, button, textarea { font: inherit; }


/* ==========================================================================
   2. Shared pieces
   ========================================================================== */

/* Every section below the hero sits on the page gradient and breathes the
   same amount. */
.section {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(4rem, 10vw, 8rem) 1.5rem;
}

/* The large title over most sections. Great Vibes at 4rem on the English
   page; Eczar bold fills the same width at about two thirds of that. */
.section__title {
  font-family: var(--font-title);
  font-size: 2.7rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--maroon);
  text-align: center;
  margin-bottom: 3rem;
}

@media (max-width: 768px) {
  .section__title { font-size: 2.1rem; }
}

/* White card with a gold hairline and a second rule inset inside it — the
   motif the invitation, the family card and the RSVP box all share. */
.card {
  position: relative;
  width: 100%;
  background: #fff;
  border: var(--rule-gold);
  border-radius: 12px;
  box-shadow: var(--shadow);
  text-align: center;
}

.card::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: 1px solid rgba(201, 162, 39, .2);
  border-radius: 8px;
  pointer-events: none;
}

/* Reveal on scroll. assets/js/reveal.js adds .is-in when the element first
   scrolls into view; an inline transition-delay staggers a group. */
[data-reveal] {
  opacity: 0;
  transform: translateY(40px);
  filter: blur(8px);
  transition: opacity .9s ease, transform .9s ease, filter .9s ease;
}

[data-reveal="fade"]  { transform: none; }
[data-reveal="left"]  { transform: translateX(-50px); filter: none; }
[data-reveal="zoom"]  { transform: scale(.95); filter: none; }

[data-reveal].is-in {
  opacity: 1;
  transform: none;
  filter: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; filter: none; transition: none; }
}


/* ==========================================================================
   3. Preloader
   Covers everything until the hero video has a frame to show.
   ========================================================================== */

.preloader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: linear-gradient(135deg, #fdfbf7 0%, #f4eee0 100%);
  transition: opacity .6s ease-out, visibility .6s ease-out;
}

.preloader.is-done { opacity: 0; visibility: hidden; }

.preloader__logo {
  width: 100px;
  height: 100px;
  margin-bottom: 2rem;
  object-fit: contain;
  filter: drop-shadow(0 4px 15px rgba(212, 175, 55, .3));
  animation: float 4s ease-in-out infinite;
}

.preloader__text {
  font-family: var(--font-heading);
  font-size: clamp(1.05rem, 4vw, 1.5rem);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  text-align: center;
  padding: 0 1rem;
  color: var(--gold-deep);
  margin-bottom: 3rem;
  animation: pulse-text 2.5s ease-in-out infinite;
}

/* A 50px highlight sliding along a 150px track. */
.preloader__bar {
  position: relative;
  width: 150px;
  height: 2px;
  border-radius: 2px;
  background: rgba(183, 140, 59, .2);
  overflow: hidden;
}

.preloader__bar::after {
  content: "";
  position: absolute;
  top: 0;
  left: -50px;
  width: 50px;
  height: 100%;
  background: linear-gradient(90deg, transparent, var(--gold-deep), transparent);
  animation: shimmer 2s cubic-bezier(.65, 0, .35, 1) infinite;
}

/* Gold motes drifting up the screen. Each one's position, size and timing are
   randomised in assets/js/effects.js. */
.motes {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.motes__item {
  position: absolute;
  border-radius: 50%;
  opacity: 0;
  background: radial-gradient(circle, rgba(212, 175, 55, .8) 0%, rgba(212, 175, 55, 0) 70%);
  animation: mote-rise linear infinite;
}

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

@keyframes pulse-text {
  0%, 100% { opacity: .6; text-shadow: 0 0 5px rgba(183, 140, 59, .2); }
  50%      { opacity: 1;  text-shadow: 0 0 15px rgba(183, 140, 59, .6); }
}

@keyframes shimmer {
  0%   { left: -50px; }
  100% { left: 100%; }
}

@keyframes mote-rise {
  0%        { opacity: 0; transform: translateY(100vh) scale(.5); }
  20%, 80%  { opacity: .6; }
  100%      { opacity: 0; transform: translateY(-10vh) scale(1.5); }
}


/* ==========================================================================
   4. Hero
   A looping film behind the couple's names. Until it is tapped, a dark
   overlay holds the "Tap to Begin" prompt.
   ========================================================================== */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  overflow: hidden;
  background: ivory;
}

.hero__video,
.hero__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__video  { z-index: 1; }

/* The still sits over the video until the video has a frame of its own, so
   the first paint is never a black box. */
.hero__poster {
  z-index: 2;
  pointer-events: none;
  transition: opacity 1s ease-in-out;
}

.hero__poster.is-hidden { opacity: 0; }

.hero__cover {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, .6);
  cursor: pointer;
  transition: opacity 1s ease-out;
}

.hero__cover.is-open { opacity: 0; pointer-events: none; }

.hero__tap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}

.hero__tap-text {
  font-family: var(--font-heading);
  font-size: clamp(1.15rem, 4vw, 1.5rem);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  text-align: center;
  padding: 0 1rem;
  color: var(--cream);
  text-shadow: 0 4px 12px rgba(0, 0, 0, .5);
  animation: breathe 2.8s ease-in-out infinite;
}

/* Deliberately larger on a phone, where it is the whole invitation to open
   and the only thing worth tapping. */
.hero__tap-logo {
  width: 70px;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, .4));
  animation: breathe 2.8s ease-in-out infinite;
}

@media (max-width: 768px) {
  .hero__tap { margin: 2rem 0; }
  .hero__tap-logo { width: 140px; }
}

@keyframes breathe {
  0%, 100% { opacity: .9; transform: scale(1); }
  50%      { opacity: 1;  transform: scale(1.04); }
}

/* The way past the film, as on template-1. Top right rather than bottom
   right, where the music button lives. Above the names, below the cover.
   Larger and barely tracked, as Devanagari labels are throughout. */
.hero__skip {
  position: absolute;
  top: 1.25rem;
  right: 1.25rem;
  z-index: 8;
  padding: .45rem 1.1rem;
  font-family: var(--font-heading);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--gold-soft);
  background: rgba(0, 0, 0, .5);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(201, 162, 39, .6);
  border-radius: 9999px;
  cursor: pointer;
  animation: skip-in .6s ease both;
  transition: background .25s ease, border-color .25s ease;
}

.hero__skip:hover {
  background: rgba(0, 0, 0, .7);
  border-color: var(--gold);
}

.hero__skip[hidden] { display: none; }

@keyframes skip-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* The names, centred and lifted clear of the lower third of the film. */
.hero__names {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-bottom: 15vh;
  text-align: center;
  pointer-events: none;
}

/* A dark veil behind the names so they read over any frame of the film. It
   stays clear while the film plays alone and fades in with the names. */
.hero__names::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, .65) 0%, rgba(0, 0, 0, .45) 55%, rgba(0, 0, 0, .3) 100%);
  opacity: 0;
  transition: opacity 1.5s ease-out;
}

.hero__names.is-in::before { opacity: 1; }

/* Each line starts hidden and is dealt in by assets/js/hero.js: it rises and
   scales up while a clip wipes it open from its own baseline, which is what
   gives the names their curtain-lift rather than a plain fade. */
.hero__names > * {
  opacity: 0;
  transform: translateY(40px) scale(.9);
  clip-path: polygon(-50% 150%, 150% 150%, 150% 150%, -50% 150%);
  transition: opacity 1.5s cubic-bezier(.215, .61, .355, 1),
              transform 1.5s cubic-bezier(.215, .61, .355, 1),
              clip-path 1.5s cubic-bezier(.215, .61, .355, 1);
}

.hero__names.is-in > * {
  opacity: 1;
  transform: none;
  clip-path: polygon(-50% -50%, 150% -50%, 150% 150%, -50% 150%);
}

/* No letter-spacing: tracking a Devanagari word breaks its headline and
   pulls its conjuncts apart. The hairline stroke is thinner than the English
   page's too — at .9px it closes up the counters of the smaller Devanagari
   letterforms. */
.hero__name {
  font-family: var(--font-names);
  font-size: 3.6rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0;
  color: var(--cream);
  padding: .15em .5em;
  -webkit-text-stroke: .4px rgba(255, 255, 255, .7);
  text-shadow: 0 0 15px rgba(0, 0, 0, .9), 0 0 30px rgba(0, 0, 0, .7), 0 0 50px rgba(0, 0, 0, .5);
}

/* संग where the English page has "Weds". */
.hero__weds {
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cream);
  margin: 1rem 0;
  text-shadow: 0 4px 12px rgba(0, 0, 0, .8), 0 12px 32px rgba(0, 0, 0, .7);
}

@media (max-width: 480px) {
  .hero__name { font-size: 2.8rem; }
  .hero__weds { font-size: 1.3rem; }
}

/* Appears once the names have finished, and bounces until scrolled past. */
.hero__scroll {
  position: absolute;
  bottom: 5.5rem;
  left: 0;
  z-index: 5;
  display: flex;
  justify-content: center;
  width: 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity .6s ease-out;
}

.hero__scroll.is-in { opacity: 1; }

.hero__scroll-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .2rem;
  animation: haptic 1s cubic-bezier(.4, 0, .2, 1) infinite;
}

.hero__scroll-text {
  font-family: var(--font-heading);
  font-size: clamp(1.15rem, 4vw, 1.6rem);
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: gold;
  text-shadow: 0 0 10px rgba(255, 215, 0, .6), 0 0 20px rgba(255, 215, 0, .4);
}

.hero__scroll-arrow {
  font-family: var(--font-heading);
  font-size: clamp(2.4rem, 9vw, 3.8rem);
  line-height: 1;
  color: #fff;
  filter: drop-shadow(0 0 8px rgba(255, 215, 0, .9)) drop-shadow(0 0 15px rgba(255, 215, 0, .7));
}

@keyframes haptic {
  0%, 100% { opacity: .8; transform: translateY(0);
             filter: drop-shadow(0 0 5px rgba(201, 162, 39, .4)); }
  50%      { opacity: 1;  transform: translateY(10px);
             filter: drop-shadow(0 0 20px rgba(201, 162, 39, 1)); }
}


/* ==========================================================================
   5. Music player
   A gold record in the corner, spinning while the track plays.
   ========================================================================== */

.music {
  position: fixed;
  right: clamp(16px, 2vw, 28px);
  bottom: clamp(16px, 2vw, 28px);
  z-index: 60;
  width: clamp(58px, 5vw, 74px);
  height: clamp(58px, 5vw, 74px);
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  opacity: 0;
  transform: translateY(60px);
  transition: opacity .8s ease-out, transform .8s ease-out;
}

/* Hidden until the invitation is opened — there is nothing to pause before. */
.music.is-in { opacity: 1; transform: none; }

.music::before {
  content: "";
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  filter: blur(10px);
  background: radial-gradient(circle, rgba(255, 208, 85, .55), rgba(255, 208, 85, .18), transparent 72%);
  animation: glow 2.5s ease-in-out infinite;
}

.music__record {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 0 8px rgba(255, 210, 80, .35));
  animation: spin 8s linear infinite;
  animation-play-state: paused;
}

.music.is-playing .music__record { animation-play-state: running; }

@keyframes glow {
  0%, 100% { opacity: .45; transform: scale(.92); }
  50%      { opacity: 1;   transform: scale(1.15); }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}


/* ==========================================================================
   6. Invitation
   ========================================================================== */

.invite__card {
  max-width: 800px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(3rem, 6vw, 4rem) clamp(1rem, 4vw, 2rem);
  overflow: hidden;
}

/* ॐ, as the English page has it — here it is simply the page's own script. */
.invite__onkar {
  font-size: 2.4rem;
  line-height: 1.3;
  color: var(--gold);
  margin-bottom: .5rem;
}

/* The Ganesh shloka, in Devanagari as a Hindi card prints it. */
.invite__shabad {
  font-size: .95rem;
  font-weight: 500;
  line-height: 2;
  letter-spacing: .02em;
  color: var(--ink);
  opacity: .7;
  margin-bottom: 1.5rem;
}

.invite__heading {
  font-family: var(--font-title);
  font-size: clamp(1.6rem, 5.5vw, 2.1rem);
  font-weight: 700;
  color: var(--maroon);
  margin-bottom: 1rem;
}

.invite__lead {
  max-width: 600px;
  font-size: clamp(1rem, 3vw, 1.25rem);
  font-weight: 500;
  line-height: 1.8;
  margin-bottom: clamp(1.5rem, 5vw, 4rem);
}

.invite__name {
  font-family: var(--font-names);
  font-size: clamp(2rem, 7vw, 2.6rem);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0;
  color: var(--maroon);
  padding: 0 .5em;
  margin-bottom: .5rem;
}

/* The card's honorifics — चि. before the groom, सौ. कां. before the
   bride — sit smaller than the name itself, as they are printed on the card.
   The &nbsp; after them in index.html keeps them from wrapping away. */
.invite__chi {
  font-size: .55em;
  font-weight: 600;
  color: var(--gold-deep);
}

.invite__relation {
  font-size: .9rem;
  font-style: normal;
  opacity: .8;
  margin-bottom: .25rem;
}

.invite__parents {
  font-size: clamp(1rem, 3vw, 1.2rem);
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0;
  color: var(--gold);
}

/* The joining words of the card's sentence — "का शुभ विवाह" between the two
   names and "के साथ होना निश्चित हुआ है।" after the bride's. Upright and
   heavier where the English "With" is italic. */
.invite__with {
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: .02em;
  opacity: .7;
  margin: 1.25rem 0;
}

/* The request to come, which closes the card. */
.invite__close {
  margin-bottom: 0;
  color: var(--maroon);
}


/* ==========================================================================
   7. Scratch card
   A gold heart scratched away with the pointer to uncover the date.
   ========================================================================== */

.scratch {
  position: relative;
  overflow: hidden;
  background-color: #fcfbf9;
  background-image: radial-gradient(circle at 10% 10%, #fff8e7 0%, transparent 60%);
}

/* Gold flecks drifting up through the whole section, behind the heart. Built
   in assets/js/effects.js because every one of them is placed at random. */
.sparks {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.sparks__item {
  position: absolute;
  border-radius: 50%;
  box-shadow: 0 0 4px rgba(255, 255, 255, .8);
  animation: spark-rise linear infinite;
}

/* The travel is in viewport units, not percentages: a percentage here would be
   a share of each 2-6px speck rather than of the section it drifts through. */
@keyframes spark-rise {
  0%       { opacity: 0; transform: translateY(100vh) rotate(0); }
  10%, 90% { opacity: 1; }
  100%     { opacity: 0; transform: translateY(-20vh) rotate(360deg); }
}

.scratch__head { position: relative; z-index: 10; text-align: center; margin-bottom: clamp(2rem, 6vw, 4rem); }

.scratch__eyebrow {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 1rem;
}

.scratch__title {
  font-family: var(--font-heading);
  font-size: clamp(1.45rem, 5vw, 2.1rem);
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: 0;
  color: #6e2c2c;
}

.scratch__stage {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 460px;
}

/* The heart is square; the clip-path does the shaping. */
.scratch__card {
  position: relative;
  width: 100%;
  max-width: 400px;
  aspect-ratio: 1;
  margin: 0 auto;
  transition: transform .5s cubic-bezier(.25, 1, .5, 1);
  animation: hover-heart 4s ease-in-out infinite;
}

.scratch__card:hover { transform: scale(1.02); }
.scratch__card:hover .scratch__heart-line { filter: drop-shadow(0 0 15px rgba(201, 162, 39, .6)); }

.scratch__heart-bg,
.scratch__heart-line,
.scratch__foil-wrap {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* White fill behind the foil, so a scratched patch shows paper not page. */
.scratch__heart-bg {
  z-index: 0;
  filter: drop-shadow(0 15px 25px rgba(0, 0, 0, .08));
}

/* The foil canvas, clipped to the heart. */
.scratch__foil-wrap {
  z-index: 2;
  clip-path: url(#heart-clip);
}

.scratch__foil {
  width: 100%;
  height: 100%;
  cursor: crosshair;
  transition: opacity 1.2s ease-in-out;
}

.scratch__foil.is-cleared { opacity: 0; pointer-events: none; }

/* A single sweep of light across the foil, fired once the guest has scratched
   enough to show they have understood the idea — it draws the eye back to the
   heart just before it gives way. */
.scratch__shimmer {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  mix-blend-mode: overlay;
  background: linear-gradient(110deg, transparent 0% 40%, rgba(255, 255, 255, .7) 50%, transparent 60% 100%) 0 0 / 200% 100%;
  animation: shimmer-sweep 1.5s ease-in-out forwards;
}

.scratch__shimmer[hidden] { display: none; }

@keyframes shimmer-sweep {
  0%   { opacity: 0; background-position: 200% 0; }
  10%  { opacity: 1; }
  90%  { opacity: 1; }
  100% { opacity: 0; background-position: -200% 0; }
}

/* The gold outline, drawn over the foil and left behind after the reveal. */
.scratch__heart-line {
  z-index: 3;
  pointer-events: none;
  filter: drop-shadow(0 0 8px rgba(201, 162, 39, .3));
  animation: heart-breathe 4s ease-in-out infinite;
}

.scratch__date {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  width: 80%;
  transform: translate(-50%, -50%) scale(.95);
  opacity: 0;
  text-align: center;
  font-family: var(--font-heading);
  font-size: 1.9rem;
  font-weight: 700;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--gold-deep);
  text-shadow: 1px 1px 2px rgba(255, 255, 255, .8);
  transition: opacity 1s ease-out, transform 1s cubic-bezier(.2, 1.4, .4, 1);
}

.scratch__date.is-in { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* Confetti fired on reveal; sized generously so pieces can fall in from
   outside the card. */
.scratch__confetti {
  position: absolute;
  top: -50%;
  left: -50%;
  z-index: 10;
  width: 200%;
  height: 200%;
  pointer-events: none;
}

.scratch__hint {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 2.5rem;
  transition: opacity .5s;
}

.scratch__hint.is-done { opacity: 0; }

.scratch__hint-text {
  font-family: var(--font-heading);
  font-size: clamp(1.05rem, 3vw, 1.2rem);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--maroon);
  opacity: .75;
  margin-bottom: .8rem;
}

.scratch__hand {
  width: 32px;
  height: 32px;
  color: var(--gold);
  opacity: .8;
  animation: swipe 2s ease-in-out infinite;
}

@keyframes hover-heart {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}

@keyframes heart-breathe {
  0%, 100% { filter: drop-shadow(0 0 8px rgba(201, 162, 39, .3)); }
  50%      { filter: drop-shadow(0 0 12px rgba(201, 162, 39, .5)); }
}

@keyframes swipe {
  0%, 100% { transform: translateX(15px) rotate(10deg); }
  50%      { transform: translateX(-15px) rotate(-10deg); }
}

@media (max-width: 480px) {
  .scratch            { padding: 40px 10px; }
  .scratch__card      { max-width: 320px; }
  .scratch__date      { font-size: 2.1rem; }
  .scratch__hint-text { font-size: 1.05rem; }
}


/* ==========================================================================
   8. Countdown
   ========================================================================== */

.countdown__grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(8px, 3vw, 2rem);
}

.countdown__cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(8px, 2vw, 16px);
}

.countdown__box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(65px, 18vw, 130px);
  height: clamp(65px, 18vw, 130px);
  background: var(--cream);
  border: 1px solid rgba(201, 161, 74, .25);
  border-radius: 8px;
  box-shadow: var(--shadow);
}

/* Swapped out and back by assets/js/countdown.js as each number changes: the
   old number leaves upwards, the new one rises into its place. */
.countdown__value {
  font-family: var(--font-heading);
  font-size: clamp(26px, 7vw, 54px);
  font-weight: 600;
  line-height: 1.1;
  color: var(--gold);
  transition: transform .35s cubic-bezier(.215, .61, .355, 1), opacity .35s ease-out;
}

.countdown__value.is-turning {
  opacity: 0;
  transform: translateY(-20px);
  transition: transform .25s ease-in, opacity .25s ease-in;
}

/* Where the incoming number waits, for one frame, before it rises. */
.countdown__value.is-below   { opacity: 0; transform: translateY(20px); }
.countdown__value.is-instant { transition: none; }

/* Larger than the English labels: at 8px a Devanagari word's matras are
   barely legible. */
.countdown__label {
  font-family: var(--font-heading);
  font-size: clamp(12px, 2.8vw, 15px);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink);
}


/* ==========================================================================
   9. Our story
   A three-photo carousel beside the text.
   ========================================================================== */

.story__grid {
  display: flex;
  align-items: center;
  gap: clamp(2rem, 5vw, 4rem);
  width: 100%;
  max-width: 1100px;
}

.story__col { flex: 1; width: 100%; }

/* The three frames are stacked in one spot; .is-prev / .is-next slide the
   neighbours out to either side. */
.carousel {
  /* How far the two neighbouring photos sit out from the middle one. */
  --offset: 120px;

  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 600px;
  perspective: 1000px;
  touch-action: pan-y;
  user-select: none;
}

.carousel__slide {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 320px;
  height: 480px;
  padding: 14px;
  background: var(--cream);
  border: var(--rule-gold);
  border-radius: 12px;
  box-shadow: var(--shadow);
  cursor: grab;
  opacity: 0;
  z-index: 1;
  transform: scale(.5);
  transition: transform .6s cubic-bezier(.22, 1, .36, 1),
              opacity .6s cubic-bezier(.22, 1, .36, 1);
}

.carousel__slide:active { cursor: grabbing; }

.carousel__slide::after {
  content: "";
  position: absolute;
  inset: 6px;
  z-index: 10;
  border: 1px solid rgba(201, 162, 39, .3);
  border-radius: 8px;
  pointer-events: none;
}

.carousel__slide.is-current { opacity: 1; z-index: 3; transform: translateX(0) scale(1); }
.carousel__slide.is-next    { opacity: .5; z-index: 2; transform: translateX(var(--offset)) scale(.85); }
.carousel__slide.is-prev    { opacity: .5; z-index: 2; transform: translateX(calc(var(--offset) * -1)) scale(.85); }


.carousel__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 4px;
  pointer-events: none;
}

.story__text {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 1.5rem;
}

.story__title {
  font-family: var(--font-title);
  font-size: clamp(2.1rem, 7vw, 2.7rem);
  font-weight: 700;
  color: var(--maroon);
  margin-bottom: 1rem;
}

.story__text p {
  font-size: clamp(1.02rem, 3vw, 1.12rem);
  font-weight: 400;
  line-height: 1.9;
  opacity: .9;
}

@media (max-width: 900px) {
  .story__grid     { flex-direction: column; text-align: center; }
  .carousel        { --offset: 60px; height: 450px; }
  .carousel__slide { width: 260px; height: 390px; }
}


/* ==========================================================================
   10. Wedding events
   ========================================================================== */

.events { background-color: var(--cream); }

.events__list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4rem;
  width: 100%;
  max-width: 600px;
}

.event {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  width: 100%;
  padding: clamp(1.5rem, 5vw, 2.5rem);
  background: #fff;
  border-radius: 20px;
  box-shadow: var(--shadow-card);
  text-align: center;
}

.event__name {
  font-family: var(--font-title);
  font-size: clamp(1.9rem, 7vw, 2.5rem);
  font-weight: 700;
  line-height: 1.35;
  color: var(--gold);
  margin-bottom: 1rem;
}

.event__date {
  font-family: var(--font-heading);
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  opacity: .75;
}

.event__time {
  font-family: var(--font-heading);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--gold);
  margin-top: .5rem;
}

/* The event films are portrait (9:16) and fill the card's width, as the
   photos did. The gold wash shows until the first frame arrives. */
.event__video {
  display: block;
  width: 100%;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  border-radius: 16px;
  background: linear-gradient(160deg, #f6ead2, #e9d3a8);
  cursor: pointer;
  /* Its own compositor layer, so a playing film is not repainted with the
     page on every scroll frame. */
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* The event cards rise in without the blur the other reveals use: a blur
   filter over a playing film forces the phone to re-filter every frame. */
.event[data-reveal] {
  filter: none;
  transition: opacity .9s ease, transform .9s ease;
}

.event__venue {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .6rem;
}

.event__venue-label {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: #2f2e2d;
}

.event__venue-name {
  font-family: var(--font-heading);
  font-size: clamp(1.45rem, 5vw, 1.9rem);
  font-weight: 700;
  /* The gradient is clipped to the text, so anything outside the element's
     box is not painted at all — at the English 1.2 the matras above a line
     would be cut off. The extra line-height and padding keep them inside it. */
  line-height: 1.5;
  padding: .1em 0;
  letter-spacing: .5px;
  text-transform: uppercase;
  background: linear-gradient(90deg, var(--gold), var(--gold-soft));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.event__street {
  font-family: var(--font-heading);
  font-size: 1.15rem;
  color: var(--ink-soft);
}

.event__country {
  font-family: var(--font-heading);
  font-size: 1.45rem;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
  color: #6e2c2c;
}

/* Shared by the four event cards; the only link out of the page. */
.map-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 1rem;
  padding: 12px 24px;
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--gold);
  background: var(--cream);
  border: 1px solid rgba(201, 161, 74, .35);
  border-radius: 100px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, .06);
  transition: transform .3s, box-shadow .3s;
}

.map-link:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 28px rgba(201, 161, 74, .15);
}

.map-link svg { width: 16px; height: 16px; }


/* ==========================================================================
   11. The journey — Ahmedabad to Udaipur
   The plane flies down the dashed line as the section is scrolled.
   ========================================================================== */

.journey {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 600px;
  margin: clamp(4rem, 10vw, 6rem) 0;
}

.journey__stop {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  z-index: 5;
}

.journey__stop img {
  width: 300px;
  max-height: 250px;
  object-fit: contain;
}

/* journey-2.webp is square with clear space above and below the palace;
   trimmed to the same 3:2-ish frame as journey-1 so the two read as a pair. */
.journey__stop img.journey__img--trim {
  aspect-ratio: 300 / 220;
  height: auto;
  object-fit: cover;
  object-position: 50% 64%;
}

.journey__place {
  font-family: var(--font-heading);
  font-size: clamp(1.8rem, 6vw, 2.2rem);
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--maroon);
  margin-top: .5rem;
}

.journey__track {
  position: relative;
  width: 100%;
  height: 350px;
  margin: 3rem 0;
}

.journey__line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  transform: translateX(-50%);
  background-image: linear-gradient(transparent 50%, rgba(0, 0, 0, .25) 50%);
  background-size: 100% 16px;
}

/* Nose-down at the top of the track; assets/js/journey.js drives --progress
   from 0 to 1 as the section passes the viewport. The travel is a percentage
   of `top`, which resolves against the track — a percentage translate would
   only ever move the plane its own height. */
.journey__plane {
  position: absolute;
  top: calc(var(--progress, 0) * 100%);
  left: 50%;
  z-index: 10;
  width: 40px;
  height: 40px;
  /* `top` tracks the scroll exactly; the turn and the swell are eased, so the
     plane banks around rather than snapping. */
  transform: translate(-50%, -50%) rotate(var(--facing, 180deg)) scale(var(--climb, 1));
  transition: transform .5s ease-out;
}

.journey__plane svg {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  color: var(--maroon);
  animation: float 1.6s ease-in-out infinite;
}

/* The ground shadow under the plane. It shrinks and fades as the plane climbs
   away at the start of the flight, and settles again as it comes back down —
   assets/js/journey.js drives both off the same --progress. */
.journey__plane-shadow {
  position: absolute;
  top: 10%;
  left: 10%;
  z-index: 1;
  width: 80%;
  height: 80%;
  border-radius: 50%;
  background: radial-gradient(rgba(0, 0, 0, .4) 0%, transparent 70%);
  transform: translateY(5px) scale(var(--shadow-scale, 1));
  opacity: var(--shadow-alpha, .5);
}

/* The track tightens on a phone but the plane itself gets bigger, so it still
   reads as an aircraft rather than a speck on the line. */
@media (max-width: 768px) {
  .journey__track     { height: 300px; }
  .journey__plane     { width: 60px; height: 60px; }
  .journey__stop img  { width: 240px; max-height: 180px; }
}


/* ==========================================================================
   12. With blessings from
   ========================================================================== */

.family__card {
  max-width: 850px;
  padding: clamp(2rem, 6vw, 3rem) clamp(.5rem, 3vw, 1rem);
}

.family__group { margin-bottom: 1.5rem; }
.family__group:last-child { margin-bottom: 0; }

.family__group h4 {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--maroon);
  margin-bottom: .25rem;
}

.family__group p {
  font-size: 1.3rem;
  font-weight: 600;
  line-height: 1.5;
  /* A pair's names wrap as two even lines rather than leaving a lone surname. */
  text-wrap: balance;
}

@media (max-width: 768px) {
  .family__group p { font-size: 1.15rem; }
}


/* ==========================================================================
   12a. बाल मनुहार
   The children's rhyme a Hindi wedding card carries, asking the guests to
   come — the Gujarati edition's ટહુકો in its Hindi form. The family card's
   white-and-gold motif, with the verse ruled off above and below and the
   children's names set as the signature.
   ========================================================================== */

/* Follows the family card closely, as the next line of the same card would. */
.manuhar { padding-top: 0; }

.manuhar__card {
  max-width: 650px;
  padding: clamp(2.25rem, 6vw, 3rem) clamp(1.25rem, 5vw, 2.5rem);
}

.manuhar__title {
  font-size: clamp(1.6rem, 5vw, 2rem);
  font-weight: 700;
  color: var(--gold-deep);
}

.manuhar__verse {
  max-width: 32rem;
  margin: 1.25rem auto 0;
  padding: 1.1rem 0;
  border-block: var(--rule-gold);
  font-size: clamp(1.05rem, 3vw, 1.2rem);
  font-weight: 600;
  line-height: 1.8;
  color: var(--maroon);
}

.manuhar__verse p + p { margin-top: .2rem; }

/* Each line is written as two half-lines. Side by side where there is room;
   stacked on a phone, where a full line would otherwise break at whatever
   word ran out of space and leave its rhyme word stranded. */
.manuhar__verse span { display: inline-block; }

@media (max-width: 480px) {
  .manuhar__verse span { display: block; }
  .manuhar__verse p + p { margin-top: .6rem; }
}

/* Who is asking: a small gold label, then the children's names beneath it,
   large enough to read as the signature on the card. */
.manuhar__signature {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .35rem;
  margin-top: 1.4rem;
}

.manuhar__from {
  display: flex;
  align-items: center;
  gap: .6rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--gold-deep);
}

.manuhar__from::before,
.manuhar__from::after {
  content: "";
  width: 1.75rem;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-deep), transparent);
}

.manuhar__kids {
  font-size: clamp(1.3rem, 4vw, 1.6rem);
  font-weight: 700;
  line-height: 1.4;
  color: var(--maroon);
}

.manuhar__kids span { margin: 0 .4rem; color: var(--gold); }


/* ==========================================================================
   13. RSVP
   A boarding pass for the journey the events section has just flown: the
   guest fills it in, and sending it stamps it. See assets/js/rsvp.js.
   Sized for Devanagari as the rest of this sheet is: the English page's
   Great Vibes and Parisienne become Eczar bold at about two thirds the size,
   tracking comes down to a third, and nothing is set in italic.
   ========================================================================== */

.rsvp__lead {
  max-width: 34rem;
  margin: -1.5rem auto 2.5rem;
  font-size: 1.3rem;
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
  color: var(--ink-soft);
}

.pass {
  position: relative;
  width: 100%;
  max-width: 560px;
  overflow: hidden;
  background: #fff;
  border-radius: 18px;
  box-shadow: 0 25px 60px -20px rgba(110, 31, 47, .35),
              0 0 0 1px rgba(201, 162, 39, .35);
}

/* The airline strip across the top. */
.pass__band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.5rem;
  font-family: var(--font-heading);
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--cream);
  background: var(--maroon);
}

.pass__airline {
  display: flex;
  align-items: center;
  gap: .6rem;
  color: var(--gold-soft);
}

/* The plane is drawn nose-up; turned to fly east, Ahmedabad to Udaipur. */
.pass__airline svg,
.pass__path svg {
  flex: none;
  width: 18px;
  height: 18px;
  transform: rotate(90deg);
}

/* AMD ✈ UDR. */
.pass__route {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 1rem;
  padding: 1.75rem 1.5rem 1.5rem;
  border-bottom: 1px dashed rgba(201, 162, 39, .45);
}

.pass__city {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .2rem;
}

.pass__city--to { align-items: flex-end; text-align: right; }

.pass__code {
  font-family: var(--font-heading);
  font-size: clamp(2rem, 8vw, 2.75rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: .05em;
  color: var(--maroon);
}

.pass__place {
  font-size: 1rem;
  font-weight: 600;
  color: var(--ink-soft);
}

.pass__when {
  font-family: var(--font-heading);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.pass__path {
  display: flex;
  align-items: center;
  gap: .5rem;
  color: var(--gold);
}

.pass__path svg { width: 24px; height: 24px; }

.pass__dash {
  flex: 1;
  height: 2px;
  background: linear-gradient(90deg, rgba(201, 162, 39, .7) 50%, transparent 50%) 0 0 / 10px 2px;
}

/* ---- The form ------------------------------------------------------------ */

.pass__body { padding: 1.75rem 1.5rem .25rem; text-align: left; }

.pass__field {
  min-width: 0;
  margin: 0 0 1.6rem;
  padding: 0;
  border: 0;
}

.pass__label {
  display: block;
  margin-bottom: .45rem;
  padding: 0;
  font-family: var(--font-heading);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

/* Written on the pass rather than typed into a box: a single rule to write
   along. */
.pass__input {
  width: 100%;
  padding: .3rem 0 .5rem;
  font-family: var(--font-body);
  font-size: 1.4rem;
  font-weight: 600;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1.5px solid rgba(110, 31, 47, .25);
  border-radius: 0;
  transition: border-color .3s;
}

.pass__input::placeholder { color: rgba(47, 47, 47, .35); font-weight: 500; }
.pass__input:focus        { outline: none; border-bottom-color: var(--maroon); }
.pass__input.is-bad       { border-bottom-color: #d9534f; }

textarea.pass__input {
  min-height: 64px;
  font-size: 1.2rem;
  line-height: 1.5;
  resize: vertical;
}

.pass__value {
  font-family: var(--font-heading);
  font-size: 1.15rem;
  color: var(--maroon);
}

.error {
  font-size: .9rem;
  color: #d9534f;
  margin-top: .35rem;
}

.error[hidden] { display: none; }

/* Joyfully yes / Regretfully no — two tiles side by side, the chosen one
   filled: maroon for yes, grey for no. They are radio buttons underneath. */
.choices {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .6rem;
}

.choice {
  position: relative;
  cursor: pointer;
}

.choice input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.choice__card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  height: 100%;
  padding: .75rem 2.2rem .75rem .95rem;
  border: 1px solid rgba(201, 162, 39, .5);
  border-radius: 10px;
  transition: background .25s, border-color .25s, transform .25s;
}

.choice:hover .choice__card { border-color: var(--maroon); transform: translateY(-1px); }

.choice__name {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--maroon);
  transition: color .25s;
}

/* A tick in the corner, drawn once the tile is chosen. */
.choice__card::after {
  content: "";
  position: absolute;
  top: 50%;
  right: .95rem;
  width: 6px;
  height: 11px;
  border: solid var(--gold-soft);
  border-width: 0 2px 2px 0;
  opacity: 0;
  transform: translateY(-65%) rotate(45deg) scale(.4);
  transition: opacity .25s, transform .25s;
}

.choice input:checked + .choice__card {
  background: var(--maroon);
  border-color: var(--maroon);
}

.choice input:checked + .choice__card .choice__name { color: var(--cream); }

.choice input:checked + .choice__card::after {
  opacity: 1;
  transform: translateY(-65%) rotate(45deg) scale(1);
}

.choice--regret input:checked + .choice__card {
  background: var(--ink-soft);
  border-color: var(--ink-soft);
}

.choice input:focus-visible + .choice__card {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.counter {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.counter button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  font-family: var(--font-heading);
  font-size: 1.1rem;
  color: var(--maroon);
  background: transparent;
  border: 1px solid var(--maroon);
  border-radius: 50%;
  cursor: pointer;
  transition: background .25s, color .25s;
}

.counter button:hover { background: var(--maroon); color: var(--cream); }

.counter output {
  min-width: 24px;
  font-family: var(--font-heading);
  font-size: 1.2rem;
  text-align: center;
  color: var(--maroon);
}

/* ---- The tear line and the stub ------------------------------------------ */

/* Dashes across, and a round bite out of each edge of the pass where it would
   be torn. The bites are the page's own cream. */
.pass__tear {
  position: relative;
  margin: 0 18px;
  border-top: 2px dashed rgba(201, 162, 39, .5);
}

.pass__tear::before,
.pass__tear::after {
  content: "";
  position: absolute;
  top: -15px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #f8f2e6;
}

.pass__tear::before { left: -32px; }
.pass__tear::after  { right: -32px; }

.pass__stub {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1.5rem;
}

.pass__barcode {
  flex: none;
  width: 84px;
  height: 46px;
  opacity: .75;
  background: repeating-linear-gradient(90deg,
    var(--ink) 0 2px, transparent 2px 4px,
    var(--ink) 4px 5px, transparent 5px 8px,
    var(--ink) 8px 11px, transparent 11px 12px,
    var(--ink) 12px 13px, transparent 13px 16px);
}

.pass__send {
  flex: 1;
  padding: 1rem 1.5rem;
  font-family: var(--font-heading);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--cream);
  background: var(--maroon);
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: background .3s, transform .3s, box-shadow .3s;
}

.pass__send:hover {
  background: var(--ink);
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .15);
}

.pass__send:disabled { opacity: .7; cursor: not-allowed; transform: none; }

/* ---- The issued pass ----------------------------------------------------- */

.pass__issued {
  padding: 2rem 1.5rem 2.25rem;
  text-align: center;
  outline: none;
}

.pass__issued[hidden] { display: none; }

/* Inked onto the pass as it is issued: dropped from above, a little crooked. */
.pass__stamp {
  display: inline-block;
  margin-bottom: 1.5rem;
  padding: .4rem 1rem;
  font-family: var(--font-heading);
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--maroon);
  border: 3px double var(--maroon);
  border-radius: 8px;
  opacity: .85;
  transform: rotate(-8deg);
}

.pass.is-issued .pass__stamp { animation: stamp .55s cubic-bezier(.2, 1.3, .4, 1) both; }
.pass.is-regret .pass__stamp { color: var(--ink-soft); border-color: var(--ink-soft); }

.pass__guest {
  font-family: var(--font-title);
  font-size: clamp(1.8rem, 6.5vw, 2.2rem);
  font-weight: 700;
  line-height: 1.4;
  color: var(--maroon);
  overflow-wrap: anywhere;
}

.pass__summary {
  max-width: 260px;
  margin: 1.5rem auto 0;
  padding-top: 1.25rem;
  border-top: 1px dashed rgba(201, 162, 39, .45);
}

.pass__summary[hidden] { display: none; }

.pass__note {
  max-width: 26rem;
  margin: 1.5rem auto 2rem;
  font-size: 1.2rem;
  line-height: 1.6;
}

.rsvp__again {
  padding: .75rem 2.5rem;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--maroon);
  background: transparent;
  border: 1px solid var(--maroon);
  border-radius: 30px;
  cursor: pointer;
  transition: background .3s, color .3s;
}

.rsvp__again:hover { background: var(--maroon); color: var(--cream); }

.rsvp__sample {
  max-width: 30rem;
  margin-top: 2rem;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.5;
  text-align: center;
  color: var(--ink-soft);
}

@media (max-width: 480px) {
  .rsvp__lead  { font-size: 1.15rem; }
  .pass__band  { padding: .9rem 1.1rem; font-size: .78rem; letter-spacing: .02em; }
  .pass__route { padding: 1.5rem 1.1rem 1.25rem; gap: .6rem; }
  .pass__place { font-size: .9rem; }
  .pass__body  { padding: 1.5rem 1.1rem .25rem; }
  .choice__card { padding: .7rem 1.6rem .7rem .8rem; }
  .choice__card::after { right: .7rem; }
  .choice__name { font-size: 1.1rem; }
  .pass__stub  { padding: 1.25rem 1.1rem; gap: .9rem; }
  .pass__barcode { width: 60px; }
  .pass__send  { padding: .95rem 1rem; font-size: .95rem; letter-spacing: .02em; }
}

@keyframes stamp {
  from { opacity: 0; transform: rotate(-8deg) scale(2.2); }
  to   { opacity: .85; transform: rotate(-8deg) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .pass.is-issued .pass__stamp { animation: none; }
}


/* ==========================================================================
   14. Footer
   A postcard home — airmail border, the monogram for a stamp and a postmark
   from the wedding — on the maroon ground.
   ========================================================================== */

.footer {
  padding: 5rem 1.5rem 2rem;
  text-align: center;
  color: var(--cream);
  background: var(--maroon);
}

/* The airmail stripes are the postcard's own background, showing as a
   border around the paper laid over it. */
.postcard {
  max-width: 820px;
  margin: 0 auto 2.5rem;
  padding: 10px;
  border-radius: 6px;
  background: repeating-linear-gradient(135deg,
    var(--gold)  0 14px,  #fdf9f0 14px 22px,
    #b8475a      22px 36px, #fdf9f0 36px 44px);
  box-shadow: 0 30px 60px -25px rgba(0, 0, 0, .5);
}

.postcard__paper {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 2rem;
  padding: 2rem;
  text-align: left;
  color: var(--ink);
  background: #fdf9f0;
  border-radius: 2px;
}

.postcard__message {
  padding-right: 2rem;
  border-right: 1px solid rgba(110, 31, 47, .2);
}

.postcard__thanks {
  margin-bottom: .75rem;
  font-family: var(--font-script);
  font-size: clamp(2.1rem, 7vw, 2.7rem);
  font-weight: 700;
  line-height: 1.35;
  color: var(--maroon);
}

.postcard__text {
  font-size: 1.2rem;
  font-weight: 500;
  line-height: 1.6;
}

.postcard__sign {
  margin-top: 1.25rem;
  font-size: 1.1rem;
  font-weight: 500;
}

.postcard__sign span {
  display: block;
  font-family: var(--font-title);
  font-size: 1.5rem;
  font-weight: 700;
  font-style: normal;
  color: var(--maroon);
}

.postcard__address { display: flex; flex-direction: column; }

.postcard__marks {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  margin-bottom: 1.75rem;
}

/* Inked over the stamp's corner, as a real one would be. */
.postcard__postmark {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 92px;
  height: 92px;
  margin-right: -12px;
  font-family: var(--font-heading);
  font-size: .68rem;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: rgba(110, 31, 47, .7);
  border: 2px solid rgba(110, 31, 47, .55);
  border-radius: 50%;
  transform: rotate(-14deg);
}

.postcard__postmark strong {
  margin: .2rem 0;
  font-size: .85rem;
  letter-spacing: .02em;
}

/* The perforated edge is a dotted border in the paper's colour, drawn over
   the stamp's white. */
.postcard__stamp {
  width: 88px;
  height: 104px;
  padding: 5px;
  background: #fff;
  border: 5px dotted #fdf9f0;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .15));
}

.postcard__stamp img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--cream);
}

.postcard__to {
  margin-bottom: .25rem;
  font-family: var(--font-heading);
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.postcard__lines {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The address, written along ruled lines. */
.postcard__lines li {
  padding: .35rem 0 .1rem .75rem;
  font-family: var(--font-title);
  font-size: 1.3rem;
  font-weight: 600;
  line-height: 1.6;
  color: var(--maroon);
  border-bottom: 1px solid rgba(110, 31, 47, .25);
}

.footer__credit {
  font-size: .78rem;
  letter-spacing: .05em;
  color: rgba(250, 245, 235, .7);
}

.footer__credit a { color: var(--gold); text-decoration: none; }

@media (max-width: 680px) {
  .footer { padding-top: 4rem; }

  .postcard__paper {
    grid-template-columns: 1fr;
    gap: 1.5rem;
    padding: 1.5rem;
  }

  .postcard__message {
    padding: 0 0 1.5rem;
    border-right: 0;
    border-bottom: 1px solid rgba(110, 31, 47, .2);
  }

  /* On a phone the stamp leads the address side, so it sits at the left. */
  .postcard__marks { justify-content: flex-start; }
}
