/*
  ნინი & საბა, all styling for index.html.

  Mobile-first: base rules target the narrowest phone, min-width queries only
  (481 / 769 / 1025). From 769px the invitation is presented as a phone-width
  column over a blurred copy of the hero, so it can be read and scrolled on a
  laptop (trackpad included) without a desktop layout of its own.

  Blocks: fonts -> tokens -> reset/scrollbar -> toggles -> loader -> entry ->
  hero -> cue -> sheets + reveal -> countdown -> note -> timetable -> dress code
  -> RSVP -> footer -> night mode -> breakpoints -> reduced motion.

  Palette is sampled off the artwork: the paper is hydrangea white in shade, the
  ink and the one accent are the gate's dusty blue, the warm gold is the sunset
  and is only ever a hairline or the ampersand.
*/

/* ==========================================================================
   1. FONTS
   block is only safe because the loader covers the block period and awaits
   document.fonts with a Georgian probe glyph (script.js).
   ========================================================================== */
@font-face {
    font-family: 'DM Medea';
    src: url('dm-medea.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
    font-display: block;
}

@font-face {
    font-family: 'BPG Irubaqidze';
    src: url('bpg_irubaqidze.otf') format('opentype');
    font-weight: normal;
    font-style: normal;
    font-display: block;
}

/* ==========================================================================
   2. TOKENS
   ========================================================================== */
:root {
    --vh: 1vh;
    --lip: 30px;

    /* Warm papers lifted off the golden-hour light in the artwork: the sunset
       sky's apricot, the gate's honey stone, the hydrangea's creamy white. The
       gate's cool dusty blue stays the ink and the accent, so the page reads
       as the painting's two temperatures rather than a single beige. */
    --paper:   #f7ece0;
    --paper-2: #f1e1cf;
    --paper-3: #ead5bf;
    --cream:   #fcf6ee;

    --ink:      #2f4556;
    --ink-soft: #6c7a86;
    --blue:     #5f7f97;
    --blue-lt:  #b0c0ca;
    --gold:     #c69552;
    --gold-lt:  #e0c095;
    --line:     #e6d3bd;
    --sky:      #e9d3b4;

    --f-display: 'DM Medea', 'BPG Irubaqidze', Georgia, serif;
    --f-body: 'BPG Irubaqidze', Georgia, serif;
    --f-num: 'Cormorant Garamond', Georgia, serif;
    --f-card: 'Noto Serif Georgian', Georgia, serif;
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --t-night: 1.1s ease;
}

/* ==========================================================================
   3. RESET + SCROLLBAR
   ========================================================================== */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* Night mode is mostly colour, so one global transition carries it. CSS does
   not merge transitions: any rule below with its own `transition:` restates
   these colours or it would snap instead of fade. */
*,
*::before,
*::after {
    transition:
        background-color var(--t-night),
        color var(--t-night),
        border-color var(--t-night),
        text-shadow var(--t-night),
        box-shadow var(--t-night);
}

/* Thumb is transparent during the intro and fades in once it hands over. */
html {
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
    transition: scrollbar-color 1.2s ease, background-color var(--t-night);
}

html.is-open {
    scrollbar-color: var(--blue) var(--paper-2);
}

html::-webkit-scrollbar { width: 7px; }
html::-webkit-scrollbar-track { background-color: var(--paper-2); }

html::-webkit-scrollbar-thumb {
    border-radius: 7px;
    background-color: transparent;
    transition: background-color 1.2s ease;
}

html.is-open::-webkit-scrollbar-thumb { background-color: var(--blue); }

/* overscroll-behavior only. NO overflow on body: with overflow-x on body it
   becomes its own scroll box that can never scroll, and a MacBook trackpad
   gesture latches onto that dead box instead of the page. */
html,
body {
    overscroll-behavior-y: none;
}

body {
    background-color: var(--paper);
    color: var(--ink);
    font-family: var(--f-body);
    font-size: 16px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
}

/* Intro scroll lock. NEVER position:fixed / overflow:hidden on the document:
   Chrome iOS opened from a chat app freezes its viewport short. The gesture is
   eaten in JS instead (script.js block 2), wheel and keys included. */
html.is-locked,
html.is-locked body {
    overscroll-behavior: none;
    touch-action: none;
}

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

[hidden] { display: none !important; }

button,
input {
    font: inherit;
    color: inherit;
}

/* ==========================================================================
   4. TOGGLES
   Hidden until html.is-open so neither sits on the gate artwork. Music right,
   night left, same frosted plate so they read as a pair.
   ========================================================================== */
.music-toggle,
.night-toggle {
    position: fixed;
    top: 14px;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    padding: 0;
    border: 1px solid rgba(95, 127, 151, 0.35);
    border-radius: 50%;
    background-color: rgba(252, 246, 238, 0.82);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    box-shadow: 0 4px 16px rgba(120, 86, 52, 0.14);
    cursor: pointer;
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity 1s ease, transform 1s var(--ease-out), background-color var(--t-night), border-color var(--t-night), box-shadow var(--t-night), color var(--t-night);
}

.music-toggle { right: 14px; }
.night-toggle { left: 14px; }

.is-open .music-toggle,
.is-open .night-toggle {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    /* Entrance delayed, colours not: a blanket transition-delay would also hold
       the plate's night fade back by 1.4s. */
    transition: opacity 1s ease 1.4s, transform 1s var(--ease-out) 1.4s, background-color var(--t-night), border-color var(--t-night), box-shadow var(--t-night), color var(--t-night);
}

.music-toggle:active,
.night-toggle:active { transform: scale(0.94); transition: transform 0.15s ease; }

.music-toggle:focus-visible,
.night-toggle:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 3px;
}

