/* ==========================================================================
   The Extraordinary — invitation deck
   Palette and type are tuned to the printed invitation (PDF pages 7–12).
   ========================================================================== */

:root {
    /* Ground */
    --ink-deep:      #3a080c;
    --ink:           #4a0d11;

    /* Gold */
    --gold-bright:   #fbe7bd;
    --gold:          #e8c68a;
    --gold-mid:      #d7a662;
    --gold-deep:     #c08a45;
    --gold-body:     #dcae72;
    --gold-muted:    #cfa065;

    /* Type */
    --serif: "Cormorant Garamond", Cormorant, Garamond, "Adobe Garamond Pro",
             "Times New Roman", Times, serif;

    /* Fallback backdrop shown until the artwork is dropped into /assets/img */
    --panel-fallback:
        radial-gradient(120% 85% at 50% 40%, #5c1116 0%, #430b10 45%, #2e0508 100%);

    --measure: 34rem;      /* copy column width */
}

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

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
}

body.invite {
    margin: 0;
    background-color: #240406;
    background-image: radial-gradient(120% 70% at 50% 0%, #350709 0%, #1d0305 70%);
    color: var(--gold-body);
    font-family: var(--serif);
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* --------------------------------------------------------------------------
   Language switch — a sticky two-segment toggle at the top of the card
   -------------------------------------------------------------------------- */

/* Bottom-right, not top: the panels' headings sit high on the card now, and
   a fixed control at the top clipped them as they scrolled under it. */
.langswitch {
    position: fixed;
    bottom: clamp(1rem, 3vh, 1.75rem);
    left: 50%;
    z-index: 50;
    display: flex;
    justify-content: flex-end;
    width: 100%;
    max-width: 500px;          /* the same column as .deck */
    padding-left: clamp(1rem, 5vw, 1.5rem);
    padding-right: clamp(1rem, 5vw, 1.5rem);
    transform: translateX(-50%);
    transition: opacity 1.2s ease;
    pointer-events: none;      /* only the track takes clicks */
}

/* Out of the way until the opening animation has finished. */
.intro-lock .langswitch {
    opacity: 0;
    pointer-events: none;
}

/* While the other language is on its way. assets/js/lang.js fetches it rather
   than reloading the page, which is usually over in a blink — this is only so
   that a slow connection shows something, and so a second tap cannot land
   mid-swap. */
.langswitch.is-busy .langswitch__track {
    opacity: 0.55;
    pointer-events: none;
    transition: opacity 0.2s ease;
}

.langswitch__track {
    display: inline-flex;
    padding: 4px;
    border: 1px solid rgba(233, 196, 134, 0.5);
    border-radius: 999px;
    background: rgba(26, 4, 6, 0.72);
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.5);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    pointer-events: auto;
}

.langswitch__opt {
    padding: 0.55em 1.2em;
    border-radius: 999px;
    color: var(--gold);
    font-size: clamp(0.82rem, 3.2vw, 0.95rem);
    font-weight: 600;
    letter-spacing: 0.16em;
    text-indent: 0.16em;       /* balance the trailing letter-space */
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.35s ease, color 0.35s ease;
}

.langswitch__opt:hover,
.langswitch__opt:focus-visible {
    color: var(--gold-bright);
}

/* The chosen side reads as the thrown half of a switch. */
.langswitch__opt.is-active {
    background: linear-gradient(180deg, var(--gold-bright) 0%, var(--gold-mid) 100%);
    color: #2b0508;
}

.langswitch__opt.is-active:hover,
.langswitch__opt.is-active:focus-visible {
    color: #2b0508;
}

/* --------------------------------------------------------------------------
   Deck — on anything wider than a phone the whole invitation stays a 500px
   portrait card, centred on a dark stage, so it keeps the proportions of the
   printed piece instead of stretching across the screen.
   -------------------------------------------------------------------------- */

.deck {
    position: relative;
    width: 100%;
    max-width: 500px;
    margin: 0 auto;
    box-shadow: 0 0 90px rgba(0, 0, 0, 0.55);
}

/* --------------------------------------------------------------------------
   Panel — one printed page, one screen
   -------------------------------------------------------------------------- */

.panel {
    position: relative;
    display: flex;
    min-height: 100vh;
    min-height: 100svh;
    isolation: isolate;
    overflow: hidden;
}

.panel__bg {
    position: absolute;
    inset: 0;
    z-index: -2;
    background-color: var(--ink);
    background-image: var(--panel-bg), var(--panel-fallback);
    background-repeat: no-repeat;
    background-position: center center;
    background-size: cover;
}

/* Soft scrim so the copy holds up over the brighter ribbon artwork. */
.panel__inner::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: radial-gradient(
        68% 52% at 50% 50%,
        rgba(38, 6, 9, 0.55) 0%,
        rgba(38, 6, 9, 0.30) 55%,
        rgba(38, 6, 9, 0) 100%
    );
    pointer-events: none;
}