/* Four bars that equalise while playing and rest short while paused, so the
   state reads without an icon swap. */
.music-toggle__bars {
    display: flex;
    align-items: flex-end;
    gap: 2.5px;
    height: 15px;
}

.music-toggle__bars span {
    width: 2.5px;
    height: 100%;
    border-radius: 1px;
    background-color: var(--ink);
    transform-origin: bottom center;
    transform: scaleY(0.3);
    transition: transform 0.3s ease, background-color var(--t-night);
}

.music-toggle.playing .music-toggle__bars span { animation: eq 1.15s ease-in-out infinite; }
.music-toggle.playing .music-toggle__bars span:nth-child(2) { animation-delay: -0.76s; }
.music-toggle.playing .music-toggle__bars span:nth-child(3) { animation-delay: -0.38s; }
.music-toggle.playing .music-toggle__bars span:nth-child(4) { animation-delay: -0.95s; }

@keyframes eq {
    0%, 100% { transform: scaleY(0.3); }
    50%      { transform: scaleY(1); }
}

/* Sun: a disc with eight ray dots drawn by one box-shadow. Moon: the disc
   empties and an offset inset shadow re-fills all but a crescent. Both states
   are transitionable values, so the icon morphs instead of swapping. */
.night-toggle__orb {
    position: relative;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background-color: var(--gold);
    box-shadow: inset 0 0 0 0 rgba(0, 0, 0, 0);
    transition: background-color var(--t-night), box-shadow var(--t-night);
}

.night-toggle__orb::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 2px;
    height: 2px;
    margin: -1px 0 0 -1px;
    border-radius: 50%;
    color: var(--gold);
    box-shadow:
        0 -10px currentColor, 0 10px currentColor,
        -10px 0 currentColor, 10px 0 currentColor,
        -7px -7px currentColor, 7px -7px currentColor,
        -7px 7px currentColor, 7px 7px currentColor;
    transition: opacity 0.7s ease, transform 0.7s ease, color var(--t-night);
}

html.night .night-toggle__orb {
    background-color: transparent;
    box-shadow: inset -4.5px 2.5px 0 0 var(--ink);
}

html.night .night-toggle__orb::before {
    opacity: 0;
    transform: scale(0.3);
}

/* ==========================================================================
   5. LOADER
   Out-ranks the entry overlay (10000). Full-bleed fixed with inset: 0 only,
   never a forced height.
   ========================================================================== */
.loader {
    position: fixed;
    inset: 0;
    z-index: 10050;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 22px;
    background-color: var(--paper);
    transition: opacity 0.9s ease;
}

.loader.is-hidden { opacity: 0; pointer-events: none; }
.loader.is-removed { display: none; }

.loader__mark {
    display: flex;
    align-items: baseline;
    gap: 10px;
    font-family: var(--f-display);
    font-size: 42px;
    line-height: 1;
    color: var(--ink);
    animation: breathe 3.4s ease-in-out infinite;
}

.loader__amp {
    font-family: var(--f-body);
    font-size: 22px;
    color: var(--gold);
}

@keyframes breathe {
    0%, 100% { opacity: 0.45; }
    50%      { opacity: 1; }
}

.loader__track {
    position: relative;
    width: 150px;
    height: 2px;
    overflow: hidden;
    border-radius: 2px;
    background-color: var(--line);
}

.loader__bar {
    position: absolute;
    inset: 0;
    transform: scaleX(0);
    transform-origin: left center;
    background-color: var(--blue);
}

.loader__pct {
    font-size: 12px;
    letter-spacing: 0.18em;
    color: var(--ink-soft);
}

/* ==========================================================================
   6. ENTRY
   Poster (the closed gate) under the clip, the clip fades in on its own first
   frame so the still simply starts moving. inset: 0 and nothing else.
   ========================================================================== */
.entry {
    position: fixed;
    inset: 0;
    z-index: 10000;
    overflow: hidden;
    background-color: var(--sky);
    cursor: pointer;
    transition: opacity 1.2s ease;
}

.entry.is-gone { opacity: 0; pointer-events: none; }
.entry.is-removed { display: none; }

.entry__poster,
.entry__clip {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
}

.entry__poster { z-index: 1; }

.entry__clip {
    z-index: 2;
    opacity: 0;
    transition: opacity 0.5s ease;
}

.entry__clip.is-playing { opacity: 1; }

/* A slow breath on the still while it waits, so the guest is looking at a
   living picture rather than a screenshot. Paused behind the loader. */
.entry__poster {
    animation: poster-breathe 9s ease-in-out infinite alternate;
}

.is-loading .entry__poster { animation-play-state: paused; }
.entry.is-rolling .entry__poster { animation: none; }

@keyframes poster-breathe {
    from { transform: scale(1); }
    to   { transform: scale(1.035); }
}

.entry__hint {
    position: absolute;
    left: 50%;
    bottom: calc(var(--vh) * 9);
    z-index: 3;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 20px;
    border-radius: 999px;
    border: 1px solid rgba(252, 246, 238, 0.5);
    background-color: rgba(252, 246, 238, 0.72);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    box-shadow: 0 4px 22px rgba(120, 86, 52, 0.18);
    font-size: 13px;
    letter-spacing: 0.16em;
    color: var(--ink);
    white-space: nowrap;
    transform: translateX(-50%);
    pointer-events: none;
    animation: breathe 3.2s ease-in-out infinite;
    transition: opacity 0.5s ease;
}

.is-loading .entry__hint { animation-play-state: paused; opacity: 0; }

.entry__hint-line {
    display: block;
    width: 20px;
    height: 1px;
    background-color: var(--gold);
}

.entry.is-rolling .entry__hint { opacity: 0; animation: none; }

/* Blocked autoplay rejects play() even inside the gesture: bring the hint back
   so there is something to tap again. */
.entry.is-stalled .entry__hint { opacity: 1; animation: breathe 3.2s ease-in-out infinite; }

/* ==========================================================================
   7. HERO
   ========================================================================== */
/* clip, not hidden: clip never creates a scroll container, so nothing here can
   catch a trackpad gesture meant for the page. */
.page {
    position: relative;
    overflow-x: hidden;
    overflow-x: clip;
}

.hero {
    position: relative;
    display: flex;
    justify-content: center;
    min-height: 100vh;
    min-height: 100svh;
    overflow: hidden;
    background-color: var(--sky);
}

.vh-lock .hero { min-height: calc(var(--vh) * 100); }

/* Held slightly oversized and settling back over nine seconds, so the hand-off
   from the clip has a slow breath out instead of stopping dead. */
.hero__still {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transform: scale(1.04);
    transition: transform 9s cubic-bezier(0.16, 0.8, 0.3, 1), opacity var(--t-night);
}

.is-open .hero__still { transform: scale(1); }

.hero__still--night { opacity: 0; }
html.night .hero__still--night { opacity: 1; }

/* A gradient cannot be transitioned, so the day wash and the night wash are two
   stacked pseudo-elements cross-faded on opacity. Lifts only the band the names
   sit on and leaves the village and the sea alone. */
.hero__veil {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
}

.hero__veil::before,
.hero__veil::after {
    content: '';
    position: absolute;
    inset: 0;
    transition: opacity var(--t-night);
}

.hero__veil::before {
    background-image:
        radial-gradient(ellipse 95% 30% at 50% 22%, rgba(251, 249, 244, 0.78) 0%, rgba(251, 249, 244, 0.36) 55%, rgba(251, 249, 244, 0) 85%);
}

.hero__veil::after {
    opacity: 0;
    background-image:
        radial-gradient(ellipse 95% 30% at 50% 22%, rgba(8, 15, 28, 0.72) 0%, rgba(8, 15, 28, 0.32) 55%, rgba(8, 15, 28, 0) 85%);
}

html.night .hero__veil::before { opacity: 0; }
html.night .hero__veil::after  { opacity: 1; }

.hero__content {
    position: relative;
    z-index: 3;
    width: 100%;
    padding: calc(var(--vh) * 10) 24px 0;
    text-align: center;
}

/* Held at frame one until .is-open, so the names rise as the clip fades off
   them and the two read as one movement. */
.hero__names,
.hero__rule,
.hero__date { opacity: 0; }