.panel__inner {
    position: relative;
    display: flex;
    flex: 1;
    justify-content: center;
    width: 100%;
    padding: clamp(2.75rem, 7.5vh, 5rem) clamp(1.25rem, 7vw, 3rem);
}

.panel--align-center .panel__inner { align-items: center; }
.panel--align-top    .panel__inner { align-items: flex-start; }

.panel__copy {
    width: 100%;
    min-width: 0;
    max-width: var(--measure);
    margin: 0 auto;
    text-align: center;
}

/* --------------------------------------------------------------------------
   Typography
   -------------------------------------------------------------------------- */

.panel__copy > * { margin: 0; }

/* Gold leaf treatment shared by every display line. */
.eyebrow,
.display,
.heading,
.lede,
.label,
.value,
.footnote {
    background-image: linear-gradient(
        175deg,
        var(--gold-bright) 0%,
        var(--gold) 34%,
        var(--gold-mid) 62%,
        var(--gold-deep) 88%,
        #e3bd80 100%
    );
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    filter: drop-shadow(0 0 22px rgba(255, 186, 104, 0.22));
}

.value,
.footnote,
.body,
.note {
    font-variant-numeric: lining-nums;
    font-feature-settings: "lnum" 1;
}

.eyebrow {
    font-size: clamp(0.72rem, 2.85vw, 0.92rem);
    font-weight: 500;
    line-height: 1.85;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    margin-bottom: clamp(1.4rem, 4.5vh, 2.4rem);
}

.display {
    font-size: clamp(2.05rem, 8.9vw, 2.6rem);
    font-weight: 400;
    line-height: 1.04;
    letter-spacing: 0.055em;
    text-transform: uppercase;
    margin-bottom: clamp(1.5rem, 4.4vh, 2.3rem);
    filter: drop-shadow(0 0 30px rgba(255, 190, 110, 0.32));
}

.display__line { display: block; }
.display .display__line:first-child { font-size: 0.88em; }
.display--single {
    font-size: clamp(2.4rem, 10vw, 3.1rem);
    margin-bottom: clamp(1rem, 2.8vh, 1.6rem);
}

.display--single .display__line:first-child { font-size: 1em; }