.is-open .hero__names   { animation: rise-soft 1.9s var(--ease-out) 0.6s both; }
.is-open .hero__rule    { animation: rule-in 1.5s var(--ease-out) 1.4s both; }
.is-open .hero__date    { animation: rise 1.5s var(--ease-out) 1.7s both; }

@keyframes rise {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
}

/* The names also come out of a soft focus, like the camera settling after the
   push through the gate. */
@keyframes rise-soft {
    from { opacity: 0; transform: translateY(20px) scale(0.97); filter: blur(6px); }
    to   { opacity: 1; transform: none; filter: blur(0); }
}

@keyframes rule-in {
    from { opacity: 0; transform: scaleX(0); }
    to   { opacity: 1; transform: scaleX(1); }
}

.hero__names {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 14px;
    font-family: var(--f-display);
    font-size: 46px;
    white-space: nowrap;
    font-weight: normal;
    line-height: 1.02;
    color: var(--ink);
    text-shadow: 0 2px 18px rgba(251, 249, 244, 0.9), 0 0 6px rgba(251, 249, 244, 0.8);
}

.hero__name { display: block; }

/* Sits on the names' baseline between them, so the pair reads as one line. */
.hero__amp {
    display: block;
    font-family: var(--f-body);
    font-size: 30px;
    line-height: 1;
    color: #a8732f;
    text-shadow: 0 0 12px rgba(251, 249, 244, 1), 0 0 24px rgba(251, 249, 244, 0.9);
}

.hero__rule {
    display: block;
    width: 64px;
    height: 1px;
    margin: 18px auto 0;
    background-color: var(--gold);
}

.hero__date {
    margin-top: 14px;
    font-size: 17px;
    letter-spacing: 0.12em;
    color: var(--ink);
    text-shadow: 0 0 10px rgba(251, 249, 244, 0.95), 0 0 22px rgba(251, 249, 244, 0.8);
}

/* ==========================================================================
   8. SCROLL CUE
   Two chevrons on a frosted ring. The hero looks finished at the fold, so motion
   is the only thing telling the guest there is more. Fades out on first scroll.
   ========================================================================== */
.cue {
    position: absolute;
    left: 50%;
    bottom: calc(var(--lip) + 22px);
    z-index: 4;
    width: 40px;
    height: 40px;
    margin-left: -20px;
    border-radius: 50%;
    background-color: rgba(252, 246, 238, 0.78);
    -webkit-backdrop-filter: blur(7px);
    backdrop-filter: blur(7px);
    box-shadow: 0 3px 16px rgba(120, 86, 52, 0.16);
    opacity: 0;
    pointer-events: none;
    transition: opacity 1.1s ease, background-color var(--t-night), box-shadow var(--t-night);
}

.is-open .cue {
    opacity: 1;
    transition: opacity 1.1s ease 2.6s, background-color var(--t-night), box-shadow var(--t-night);
}

.is-open.is-scrolled .cue {
    opacity: 0;
    transition: opacity 0.6s ease, background-color var(--t-night), box-shadow var(--t-night);
}

.cue__chev {
    position: absolute;
    left: 50%;
    top: 11px;
    width: 9px;
    height: 9px;
    margin-left: -4.5px;
    border-right: 1.5px solid var(--ink);
    border-bottom: 1.5px solid var(--ink);
    transform: rotate(45deg);
    animation: chev 2.4s ease-in-out infinite;
}

.cue__chev--2 { top: 18px; animation-delay: 0.3s; }

@keyframes chev {
    0%, 100% { opacity: 0.25; transform: translateY(-2px) rotate(45deg); }
    50%      { opacity: 1; transform: translateY(2px) rotate(45deg); }
}

/* ==========================================================================
   9. SHEETS + REVEAL
   Every section below the hero is a sheet laid over the one before it: rounded
   lip, upward shadow, negative margin. Paint order is DOM order, later on top.
   ========================================================================== */
.sheet {
    position: relative;
    z-index: 2;
    margin-top: calc(var(--lip) * -1);
    padding: 58px 24px 64px;
    border-top-left-radius: var(--lip);
    border-top-right-radius: var(--lip);
    background-color: var(--paper);
    box-shadow: 0 -14px 34px rgba(120, 86, 52, 0.14);
}

/* Light catching the lip, so the fold reads where two papers are near-equal. */
.sheet::before {
    content: '';
    position: absolute;
    top: 0;
    left: 12%;
    right: 12%;
    height: 1px;
    background-color: rgba(255, 255, 255, 0.85);
}

.sheet--alt   { background-color: var(--paper-2); }
.sheet--note  { background-color: var(--cream); }
.sheet--dress { background-color: var(--cream); }
.sheet--rsvp  { background-color: var(--paper); }
.sheet--foot  { background-color: var(--paper-3); }

.sheet__inner {
    width: 100%;
    max-width: 380px;
    margin: 0 auto;
    text-align: center;
}

.sheet__title {
    font-family: var(--f-display);
    font-size: 29px;
    font-weight: normal;
    /* DM Medea's descenders hang far below its em box; without the extra
       leading the rule underneath runs through them. */
    line-height: 1.45;
    padding-bottom: 14px;
    color: var(--ink);
}

/* Grows out of the centre once the heading lands, which ties it to the title
   rather than reading as a divider that was already there. */
.sheet__rule {
    display: block;
    width: 56px;
    height: 1px;
    margin: 12px auto 0;
    background-color: var(--gold);
}

/* --i is set per element by script.js so siblings in one sheet arrive one
   after another rather than as a block. The stagger rides on opacity and
   transform only; the night colours keep their own undelayed fade. */
.reveal {
    --d: calc(var(--i, 0) * 90ms);
    opacity: 0;
    transform: translateY(22px);
    transition: opacity 1.2s ease var(--d), transform 1.3s var(--ease-out) var(--d), background-color var(--t-night), color var(--t-night), border-color var(--t-night), text-shadow var(--t-night), box-shadow var(--t-night);
}

.reveal.is-in { opacity: 1; transform: none; }

/* The rule animates scaleX, so it must not inherit the translate reveal. */
.sheet__rule.reveal { --d: calc(var(--i, 0) * 90ms + 0.25s); transform: scaleX(0); }
.sheet__rule.reveal.is-in { transform: scaleX(1); }


/* ==========================================================================
   10. COUNTDOWN
   ========================================================================== */
.cd {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    margin-top: 34px;
}

.cd__unit {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

/* Hairlines between units instead of four boxes: the numbers carry it. */
.cd__unit + .cd__unit { border-left: 1px solid var(--line); }

.cd__num {
    font-family: var(--f-num);
    font-weight: 500;
    font-size: 44px;
    line-height: 1;
    font-variant-numeric: lining-nums tabular-nums;
    color: var(--ink);
}

.cd__label {
    font-size: 12px;
    letter-spacing: 0.14em;
    color: var(--ink-soft);
}

.cd__date {
    margin-top: 30px;
    font-size: 15px;
    letter-spacing: 0.14em;
    color: var(--blue);
}

/* ==========================================================================
   11. NOTE
   ========================================================================== */
/* A small sprig of three dots in the hydrangea's cluster shape, instead of a
   flourish glyph: enough to mark the head of a letter. */
.note__mark {
    position: relative;
    display: block;
    width: 8px;
    height: 8px;
    margin: 0 auto 22px;
    border-radius: 50%;
    background-color: var(--gold-lt);
    box-shadow: -12px 6px 0 -1px var(--gold-lt), 12px 6px 0 -1px var(--gold-lt);
}

.note__salut {
    font-family: var(--f-display);
    font-size: 22px;
    line-height: 1.5;
    color: var(--blue);
}

.note__body p {
    margin-top: 16px;
    font-size: 17px;
    line-height: 1.8;
    color: var(--ink);
}

.note__sign {
    margin-top: 26px;
    font-family: var(--f-display);
    font-size: 21px;
    line-height: 1.5;
    color: var(--ink);
}

/* ==========================================================================
   12. TIMETABLE
   Card layout taken one-to-one from salome-giga's event-card (same structure,
   paddings, radius, type sizes and rhythm), recoloured to this site's tokens:
   its --teal is our --blue, its --rule our --gold-lt, its card paper our cream.
   ========================================================================== */
/* Ruled either side, so the date reads as a divider over the cards rather than
   a heading belonging to the first one. */
.day-header {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    margin: 26px 0 30px;
}

.day-header::before,
.day-header::after {
    content: '';
    width: 28px;
    height: 1px;
    background-color: var(--gold-lt);
}

.day-date {
    font-size: 17px;
    letter-spacing: 0.2em;
    color: var(--blue);
}

.events-cards {
    display: flex;
    flex-direction: column;
    gap: 40px;
}

/* overflow: hidden clips the bled painting to the card's rounded corners. */
.event-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    overflow: hidden;
    /* clip, not hidden: hidden makes this a scroll container and the painting's
       view() parallax would track it instead of the page. */
    overflow: clip;
    padding: 40px 32px 36px;
    border: 1px solid var(--line);
    border-radius: 32px;
    background-color: var(--cream);
    text-align: center;
    opacity: 0;
    transform: translateY(28px);
    transition: opacity 1.1s ease, transform 1.3s var(--ease-out), background-color var(--t-night), border-color var(--t-night), color var(--t-night);
}

.event-card.is-lit { opacity: 1; transform: none; }

/* Pulled out past the card's padding so the painting runs edge to edge, shown
   at its natural (square) size like the reference. */