.heading {
    font-size: clamp(1.55rem, 6.4vw, 2.35rem);
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

.lede {
    font-size: clamp(1rem, 4vw, 1.3rem);
    font-weight: 400;
    line-height: 1.55;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    margin-bottom: clamp(1.5rem, 4.5vh, 2.25rem);
}

.label {
    font-size: clamp(0.72rem, 2.7vw, 0.9rem);
    font-weight: 500;
    line-height: 1.6;
    letter-spacing: 0.21em;
    text-transform: uppercase;
    opacity: 0.92;
}

.label--lg {
    font-size: clamp(0.82rem, 3.1vw, 1.02rem);
    letter-spacing: 0.19em;
}

.value {
    font-size: clamp(1.45rem, 6vw, 2.05rem);
    font-weight: 400;
    line-height: 1.3;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-top: 0.15em;
}

.value + .label { margin-top: clamp(1.1rem, 3.2vh, 1.7rem); }

.value--lg { font-size: clamp(1.7rem, 7vw, 2.4rem); }
.value--xl { font-size: clamp(2rem, 8.2vw, 2.75rem); }

/* "View on Google Maps" under a detail. Flat gold and small caps rather than
   the gradient the values carry: it is somewhere to tap, not another line of
   the invitation, and it must not pull the eye off DUBAI above it. */
.map-link {
    margin-top: clamp(0.55rem, 1.7vh, 0.85rem);
}

.map-link a {
    display: inline-flex;
    align-items: center;
    gap: 0.55em;
    font-size: clamp(0.62rem, 2.45vw, 0.79rem);
    font-weight: 500;
    line-height: 1.6;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gold-muted);
    text-decoration: none;
    text-shadow: 0 0 22px rgba(255, 182, 100, 0.18);
    border-bottom: 1px solid rgba(207, 160, 101, 0.45);
    padding-bottom: 0.3em;
    transition: color 0.35s ease, border-color 0.35s ease;
}

.map-link a:hover,
.map-link a:focus-visible {
    color: var(--gold-bright);
    border-bottom-color: rgba(251, 231, 189, 0.72);
}

.map-link__pin {
    width: 1.15em;
    height: 1.15em;
    flex: none;
}

/* Letter-spacing leaves a gap after the last letter; pull the rule back in so
   it ends with the text instead of trailing past it. */
.map-link__text { margin-right: -0.18em; }

/* The link stands in for the value when it comes to spacing the next detail. */
.map-link + .label { margin-top: clamp(1.1rem, 3.2vh, 1.7rem); }

/* Running copy keeps a flat gold — no gradient — exactly as printed. */
.body,
.note {
    font-size: clamp(1rem, 4.1vw, 1.22rem);
    font-weight: 400;
    line-height: 1.62;
    letter-spacing: 0.012em;
    color: var(--gold-body);
    text-shadow: 0 0 26px rgba(255, 182, 100, 0.16);
}

.body + .body { margin-top: clamp(1.4rem, 4vh, 2.1rem); }

.note {
    font-size: clamp(0.94rem, 3.7vw, 1.1rem);
    line-height: 1.66;
    color: var(--gold-muted);
}

.footnote {
    font-size: clamp(0.6rem, 2.35vw, 0.78rem);
    font-weight: 500;
    line-height: 1.7;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin-top: clamp(1.8rem, 5vh, 2.75rem);
}

sup {
    font-size: 0.5em;
    line-height: 0;
    vertical-align: super;
    letter-spacing: 0.02em;
}

/* --------------------------------------------------------------------------
   The invitation carries the most copy of any panel — compress its rhythm
   so the whole card still lands inside a single phone screen.
   -------------------------------------------------------------------------- */

.panel--invitation .panel__inner {
    padding-top: clamp(2rem, 5vh, 3.5rem);
    padding-bottom: clamp(2rem, 5vh, 3.5rem);
}

.panel--invitation .eyebrow  { margin-bottom: clamp(1rem, 2.8vh, 1.7rem); }
.panel--invitation .display  { margin-bottom: clamp(1rem, 2.8vh, 1.6rem); }
.panel--invitation .divider  { margin: clamp(0.8rem, 2.1vh, 1.3rem) auto; }

.panel--invitation .value + .label { margin-top: clamp(0.7rem, 1.9vh, 1.1rem); }

.panel--invitation .value     { font-size: clamp(1.35rem, 5.5vw, 1.9rem); }
.panel--invitation .value--lg { font-size: clamp(1.6rem, 6.5vw, 2.2rem); }
.panel--invitation .note      { font-size: clamp(0.88rem, 3.4vw, 1.02rem); }

/* --------------------------------------------------------------------------
   The closing panels sit high on the page, clear of the ribbon work that
   sweeps across the lower half of their artwork — but not flush to the top.
   -------------------------------------------------------------------------- */

.panel--dress-code .panel__inner,
.panel--entertainment .panel__inner {
    padding-top: clamp(1.5rem, 4vh, 2.5rem);
}

.panel--food-beverage .panel__inner {
    padding-top: clamp(2.25rem, 8.5vh, 4.75rem);
}

.panel--privacy .panel__inner {
    padding-top: clamp(3rem, 11vh, 6rem);
}

/* The longest heading of the deck — set a little smaller so it sits calmly. */
.panel--privacy .heading {
    font-size: clamp(1.3rem, 5.4vw, 2rem);
}

/* The RSVP form is the tallest block in the deck and bg-rsvp.jpg only leaves
   a clear band across its middle, so the form starts high and carries a
   deeper scrim (below) to stay readable where it crosses the ribbons. */
.panel--rsvp .panel__inner {
    padding-top: clamp(2.5rem, 7vh, 4rem);
}

.panel--rsvp .panel__inner::before {
    background: radial-gradient(
        82% 74% at 50% 52%,
        rgba(24, 3, 5, 0.88) 0%,
        rgba(24, 3, 5, 0.72) 42%,
        rgba(24, 3, 5, 0.44) 70%,
        rgba(24, 3, 5, 0.12) 88%,
        rgba(24, 3, 5, 0) 100%
    );
}

/* --------------------------------------------------------------------------
   Phone viewports

   On a phone `vh` is the LARGE viewport — the height the page would have if
   the browser's address bar were hidden — so every vh padding above computes
   taller than the screen actually is and the copy sits lower than it does on
   a desktop preview. `svh` is the small (visible) viewport, which is what
   these paddings actually mean.

   Re-declared here rather than edited above so a browser without svh keeps
   the vh values instead of losing the padding altogether. This block sits
   before the desktop media query, which still wins on wide screens (where
   svh and vh are the same anyway).
   -------------------------------------------------------------------------- */

@supports (height: 100svh) {
    .panel__inner {
        padding-top: clamp(2.75rem, 7.5svh, 5rem);
        padding-bottom: clamp(2.75rem, 7.5svh, 5rem);
    }

    .panel--invitation .panel__inner {
        padding-top: clamp(2rem, 5svh, 3.5rem);
        padding-bottom: clamp(2rem, 5svh, 3.5rem);
    }

    .panel--dress-code .panel__inner,
    .panel--entertainment .panel__inner {
        padding-top: clamp(1.5rem, 4svh, 2.5rem);
    }

    .panel--food-beverage .panel__inner {
        padding-top: clamp(2.25rem, 8.5svh, 4.75rem);
    }

    .panel--privacy .panel__inner {
        padding-top: clamp(3rem, 11svh, 6rem);
    }

    .panel--rsvp .panel__inner {
        padding-top: clamp(2.5rem, 7svh, 4rem);
    }
}

/* --------------------------------------------------------------------------
   Divider — gold rule with the four-point star
   -------------------------------------------------------------------------- */

.divider {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: clamp(0.6rem, 2.4vw, 0.95rem);
    width: min(100%, 17rem);
    margin: clamp(1.35rem, 3.9vh, 2.1rem) auto;
}

.divider--lg { width: min(100%, 22rem); }

.divider__line {
    flex: 1;
    height: 1px;
    background: linear-gradient(
        90deg,
        rgba(216, 166, 98, 0) 0%,
        rgba(233, 196, 134, 0.85) 50%,
        rgba(216, 166, 98, 0) 100%
    );
}

.divider__star {
    flex: none;
    width: clamp(0.85rem, 3.2vw, 1.05rem);
    height: clamp(0.85rem, 3.2vw, 1.05rem);
    fill: var(--gold-bright);
    filter: drop-shadow(0 0 8px rgba(255, 199, 124, 0.65));
}