.event-card__img {
    position: relative;
    width: calc(100% + 64px);
    margin: -40px -32px 24px;
    overflow: hidden;
    overflow: clip;
}

.event-card__img img {
    display: block;
    width: 100%;
    height: auto;
    opacity: 0.9;
    transition: opacity var(--t-night);
}

/* The night painting is stacked on the day one, so the card's height never
   changes when the page goes dark. */
.event-card__img .event-card__night {
    position: absolute;
    inset: 0;
    height: 100%;
    object-fit: cover;
    opacity: 0;
}

html.night .event-card__img .event-card__night { opacity: 0.9; }

/* Painting fades into the card. Day and night bands cross-fade because a
   gradient cannot transition. */
.event-card__img::before,
.event-card__img::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    height: 16%;
    pointer-events: none;
    transition: opacity var(--t-night);
}

.event-card__img::after  { background-image: linear-gradient(to bottom, rgba(252, 246, 238, 0), #fcf6ee); }
.event-card__img::before { opacity: 0; background-image: linear-gradient(to bottom, rgba(20, 34, 54, 0), #142236); }

html.night .event-card__img::after  { opacity: 0; }
html.night .event-card__img::before { opacity: 1; }

.event-card__label {
    margin-bottom: 16px;
    font-family: var(--f-card);
    font-weight: 500;
    font-size: 16px;
    line-height: 1.6;
    letter-spacing: 0.28em;
    color: var(--blue);
}

.event-card__venue {
    margin-bottom: 10px;
    font-family: var(--f-display);
    font-size: 18px;
    font-weight: normal;
    line-height: 2.4;
    letter-spacing: 0.01em;
    color: var(--ink);
}

.event-card__addr {
    margin-bottom: 20px;
    font-family: var(--f-card);
    font-size: 15px;
    line-height: 1.5;
    letter-spacing: 0.03em;
    color: var(--ink-soft);
}

.event-card__rule {
    width: 40px;
    height: 1px;
    margin: 0 auto 20px;
    background-color: var(--gold-lt);
}

.event-card__time {
    margin-bottom: 22px;
    font-family: var(--f-num);
    font-weight: 500;
    font-size: 34px;
    line-height: 1;
    letter-spacing: 0.02em;
    font-variant-numeric: lining-nums tabular-nums;
    color: var(--blue);
}

.event-card__map {
    padding-bottom: 2px;
    font-family: var(--f-card);
    border-bottom: 1px solid var(--gold-lt);
    font-size: 12px;
    letter-spacing: 0.28em;
    color: var(--ink);
    text-decoration: none;
    transition: color 0.2s ease, border-color 0.2s ease;
}

.event-card__map:hover,
.event-card__map:focus-visible {
    color: var(--blue);
    border-color: var(--blue);
}

/* ==========================================================================
   13. DRESS CODE
   ========================================================================== */
.dress__value {
    margin-top: 22px;
    font-family: var(--f-display);
    font-size: 26px;
    line-height: 1.5;
    color: var(--blue);
}

.dress__note {
    max-width: 300px;
    margin: 12px auto 0;
    font-size: 16px;
    line-height: 1.7;
    color: var(--ink-soft);
}

/* ==========================================================================
   14. RSVP
   ========================================================================== */
.rsvp__lead {
    margin-top: 16px;
    font-size: 16px;
    line-height: 1.7;
    color: var(--ink-soft);
}

.rsvp {
    margin-top: 28px;
    text-align: left;
}

.field + .field,
.field + .choice,
.choice + .choice { margin-top: 20px; }

.field__label {
    display: block;
    margin-bottom: 8px;
    font-size: 14px;
    letter-spacing: 0.04em;
    color: var(--ink);
}

.field__input {
    display: block;
    width: 100%;
    height: 50px;
    padding: 0 16px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background-color: var(--cream);
    font-size: 16px;
    outline: none;
    transition: border-color 0.3s ease, background-color var(--t-night), color var(--t-night);
}

.field__input::placeholder { color: #a3968a; }

.field__input:focus { border-color: var(--blue); }

.choice {
    border: 0;
    min-width: 0;
}

.choice__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

.choice__row--four { grid-template-columns: repeat(4, 1fr); }

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

.choice__box {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 48px;
    padding: 0 8px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background-color: var(--cream);
    font-size: 15px;
    text-align: center;
    cursor: pointer;
    transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease, transform 0.15s ease;
}

.choice__opt:active .choice__box { transform: scale(0.97); }

.choice__opt input:focus-visible + .choice__box {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

.choice__opt input:checked + .choice__box {
    border-color: var(--ink);
    background-color: var(--ink);
    color: var(--cream);
}

/* Head count is meaningless for a "no": collapses rather than disappears. */
#guest-count-group {
    max-height: 140px;
    overflow: hidden;
    transition: max-height 0.5s ease, opacity 0.5s ease, margin-top 0.5s ease, transform 1.3s var(--ease-out), color var(--t-night);
}

#guest-count-group.is-hidden {
    max-height: 0;
    margin-top: 0;
    opacity: 0;
}

.rsvp__submit {
    display: block;
    width: 100%;
    height: 54px;
    margin-top: 28px;
    border: 0;
    border-radius: 999px;
    background-color: var(--blue);
    color: var(--cream);
    font-size: 16px;
    letter-spacing: 0.1em;
    cursor: pointer;
    transition: opacity 1.2s ease var(--d), transform 1.3s var(--ease-out) var(--d), background-color 0.3s ease, color var(--t-night);
}

.rsvp__submit:active { transform: scale(0.98); }
.rsvp__submit:disabled { opacity: 0.6; cursor: default; }

.rsvp__status {
    min-height: 24px;
    margin-top: 14px;
    font-size: 14px;
    text-align: center;
    color: var(--ink-soft);
}

.rsvp__thanks {
    margin-top: 30px;
    padding: 32px 22px;
    border: 1px solid var(--line);
    border-radius: 24px;
    background-color: var(--cream);
    animation: rise 1s var(--ease-out) both;
}

.rsvp__thanks-title {
    font-family: var(--f-display);
    font-size: 26px;
    line-height: 1.5;
    color: var(--blue);
}

.rsvp__thanks-body {
    margin-top: 8px;
    font-size: 16px;
    color: var(--ink);
}

/* ==========================================================================
   15. FOOTER
   ========================================================================== */
.sheet--foot {
    padding-bottom: calc(40px + env(safe-area-inset-bottom));
    text-align: center;
}

.foot__lead {
    font-size: 15px;
    letter-spacing: 0.06em;
    color: var(--ink-soft);
}

.foot__names {
    margin-top: 6px;
    font-family: var(--f-display);
    font-size: 32px;
    line-height: 1.5;
    color: var(--ink);
}

.foot__names span {
    font-family: var(--f-body);
    font-size: 24px;
    color: var(--gold);
}

.credit {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 34px;
    font-family: 'BPG Irubaqidze', sans-serif;
    font-size: 12px;
    color: var(--ink);
    text-decoration: none;
    opacity: 0.3;
    transition: opacity 0.3s ease, color var(--t-night);
}

.credit:hover,
.credit:focus-visible { opacity: 0.75; }

/* The logo ships gold; filtered to the page's slate ink so it belongs here. */
.credit__logo {
    width: 26px;
    height: auto;
    filter: brightness(0) saturate(100%) invert(24%) sepia(16%) saturate(1100%) hue-rotate(163deg) brightness(92%);
}

/* ==========================================================================
   16. NIGHT MODE
   The same village after dark, so the page is coloured to match the night
   paintings: the ground is their sky, the gold their lamplight. Mostly the token
   block restated on html.night; only baked rgba plates follow.
   ========================================================================== */
html.night {
    --paper:   #0f1a2a;
    --paper-2: #0c1624;
    --paper-3: #09111d;
    --cream:   #142236;

    --ink:      #e4ecf3;
    --ink-soft: #95a9bc;
    --blue:     #a7c6dc;
    --blue-lt:  #3d5a72;
    --gold:     #dcb26b;
    --gold-lt:  #8e7246;
    --line:     #263a52;
    --sky:      #0f1a2a;
}

html.night .music-toggle,
html.night .night-toggle,
html.night .cue {
    border-color: rgba(220, 178, 107, 0.35);
    background-color: rgba(15, 26, 42, 0.82);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
}

html.night .hero__date { text-shadow: 0 0 12px rgba(8, 15, 28, 0.95), 0 0 24px rgba(8, 15, 28, 0.7); }
html.night .hero__names { text-shadow: 0 2px 18px rgba(8, 15, 28, 0.9), 0 0 6px rgba(8, 15, 28, 0.8); }
html.night .hero__amp { color: var(--gold); text-shadow: 0 0 12px rgba(8, 15, 28, 0.95), 0 0 24px rgba(8, 15, 28, 0.8); }

html.night .sheet { box-shadow: 0 -14px 34px rgba(0, 0, 0, 0.5); }
html.night .sheet::before { background-color: rgba(255, 255, 255, 0.07); }


html.night .field__input::placeholder { color: #6c8197; }

/* Filled controls take the lamplight gold at night: --ink is near-white after
   dark and would turn them into the brightest slabs on the page. */
html.night .choice__opt input:checked + .choice__box {
    border-color: var(--gold);
    background-color: var(--gold);
    color: #101b2b;
}

html.night .rsvp__submit {
    background-color: var(--gold);
    color: #101b2b;
}

html.night .credit__logo {
    filter: brightness(0) saturate(100%) invert(93%) sepia(8%) saturate(300%) hue-rotate(180deg);
}

/* ==========================================================================
   16b. PARALLAX
   Deliberately faint: depth, not motion sickness. Built on CSS scroll-driven
   animations, never a JS scroll handler, and animated on the standalone
   `translate` property so it composes with the `transform` the reveals and the
   hero settle already own instead of fighting them.

   Hero: driven by the document's own scroll over a FIXED 0-900px range, not a
   viewport-relative one. Chrome iOS resizes its toolbar mid-scroll and any
   range measured in viewport units would re-map under the guest's thumb; a
   pixel range does not move, so this one is safe everywhere.

   Painting drift + title float: view() timelines ARE viewport-relative, so
   they are switched off under html.is-ios (set in script.js) for the reason
   above. Browsers without scroll-driven animations simply get a still page.
   ========================================================================== */
@supports (animation-timeline: scroll()) {
    /* The painting sinks slower than the page, so the village sits behind the
       sheet that slides over it. Gap opens only above the fold, never in view. */
    .hero__still {
        animation: px-hero linear both;
        animation-timeline: scroll(root);
        animation-range: 0px 900px;
    }

    @keyframes px-hero {
        from { translate: 0 0; }
        to   { translate: 0 110px; }
    }

    /* The names lag a touch behind the picture, a second plane of depth. */
    .hero__content {
        animation: px-hero-type linear both;
        animation-timeline: scroll(root);
        animation-range: 0px 900px;
    }

    @keyframes px-hero-type {
        from { translate: 0 0; }
        to   { translate: 0 60px; }
    }

    html:not(.is-ios) .event-card__img img {
        scale: 1.08;
        animation: px-card linear both;
        animation-timeline: view();
        animation-range: cover;
    }

    @keyframes px-card {
        from { translate: 0 -3.5%; }
        to   { translate: 0 3.5%; }
    }

    html:not(.is-ios) .sheet__title {
        animation: px-title linear both;
        animation-timeline: view();
        animation-range: cover;
    }

    @keyframes px-title {
        from { translate: 0 10px; }
        to   { translate: 0 -10px; }
    }
}

/* ==========================================================================
   17. BREAKPOINTS
   ========================================================================== */
@media (min-width: 481px) {
    .hero__names  { font-size: 54px; }
    .sheet__title { font-size: 32px; }
    .cd__num      { font-size: 48px; }
    .sheet__inner { max-width: 400px; }
}

/* Laptop: the invitation becomes a phone-width column over a blurred, dimmed
   copy of the hero. The document still scrolls natively, so a trackpad or
   wheel moves the page exactly as on a phone. The fixed overlays are pinned to
   the same column. */
@media (min-width: 769px) {
    :root { --col: 440px; }

    body { background-color: #1b2531; }

    body::before,
    body::after {
        content: '';
        position: fixed;
        inset: -40px;
        z-index: 0;
        background: url('hero.jpg') center / cover no-repeat;
        filter: blur(28px) brightness(0.62) saturate(1.1);
        pointer-events: none;
        transition: opacity var(--t-night);
    }

    body::after {
        background-image: url('hero-night.jpg');
        opacity: 0;
    }

    html.night body::after { opacity: 1; }

    .page {
        z-index: 1;
        width: var(--col);
        margin: 0 auto;
        box-shadow: 0 0 80px rgba(0, 0, 0, 0.45);
    }

    .entry {
        left: calc(50% - var(--col) / 2);
        right: auto;
        width: var(--col);
    }

    .music-toggle { right: calc(50% - var(--col) / 2 + 14px); }
    .night-toggle { left: calc(50% - var(--col) / 2 + 14px); }

    .hero__names { font-size: 52px; }
}

/* ==========================================================================
   18. REDUCED MOTION
   Loops go; reveals become instant rather than disabled, so nothing is left at
   opacity 0.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    .loader__mark,
    .entry__poster,
    .entry__hint,
    .cue__chev,
    .music-toggle.playing .music-toggle__bars span {
        animation: none !important;
    }

    .is-open .hero__names,
    .is-open .hero__rule,
    .is-open .hero__date {
        animation: none !important;
        opacity: 1;
    }

    .hero__still { transform: none !important; }

    .hero__still,
    .hero__content,
    .event-card__img img,
    .sheet__title {
        animation: none !important;
        translate: none !important;
        scale: none !important;
    }

    .reveal,
    .event-card {
        transition-duration: 0.01ms !important;
        transition-delay: 0s !important;
    }
}