/* --------------------------------------------------------------------------
   RSVP form — name and headcount, posted by assets/js/rsvp.js
   -------------------------------------------------------------------------- */

.rsvp {
    display: flex;
    flex-direction: column;
    gap: clamp(0.9rem, 2.6vh, 1.35rem);
    margin-top: clamp(1.1rem, 3.4vh, 1.8rem);
    text-align: center;
}

.rsvp__field {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
}

/* `display: flex` above would otherwise beat the UA rule for [hidden], which
   is how rsvp.js takes the headcount away from a guest who cannot come. */
.rsvp__field[hidden] {
    display: none;
}

.rsvp__label {
    font-size: clamp(0.62rem, 2.4vw, 0.76rem);
    font-weight: 500;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--gold-muted);
}

.rsvp__control {
    width: 100%;
    padding: 0.5em 0.3em;
    border: 0;
    border-bottom: 1px solid rgba(233, 196, 134, 0.4);
    border-radius: 0;
    background: transparent;
    color: var(--gold);
    font-family: inherit;
    font-size: clamp(1rem, 4vw, 1.18rem);
    font-variant-numeric: lining-nums;
    text-align: center;
    transition: border-color 0.35s ease;
    -webkit-appearance: none;
    appearance: none;
}

.rsvp__control::placeholder { color: rgba(207, 160, 101, 0.5); }

.rsvp__control:focus {
    outline: none;
    border-bottom-color: rgba(240, 206, 146, 0.9);
}

/* Count me in / Sorry, I can't make it */
.rsvp__choices {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5em clamp(1rem, 4vw, 1.75rem);
}

.rsvp__choice {
    display: inline-flex;
    align-items: center;
    gap: 0.55em;
    cursor: pointer;
    font-size: clamp(0.82rem, 3.2vw, 0.98rem);
    color: var(--gold-body);
}

/* The native control stays for keyboard and screen readers; the dot is what
   you see. */
.rsvp__choice input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.rsvp__dot {
    flex: none;
    width: 0.82em;
    height: 0.82em;
    border: 1px solid rgba(233, 196, 134, 0.55);
    border-radius: 50%;
    transition: box-shadow 0.3s ease, border-color 0.3s ease;
}

.rsvp__choice input:checked + .rsvp__dot {
    border-color: rgba(246, 224, 176, 0.95);
    box-shadow: inset 0 0 0 0.19em var(--gold);
}

.rsvp__choice input:focus-visible + .rsvp__dot {
    outline: 1px solid rgba(240, 206, 146, 0.8);
    outline-offset: 3px;
}

.rsvp__choice input:checked ~ .rsvp__choice-text {
    color: var(--gold);
}

/* Headcount stepper — minus, count, plus. */
.rsvp__stepper {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: clamp(0.9rem, 4vw, 1.5rem);
}

.rsvp__step {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.1em;
    height: 2.1em;
    padding: 0;
    border: 1px solid rgba(233, 196, 134, 0.45);
    border-radius: 50%;
    background: rgba(35, 5, 8, 0.35);
    color: var(--gold);
    font-family: inherit;
    font-size: clamp(1rem, 4vw, 1.2rem);
    line-height: 1;
    cursor: pointer;
    transition: border-color 0.3s ease, background-color 0.3s ease, opacity 0.3s ease;
}

.rsvp__step:hover:not([disabled]),
.rsvp__step:focus-visible {
    border-color: rgba(240, 206, 146, 0.85);
    background: rgba(60, 12, 16, 0.5);
}

.rsvp__step[disabled] {
    opacity: 0.32;
    cursor: default;
}

.rsvp__count {
    width: 2.6em;
    padding: 0.1em 0;
    border: 0;
    background: transparent;
    color: var(--gold);
    font-family: inherit;
    font-size: clamp(1.5rem, 6vw, 1.9rem);
    font-variant-numeric: lining-nums;
    text-align: center;
    -moz-appearance: textfield;
    appearance: textfield;
}

.rsvp__count:focus { outline: none; }

/* The native spinners would fight the two buttons. */
.rsvp__count::-webkit-outer-spin-button,
.rsvp__count::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.rsvp__submit {
    align-self: center;
    margin-top: clamp(0.3rem, 1.4vh, 0.8rem);
    padding: 0.85em 2.4em;
    border: 1px solid rgba(233, 196, 134, 0.45);
    border-radius: 999px;
    background: rgba(35, 5, 8, 0.35);
    color: var(--gold);
    font-family: inherit;
    font-size: clamp(0.7rem, 2.8vw, 0.85rem);
    font-weight: 500;
    letter-spacing: 0.21em;
    text-transform: uppercase;
    cursor: pointer;
    transition: border-color 0.35s ease, background-color 0.35s ease;
}

.rsvp__submit:hover,
.rsvp__submit:focus-visible {
    border-color: rgba(240, 206, 146, 0.85);
    background: rgba(60, 12, 16, 0.5);
}

.rsvp__submit[disabled] {
    opacity: 0.55;
    cursor: default;
}

/* Reserve the line so the layout does not jump when a message lands. */
.rsvp__message {
    min-height: 1.5em;
    font-size: clamp(0.85rem, 3.4vw, 1rem);
    line-height: 1.5;
    color: var(--gold-muted);
}

.rsvp__message.is-good { color: var(--gold); }
.rsvp__message.is-bad  { color: #e8a48a; }

/* Once a reply is in, only the thank-you remains. */
.rsvp.is-sent .rsvp__choices,
.rsvp.is-sent .rsvp__field,
.rsvp.is-sent .rsvp__submit {
    display: none;
}

:focus-visible {
    outline: 1px solid rgba(240, 206, 146, 0.8);
    outline-offset: 6px;
}

/* --------------------------------------------------------------------------
   Intro — PDF pages 1–6

   The page is scroll-locked (html.intro-lock) until the sequence finishes.
   The lock class is added by an inline script in the head, so it only ever
   applies when JavaScript is running; assets/js/intro.js removes it, and a
   watchdog in that file removes it too if the video never plays.
   -------------------------------------------------------------------------- */

.intro-lock,
.intro-lock body {
    height: 100%;
    overflow: hidden;
}

.intro {
    position: absolute;
    inset: 0;
    overflow: hidden;
}

.intro__video,
.intro__cover,
.intro__still {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.intro__video { z-index: 1; }

/* The same scene without the envelope. It fades in as the boat parks, which
   is what makes the envelope disappear. */
.intro__still {
    z-index: 2;
    opacity: 0;
    transition: opacity var(--intro-envelopeOut, 1500ms) ease;
}

.intro__still.is-visible { opacity: 1; }

/* The poster sits over the video until the first frame is actually painted. */
.intro__cover {
    z-index: 3;
    transition: opacity var(--intro-coverOut, 500ms) ease;
}

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

/* The boat parks in from the bottom, then leaves off the top. */
.intro__boat {
    position: absolute;
    left: 50%;
    top: 52%;              /* down inside the opened envelope's pocket */
    z-index: 4;
    height: 34%;
    width: auto;
    max-width: 44%;
    object-fit: contain;
    opacity: 0;
    transform: translate(-50%, calc(-50% + 70%));
    transition:
        opacity   var(--intro-boatIn, 2200ms) ease,
        transform var(--intro-boatIn, 2200ms) cubic-bezier(0.22, 0.61, 0.36, 1);
    will-change: opacity, transform;
}

.intro__boat.is-visible {
    opacity: 1;
    transform: translate(-50%, -50%);
}

.intro__boat.is-gone {
    opacity: 0;
    transform: translate(-50%, calc(-50% - 150%));
    transition:
        opacity   var(--intro-boatOut, 2000ms) ease,
        transform var(--intro-boatOut, 2000ms) cubic-bezier(0.45, 0, 0.7, 1);
}

/* Title and rule share one anchored block, so the title never shifts when the
   rule arrives — the rule's space is reserved from the start. */
.intro__lockup {
    position: absolute;
    left: 0;
    right: 0;
    /* High enough that the short first line ("THE", and a bare "O" in
       Portuguese) clears the boat's bow, where gold type on the gold hull
       reads as part of the boat rather than as a word. */
    top: 39%;
    z-index: 5;
    transform: translateY(-50%);
    padding: 0 clamp(1rem, 5vw, 2rem);
    text-align: center;
    pointer-events: none;
}

.intro__titlebox {
    position: relative;
    isolation: isolate;          /* so the shadow below can sit behind the type */
    display: inline-block;
    max-width: 100%;
    padding: clamp(0.6rem, 2.4vw, 1.1rem) clamp(0.7rem, 2.6vw, 1.1rem);
    opacity: 0;
    transform: translateY(0.9rem);
    transition:
        opacity   var(--intro-titleIn, 1600ms) ease,
        transform var(--intro-titleIn, 1600ms) cubic-bezier(0.22, 0.61, 0.36, 1);
}

.intro__titlebox.is-visible {
    opacity: 1;
    transform: none;
}

/* A soft, edgeless pool of shadow that lifts the gold off the boat's bright
   hull. It sits low behind the type — weighted under the words rather than
   ringed around them — and it is its own layer, not the box's background, so
   it can fade away on its own once the boat has gone. */
.intro__titlebox::before {
    content: "";
    position: absolute;
    z-index: -1;
    left: -8%;
    right: -8%;
    top: -8%;
    bottom: -20%;
    /* Weighted low — the mass sits under the words rather than ringing them —
       but it still reaches the first line, which lands on the boat's bright
       bow and disappears without it. */
    background: radial-gradient(
        ellipse 60% 66% at 50% 58%,
        rgba(0, 0, 0, 0.54) 0%,
        rgba(0, 0, 0, 0.42) 45%,
        rgba(0, 0, 0, 0.18) 75%,
        rgba(0, 0, 0, 0) 100%
    );
    transition: opacity var(--intro-scrimOut, 2200ms) ease;
    pointer-events: none;
}

/* The boat is leaving, so the type no longer needs the help — the shadow
   goes with it, slowly enough that nobody sees it happen. */
.intro__titlebox.is-bare::before {
    opacity: 0;
}

.intro__title {
    font-size: clamp(1.95rem, 8.1vw, 2.5rem);
    margin-bottom: 0;
    filter:
        drop-shadow(0 0 2px rgba(0, 0, 0, 0.9))
        drop-shadow(0 2px 7px rgba(0, 0, 0, 0.6))
        drop-shadow(0 0 30px rgba(255, 190, 110, 0.3));
}

.intro__rule {
    margin-top: clamp(0.9rem, 3vh, 1.5rem);
    opacity: 0;
    transition: opacity var(--intro-ruleIn, 1400ms) ease;
}

.intro__rule.is-visible { opacity: 1; }

.intro__rule .divider { margin-top: 0; margin-bottom: 0; }

/* Two cases show the finished opening with no animation at all:

   .no-js      nothing can play, so page 6 is the only sensible state
   .intro-done this session has already watched it — switching language
               reloads the page, and replaying (or even flashing) the
               envelope would be wrong

   Both are set before the body paints, so nothing of the opening is ever
   shown and then taken away. */
.no-js .intro__video,
.no-js .intro__cover,
.no-js .intro__boat,
.no-js .intro__tap,
.intro-done .intro__video,
.intro-done .intro__cover,
.intro-done .intro__boat,
.intro-done .intro__tap {
    display: none;
}

.no-js .intro__still,
.no-js .intro__titlebox,
.no-js .intro__rule,
.intro-done .intro__still,
.intro-done .intro__titlebox,
.intro-done .intro__rule {
    opacity: 1;
    transition: none;
}

/* Only the title box has a transform to undo — the cue is centred with one. */
.no-js .intro__titlebox,
.intro-done .intro__titlebox {
    transform: none;
}

.intro-done .intro__cue {
    opacity: 0.85;
    transition: none;
}

/* The boat is long gone, so the type needs no shadow behind it. */
.no-js .intro__titlebox::before,
.intro-done .intro__titlebox::before {
    opacity: 0;
    transition: none;
}

/* The way in — the guest taps the envelope to open it. */
.intro__tap {
    position: absolute;
    left: 50%;
    bottom: clamp(3rem, 12vh, 6rem);
    z-index: 7;
    transform: translateX(-50%);
    padding: 0.85em 1.9em;
    border: 1px solid rgba(233, 196, 134, 0.45);
    border-radius: 999px;
    background: rgba(35, 5, 8, 0.4);
    color: var(--gold);
    font-family: inherit;
    font-size: clamp(0.72rem, 2.9vw, 0.88rem);
    font-weight: 500;
    letter-spacing: 0.21em;
    text-transform: uppercase;
    cursor: pointer;
    animation: introPulse 2.6s ease-in-out infinite;
}

@keyframes introPulse {
    0%, 100% { opacity: 0.75; }
    50%      { opacity: 1; }
}

/* Appears once the sequence has finished and the page is scrollable again. */
.intro__cue {
    position: absolute;
    left: 50%;
    /* Sits clear of the gold ribbon that sweeps the lower third of
       bg-intro.jpg — below ~80% the type lands on the bright weave. */
    bottom: 21%;
    z-index: 6;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    transform: translateX(-50%);
    opacity: 0;
    transition: opacity 1.4s ease;
    pointer-events: none;
}

.intro__cue.is-visible { opacity: 0.85; }

.intro__cue-label {
    color: var(--gold-muted);
    font-size: clamp(0.58rem, 2.3vw, 0.7rem);
    font-weight: 500;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    text-indent: 0.3em;
}

.intro__cue-line {
    width: 1px;
    height: clamp(1.75rem, 5vh, 2.75rem);
    background: linear-gradient(
        180deg,
        rgba(233, 196, 134, 0.75) 0%,
        rgba(233, 196, 134, 0) 100%
    );
}

/* --------------------------------------------------------------------------
   Reveal on scroll
   -------------------------------------------------------------------------- */

[data-reveal] {
    opacity: 0;
    transform: translateY(1.4rem);
    transition: opacity 1.1s ease, transform 1.1s cubic-bezier(0.22, 0.61, 0.36, 1);
    will-change: opacity, transform;
}

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

.no-js [data-reveal] {
    opacity: 1;
    transform: none;
}

/* --------------------------------------------------------------------------
   Larger screens — the deck stays a portrait card, centred
   -------------------------------------------------------------------------- */

@media (min-width: 48rem) {
    :root { --measure: 36rem; }

    .panel__inner::before {
        background: radial-gradient(
            48% 58% at 50% 50%,
            rgba(38, 6, 9, 0.5) 0%,
            rgba(38, 6, 9, 0.24) 60%,
            rgba(38, 6, 9, 0) 100%
        );
    }
}

/* --------------------------------------------------------------------------
   Desktop-only trims. The card is a fixed 500px there while the screen is
   shorter than a phone's, so a few panels need their copy sitting higher to
   stay clear of the artwork.
   -------------------------------------------------------------------------- */

@media (min-width: 40rem) {
    .panel--food-beverage .panel__inner {
        padding-top: clamp(0.85rem, 2.2vh, 1.5rem);
    }

    .panel--dress-code .panel__inner,
    .panel--entertainment .panel__inner {
        padding-top: clamp(0.6rem, 1.4vh, 1rem);
    }

    .panel--privacy .panel__inner {
        padding-top: clamp(1.25rem, 3.5vh, 2rem);
    }

    .panel--rsvp .panel__inner {
        padding-top: clamp(1.75rem, 4.5vh, 3rem);
    }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    [data-reveal] {
        opacity: 1;
        transform: none;
        transition: none;
    }
}
