/* ═══════════════════════════════════════════
   three-gifts — beat 3 of best-boyfriend
   26 s · verb open · hold `gifts` at 8 s (3 steps), then `onward` at 8.5 s

   Three wrapped gifts hover over the open envelope. Each one opens into the
   beat's single panel (photo-booth strips, a record, a column of tickets),
   the other two shrinking to tabs along the bottom. Then they re-tie, slide
   into the envelope, and the room dims to one lamp over the letter's edge.

   Layers inside the container (one stacking context, bottom to top):
     0 .three-gifts-room    world space: the room dimming to a lamp (the exit),
                            behind the table as in the-letter, so it ends on
                            the-letter's own first frame
     1 .three-gifts-scene   world space: the open envelope, letter, seal halves
     2 .three-gifts-ui      SCREEN space: the scrim, the panel, tab slots, onward
     3 .three-gifts-gifts   world space: the three gifts (later their tabs)
     4 .three-gifts-lines   world space: the lines under the envelope
     5 .three-gifts-viewer  SCREEN space: a photo seen whole

   "Screen space" layers cancel the camera's translation with the same
   --cam-* values (and the same transition) that move the world, so the
   panel and the full view always sit on the phone's screen, whatever pose
   the camera holds (the table pose here; none at all under reduced motion).

   Geometry comes only from tokens.css's continuity variables, and the
   envelope, its letter, the two halves and the wrapped gifts are drawn as
   the-seal leaves them (its handover: the V-mouthed pocket, the lining
   standing open, the letter 86% x 80% at -peek, the halves lying back
   48deg at their resting places, the gifts' tissue, thread, bow and blank
   tag), so the cut between the two beats is invisible.
   Every class and keyframe is prefixed `three-gifts-`.
   ═══════════════════════════════════════════ */

.three-gifts-container {
    --three-gifts-tab: 52px;                                        /* a tab: still a >= 44 px target */
    --three-gifts-slot-gap: 20px;
    --three-gifts-gap: 12px;
    --three-gifts-foot: calc(18px + env(safe-area-inset-bottom, 0px));
    --three-gifts-onward-h: 48px;
    /* The "Made with Reveel" badge's band: once "On to the letter" shows, the
       badge guard lifts the 32px badge to 8px above it, so the panel ends a
       clear 8px above that (8 + 32 + 8) and none of its text is ever under it. */
    --three-gifts-badge-band: 48px;
    --three-gifts-panel-top: calc(58px + env(safe-area-inset-top, 0px));
    --three-gifts-panel-bottom: calc(var(--three-gifts-foot) + var(--three-gifts-tab) + var(--three-gifts-gap) + var(--three-gifts-onward-h) + var(--three-gifts-badge-band));
    --three-gifts-panel-w: min(92vw, 30rem);
    position: absolute;
    inset: 0;
    isolation: isolate;
    pointer-events: none;
    -webkit-user-select: none;
    user-select: none;
}

/* Entry states are applied instantly (prepare), never animated in. */
.three-gifts-container.three-gifts--instant,
.three-gifts-container.three-gifts--instant *,
.three-gifts-container.three-gifts--instant *::before,
.three-gifts-container.three-gifts--instant *::after {
    transition: none !important;
}

.three-gifts-scene,
.three-gifts-gifts,
.three-gifts-lines {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.three-gifts-scene { z-index: 1; }
.three-gifts-gifts { z-index: 3; }
.three-gifts-lines { z-index: 4; }

/* ───── Screen-space layers: cancel the camera's translation ───── */
.three-gifts-ui,
.three-gifts-viewer {
    position: absolute;
    inset: 0;
    transform: translate3d(calc(var(--cam-x, 0px) * -1), calc(var(--cam-y, 0px) * -1), calc(var(--cam-z, 0px) * -1));
}
.three-gifts-ui {
    z-index: 2;
    pointer-events: none;
    transition: transform var(--cam-ms, 300ms) ease-out;
}

/* ═══════════ 1. The envelope (continuity geometry) ═══════════
   The box is the envelope; its children paint in DOM order: the inside,
   the open flap's lining, the letter, the pocket, the halves. */
.three-gifts-env {
    position: absolute;
    left: calc(var(--env-x) - var(--env-w) / 2);
    top: calc(var(--env-y) - var(--env-h) / 2);
    width: var(--env-w);
    height: var(--env-h);
}

/* The inside (seen through the open mouth), carrying the drop shadow. */
.three-gifts-env-back {
    position: absolute;
    inset: 0;
    border-radius: 3px;
    background: linear-gradient(180deg, var(--void) 0%, var(--bg-primary) 58%, var(--bg-elevated) 100%);
    box-shadow: var(--envelope-shadow);
}

/* The flap, hinged open onto its champagne lining: standing up off the top
   edge, its tip --flap-depth above it. */
.three-gifts-env-flap {
    position: absolute;
    left: 0;
    top: -100%;
    width: 100%;
    height: 100%;
    background: var(--envelope-lining);
    clip-path: polygon(0 100%, 100% 100%, 50% calc(100% - var(--flap-depth)));
}
.three-gifts-env-line {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
}
.three-gifts-env-line path {
    fill: none;
    stroke: var(--envelope-edge);
    stroke-width: 2px;
    vector-effect: non-scaling-stroke;
    stroke-linejoin: round;
}

/* The letter: 86% x 80% of the envelope, its cream edge --letter-peek above the mouth. */
.three-gifts-letter {
    position: absolute;
    left: 7%;
    width: 86%;
    top: calc(var(--letter-peek) * -1);
    height: 80%;
    transition: transform 1.4s var(--ease-expo-out);
}
.three-gifts-letter-glow {
    position: absolute;
    left: -16%;
    right: -16%;
    top: calc(var(--letter-peek) * -1.6);
    height: calc(var(--letter-peek) * 4.4);
    background: radial-gradient(ellipse at 50% 50%, rgba(246, 220, 154, 0.55) 0%, rgba(226, 177, 85, 0.16) 42%, rgba(226, 177, 85, 0) 70%);
    opacity: 0;
    transition: opacity 2.6s var(--ease-silk);
}
.three-gifts-letter-sheet {
    position: relative;
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 2px 2px 0 0;
    background:
        repeating-linear-gradient(180deg, rgba(184, 134, 47, 0) 0, rgba(184, 134, 47, 0) 13px, var(--paper-rule) 13px, var(--paper-rule) 14px) 0 10px / 100% 100% no-repeat,
        linear-gradient(180deg, var(--paper) 0%, var(--paper) 55%, var(--accent-celestial) 100%);
    box-shadow: inset 0 1px 0 var(--paper-edge), 0 -2px 10px var(--accent-warm-glow-soft);
}

/* The pocket: the envelope's front, with its V mouth 38% deep. */
.three-gifts-pocket {
    position: absolute;
    inset: 0;
    background: var(--envelope-body);
    clip-path: polygon(0 0, 50% 38%, 100% 0, 100% 100%, 0 100%);
}
.three-gifts-pocket-lines {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
.three-gifts-pocket-edge { fill: none; stroke: var(--envelope-edge); stroke-width: 2px; vector-effect: non-scaling-stroke; }
.three-gifts-pocket-fold { fill: none; stroke: var(--foil-line-soft); stroke-width: 1px; vector-effect: non-scaling-stroke; }
.three-gifts-pocket-mouth { fill: none; stroke: var(--foil-line-strong); stroke-width: 2px; vector-effect: non-scaling-stroke; stroke-linejoin: round; }

/* The over-copy (in the gifts layer): identical pixels, shown only while the
   gifts slide into the mouth, so they pass behind the envelope's face. */
.three-gifts-env.three-gifts-env--over {
    z-index: 2;
    opacity: 0;
    visibility: hidden;
}
.three-gifts-container.three-gifts--stowing .three-gifts-env.three-gifts-env--over {
    opacity: 1;
    visibility: visible;
}

/* The two halves of the broken seal, where the-seal's tumble left them: a
   seal-sized box on the flap's tip, moved to its resting place on the
   table and lying back. Left centred (-0.36 env-w, +0.62 env-h) from the
   envelope's centre at -24deg; right (+0.31 env-w, +0.66 env-h) at 31deg. */
.three-gifts-half,
.three-gifts-rest {
    position: absolute;
    left: calc(50% - var(--seal-d) / 2);
    top: calc(var(--flap-depth) - var(--seal-d) / 2);
    width: var(--seal-d);
    height: var(--seal-d);
    transition: opacity 4s var(--ease-silk) 0.6s;
}
.three-gifts-half.three-gifts-half--left {
    transform: perspective(420px) translate(-150%, 154%) rotateZ(-24deg) rotateY(0deg) rotateX(48deg);
}
.three-gifts-half.three-gifts-half--right {
    transform: perspective(420px) translate(129%, 165%) rotateZ(31deg) rotateY(0deg) rotateX(48deg);
}
.three-gifts-half-wax {
    position: absolute;
    inset: 0;
}
.three-gifts-half--left .three-gifts-half-wax {
    clip-path: polygon(0 0, 50% 0, 45% 13%, 55% 27%, 48% 40%, 51% 50%, 46% 61%, 55% 74%, 47% 87%, 50% 100%, 0 100%);
}
.three-gifts-half--right .three-gifts-half-wax {
    clip-path: polygon(50% 0, 100% 0, 100% 100%, 50% 100%, 47% 87%, 55% 74%, 46% 61%, 51% 50%, 48% 40%, 55% 27%, 45% 13%);
}
.three-gifts-wax {
    position: absolute;
    inset: 0;
    border-radius: 47% 53% 49% 51% / 52% 46% 54% 48%;
}
.three-gifts-wax-base {
    background: var(--wax-gold);
    box-shadow: 0 3px 7px rgba(22, 5, 9, 0.5), 0 0 0 1px rgba(184, 134, 47, 0.55);
}
/* The stamp's impression ring. */
.three-gifts-wax-base::after {
    content: '';
    position: absolute;
    inset: 15%;
    border-radius: 50%;
    border: 1px solid rgba(184, 134, 47, 0.8);
    box-shadow: inset 0 1px 2px rgba(22, 5, 9, 0.35), 0 1px 0 rgba(246, 220, 154, 0.45);
}
.three-gifts-wax-rim { box-shadow: var(--wax-rim); }
.three-gifts-monogram {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-bottom: 0.05em;
    font: 700 calc(var(--seal-d) * 0.44)/1 var(--font-display);
    color: var(--accent-warm-deep);
    text-shadow: 0 1px 0 rgba(246, 220, 154, 0.6), 0 -1px 0 rgba(22, 5, 9, 0.3);
}
.three-gifts-half-edge {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
.three-gifts-half-edge path { fill: none; stroke: var(--accent-warm-bright); stroke-width: 2px; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
/* Their soft contact shadows on the table. */
.three-gifts-rest {
    border-radius: 50%;
    background: radial-gradient(closest-side, rgba(22, 5, 9, 0.62), rgba(22, 5, 9, 0));
}
.three-gifts-rest.three-gifts-rest--left { transform: translate(-150%, 176%) scale(1.15, 0.34); }
.three-gifts-rest.three-gifts-rest--right { transform: translate(129%, 187%) scale(1.15, 0.34); }

/* ═══════════ 3. The gifts ═══════════ */
.three-gifts-gift {
    --three-gifts-hx: 0px;
    --three-gifts-hy: 0px;
    position: absolute;
    left: var(--three-gifts-gx);
    top: var(--three-gifts-gy);
    width: var(--gift-w);
    height: var(--gift-w);
    margin: calc(var(--gift-w) / -2) 0 0 calc(var(--gift-w) / -2);
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--text-primary);
    font: inherit;
    cursor: pointer;
    pointer-events: auto;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    z-index: 1;
    transition: transform 0.85s var(--ease-expo-out);
}
.three-gifts-gift:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 6px;
}
/* Left to right: the photo strips, the song, the coupons. --three-gifts-hx/-hy
   carry each one down into the envelope's mouth, below the V's point. */
.three-gifts-gift.three-gifts-gift--strips {
    --three-gifts-i: 0;
    --three-gifts-gx: calc(var(--env-x) - var(--gift-spread));
    --three-gifts-gy: calc(var(--env-y) - var(--gift-rise));
    --three-gifts-hx: calc(var(--gift-spread) - var(--env-w) * 0.2);
    --three-gifts-hy: calc(var(--gift-rise) + var(--env-h) * 0.12);
    --three-gifts-rise: var(--gift-rise);
    --three-gifts-bob-delay: 0s;
}
.three-gifts-gift.three-gifts-gift--song {
    --three-gifts-i: 1;
    --three-gifts-gx: var(--env-x);
    --three-gifts-gy: calc(var(--env-y) - var(--gift-rise-mid));
    --three-gifts-hx: 0px;
    --three-gifts-hy: calc(var(--gift-rise-mid) + var(--env-h) * 0.12);
    --three-gifts-rise: var(--gift-rise-mid);
    --three-gifts-bob-delay: 0.35s;
}
.three-gifts-gift.three-gifts-gift--coupons {
    --three-gifts-i: 2;
    --three-gifts-gx: calc(var(--env-x) + var(--gift-spread));
    --three-gifts-gy: calc(var(--env-y) - var(--gift-rise));
    --three-gifts-hx: calc(var(--env-w) * 0.2 - var(--gift-spread));
    --three-gifts-hy: calc(var(--gift-rise) + var(--env-h) * 0.12);
    --three-gifts-rise: var(--gift-rise);
    --three-gifts-bob-delay: 0.7s;
}
/* The whole column is the gift's tap target: the gift, its tag, and an
   invisible reach down over the envelope to its lower edge (--env-y + 0.5
   --env-h), so a thumb in the lower half of the screen can open any of the
   three without stretching to the row. It stops there: below the envelope
   the Reveel badge may lift (above the line and the hint), and the badge's
   guard sees only the button's own box, so the reach must never run under
   it. The columns are one --gift-spread apart, with a 6px seam between
   them. They serve the first tap only: gone once a gift has opened (the
   gifts are then tabs), and while the gifts are disabled for the exit. */
.three-gifts-gift::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 0;
    width: calc(var(--gift-spread) - 6px);
    height: calc(var(--three-gifts-rise) + var(--env-h) * 0.5 + var(--gift-w) / 2);
    transform: translateX(-50%);
}
.three-gifts-container.three-gifts--browsing .three-gifts-gift::after,
.three-gifts-gift.three-gifts-gift--tab::after,
.three-gifts-gift:disabled::after {
    display: none;
}

/* A soft halo in the light, so cream reads against the dark (as the-seal's). */
.three-gifts-gift-halo {
    position: absolute;
    inset: -32%;
    border-radius: 50%;
    background: radial-gradient(closest-side, var(--halo) 0%, var(--halo-far) 55%, rgba(226, 177, 85, 0) 100%);
    pointer-events: none;
    transition: opacity 0.4s var(--ease-silk);
}

/* Each on its own breath bob: a bar (4 beats) per bob, picked up at rest
   exactly where the-seal's bob left it, and staggered as they rose. */
.three-gifts-gift-bob {
    position: absolute;
    inset: 0;
    animation: three-gifts-bob 2.667s var(--ease-breath) var(--three-gifts-bob-delay, 0s) infinite;
}
@keyframes three-gifts-bob {
    0%, 100% { transform: translateY(0px); }
    50% { transform: translateY(-5px); }
}

.three-gifts-gift-art,
.three-gifts-gift-flap {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
}
.three-gifts-defs {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}
.three-gifts-stop-paper { stop-color: var(--paper); }
.three-gifts-stop-champagne { stop-color: var(--accent-celestial); }
.three-gifts-stop-cream { stop-color: var(--text-secondary); }
.three-gifts-stop-gold-hi { stop-color: var(--accent-warm-bright); }
.three-gifts-stop-gold { stop-color: var(--accent-warm); }
.three-gifts-stop-gold-deep { stop-color: var(--accent-warm-deep); }
.three-gifts-stop-wine { stop-color: var(--wine); }
.three-gifts-stop-ground { stop-color: var(--bg-primary); }
.three-gifts-stop-pool { stop-color: var(--bg-elevated); }
.three-gifts-stop-void { stop-color: var(--void); }

/* Tissue, gold thread, a bow and a small blank tag. */
.three-gifts-tissue-back { fill: var(--accent-celestial); stroke: var(--paper-edge); stroke-width: 0.6px; stroke-linejoin: round; }
.three-gifts-tissue-front { fill: url(#three-gifts-g-tissue); stroke: var(--paper-edge); stroke-width: 0.6px; }
.three-gifts-tissue-shade { fill: var(--paper-shade); }
.three-gifts-tissue-fold { fill: none; stroke: var(--paper-shade); stroke-width: 0.9px; stroke-linecap: round; }
.three-gifts-thread-line { fill: none; stroke: var(--accent-warm); stroke-width: 2.6px; }
.three-gifts-thread-hi { fill: none; stroke: var(--accent-warm-bright); stroke-width: 0.7px; opacity: 0.85; }
.three-gifts-bow { fill: url(#three-gifts-g-gilt); stroke: var(--accent-warm-deep); stroke-width: 0.6px; }
.three-gifts-bow-tail { fill: none; stroke: var(--accent-warm); stroke-width: 2.2px; stroke-linecap: round; }
.three-gifts-knot { fill: var(--accent-warm-bright); stroke: var(--accent-warm-deep); stroke-width: 0.6px; }
.three-gifts-blank-tag { fill: var(--accent-celestial); stroke: var(--accent-warm-deep); stroke-width: 0.6px; stroke-linejoin: round; }
.three-gifts-blank-tag-hole { fill: var(--accent-warm-deep); }
.three-gifts-tag-string { fill: none; stroke: var(--accent-warm-deep); stroke-width: 0.6px; }

/* What peeks out: a strip's top frames, a record's gold edge, a ticket's claret stub. */
.three-gifts-strip-art { fill: var(--paper); stroke: var(--paper-edge); stroke-width: 0.6px; }
.three-gifts-photo-a { fill: url(#three-gifts-g-photo-a); }
.three-gifts-photo-b { fill: url(#three-gifts-g-photo-b); }
.three-gifts-rec { fill: url(#three-gifts-g-record); }
.three-gifts-rec-groove { fill: none; stroke: rgba(246, 220, 154, 0.14); stroke-width: 0.6px; }
.three-gifts-rec-label { fill: var(--wine); }
.three-gifts-rec-hole { fill: var(--void); }
.three-gifts-rec-edge { fill: none; stroke: var(--accent-warm); stroke-width: 2.2px; }
.three-gifts-rec-shine { fill: none; stroke: rgba(249, 238, 219, 0.42); stroke-width: 1.1px; stroke-linecap: round; }
.three-gifts-tkt { fill: var(--paper); stroke: var(--paper-edge); stroke-width: 0.6px; }
.three-gifts-tkt-under { fill: var(--accent-celestial); }
.three-gifts-tkt-stub { fill: var(--wine); }
.three-gifts-tkt-perf { fill: none; stroke: var(--coupon-perf); stroke-width: 0.8px; stroke-dasharray: 1.6 1.4; }
.three-gifts-tkt-ink { fill: none; stroke: var(--ink-soft); stroke-width: 1px; stroke-linecap: round; opacity: 0.45; }
.three-gifts-tkt-star { fill: var(--accent-warm-bright); }

/* The opening: the whole tissue gives way to four copies of it, each
   clipped to one side, which peel outward about their outer edges. At
   rest only the whole one shows (no seams). */
.three-gifts-gift-box {
    position: absolute;
    inset: 0;
    perspective: 260px;
}
.three-gifts-gift-flap { opacity: 0; }
/* The light inside the parcel, which the peeling tissue reveals (pre-painted; only its opacity moves). */
.three-gifts-gift-box::before {
    content: '';
    position: absolute;
    left: 6%;
    right: 6%;
    top: 27%;
    bottom: 2%;
    border-radius: 8% / 10%;
    background: radial-gradient(ellipse 70% 70% at 50% 52%, var(--light-core) 0%, var(--halo) 50%, rgba(226, 177, 85, 0.32) 100%);
    opacity: 0;
}
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-box::before {
    opacity: 1;
    transition: opacity 0.35s var(--ease-silk) 0.05s;
}
.three-gifts-gift-flap.three-gifts-gift-flap--top {
    clip-path: polygon(0 0, 100% 0, 50% 62%);
    transform-origin: 50% 27%;
}
.three-gifts-gift-flap.three-gifts-gift-flap--right {
    clip-path: polygon(100% 0, 100% 100%, 50% 62%);
    transform-origin: 94% 62%;
}
.three-gifts-gift-flap.three-gifts-gift-flap--bottom {
    clip-path: polygon(0 100%, 100% 100%, 50% 62%);
    transform-origin: 50% 98%;
}
.three-gifts-gift-flap.three-gifts-gift-flap--left {
    clip-path: polygon(0 0, 0 100%, 50% 62%);
    transform-origin: 6% 62%;
}

/* The thread, the bow and the tag: they slacken and slide off together. */
.three-gifts-gift-thread {
    transition: opacity 0.5s var(--ease-silk), transform 0.7s var(--ease-expo-out);
    transition-delay: calc(var(--three-gifts-i) * 0.18s);
}

/* 6 s: the ribbon tails stir to invite a tap (a few times, then rest). */
.three-gifts-bow-tail {
    transform-box: fill-box;
    transform-origin: 50% 0;
}
.three-gifts-container.three-gifts--invite .three-gifts-bow-tail {
    animation: three-gifts-stir 1.3s var(--ease-breath) 3;
    animation-delay: calc(var(--three-gifts-i) * 0.22s);
}
@keyframes three-gifts-stir {
    0%, 100% { transform: rotate(0deg); }
    30% { transform: rotate(7deg); }
    70% { transform: rotate(-6deg); }
}
.three-gifts-container.three-gifts--browsing .three-gifts-bow-tail { animation: none; }

/* The small gold tick an opened gift keeps. */
.three-gifts-gift-tick {
    position: absolute;
    right: -6%;
    top: 14%;
    width: 22%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--btn-fill);
    box-shadow: 0 0 0 1px var(--accent-warm-deep), 0 2px 6px rgba(22, 5, 9, 0.5);
    opacity: 0;
    transform: scale(0.5);
    transition: opacity 0.4s var(--ease-silk), transform 0.5s var(--ease-expo-out);
}
.three-gifts-gift-tick::after {
    content: '';
    position: absolute;
    left: 31%;
    top: 20%;
    width: 26%;
    height: 44%;
    border-right: 2px solid var(--btn-ink);
    border-bottom: 2px solid var(--btn-ink);
    transform: rotate(40deg);
}

/* The tag beneath each gift: Outfit caps on a small gilt plaque. */
.three-gifts-tag {
    position: absolute;
    left: 50%;
    top: calc(100% + 8px);
    width: max-content;
    max-width: calc(var(--gift-w) * 0.98);
    transform: translate(-50%, 5px);
    opacity: 0;
    transition: opacity 0.9s var(--ease-silk), transform 1.1s var(--ease-expo-out), visibility 0s linear 0s;
}
.three-gifts-tag-plate {
    position: relative;
    display: block;
    padding: 0.3rem 0.55rem;
    border: 1px solid var(--foil-line);
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(70, 21, 35, 0.94), rgba(22, 5, 9, 0.9));
    box-shadow: var(--plaque-inset);
    font: 500 0.72rem/1.2 var(--font-body);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-align: center;
    text-wrap: balance;
    color: var(--text-primary);
}
.three-gifts-gift.three-gifts-gift--tagged .three-gifts-tag {
    opacity: 1;
    transform: translate(-50%, 0);
}
/* Once a gift has been opened the tags have done their job. */
.three-gifts-container.three-gifts--browsing .three-gifts-tag {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.4s var(--ease-silk), visibility 0s linear 0.4s;
}

/* ───── Gift states ───── */
/* A tab: shrunk to 52 px in its slot along the bottom (the deltas are measured). */
.three-gifts-gift.three-gifts-gift--tab {
    transform: translate(var(--three-gifts-tx, 0px), var(--three-gifts-ty, 0px)) scale(var(--three-gifts-ts, 0.5));
}
.three-gifts-gift.three-gifts-gift--tab .three-gifts-gift-bob { animation: none; }
.three-gifts-gift.three-gifts-gift--tab .three-gifts-gift-halo { opacity: 0; }

/* Open: the tissue peeled away to four sides, what was peeking out risen
   into the panel, the gift itself gone. */
.three-gifts-gift.three-gifts-gift--open {
    opacity: 0;
    visibility: hidden;
}
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-back {
    opacity: 0;
    transition: opacity 0.7s var(--ease-silk) 0.3s;
}
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-tissue,
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-flap,
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-halo { opacity: 0; }
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-flap--top { transform: rotateX(150deg); }
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-flap--right { transform: rotateY(150deg); }
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-flap--bottom { transform: rotateX(-150deg); }
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-flap--left { transform: rotateY(-150deg); }
.three-gifts-gift.three-gifts-gift--open .three-gifts-gift-peek {
    opacity: 0;
    translate: 0 -40%;
    transition: opacity 0.6s var(--ease-silk) 0.25s, translate 0.9s var(--ease-expo-out) 0.25s;
}

/* Opened once: its thread is off, and it keeps a gold tick. */
.three-gifts-gift.three-gifts-gift--opened .three-gifts-gift-thread {
    opacity: 0;
    transform: translateY(-42%) rotate(-10deg);
    transition: none;
}
.three-gifts-gift.three-gifts-gift--opened .three-gifts-gift-tick {
    opacity: 1;
    transform: none;
}
.three-gifts-gift.three-gifts-gift--opened.three-gifts-gift--open .three-gifts-gift-tick { opacity: 0; }
/* The exit: re-tied, one after another. */
.three-gifts-gift.three-gifts-gift--opened.three-gifts-gift--tied .three-gifts-gift-thread {
    opacity: 1;
    transform: none;
    transition: opacity 0.5s var(--ease-silk), transform 0.7s var(--ease-expo-out);
    transition-delay: calc(var(--three-gifts-i) * 0.18s);
}

/* Home: down into the envelope's mouth, shrinking (1.2 s expo-out). */
.three-gifts-gift.three-gifts-gift--home {
    transform: translate(var(--three-gifts-hx), var(--three-gifts-hy)) scale(0.3);
    opacity: 0;
    visibility: hidden;
    transition: transform 1.2s var(--ease-expo-out), opacity 0.45s var(--ease-silk) 0.75s, visibility 0s linear 1.2s;
}
.three-gifts-gift.three-gifts-gift--home .three-gifts-gift-halo { opacity: 0; }

/* Jumps to a new place without travelling (a folded gift reappearing as a tab). */
.three-gifts-gift.three-gifts-gift--snap,
.three-gifts-gift.three-gifts-gift--snap * {
    transition: none !important;
}

/* ═══════════ 2. Screen space: scrim, panel, slots, onward ═══════════ */
.three-gifts-scrim {
    position: absolute;
    inset: -4px;
    background: radial-gradient(ellipse 120% 90% at 50% 42%, rgba(22, 5, 9, 0.6), rgba(22, 5, 9, 0.86));
    opacity: 0;
    transition: opacity 0.7s var(--ease-silk);
}
.three-gifts-container.three-gifts--panel .three-gifts-scrim { opacity: 1; }

/* The one open panel: a sheet up to 92vw x 74vh between the mute control
   and the badge's band over the way on and the tab row. Its three contents
   share it; one is current. */
.three-gifts-panel {
    position: absolute;
    left: 50%;
    top: var(--three-gifts-panel-top);
    bottom: var(--three-gifts-panel-bottom);
    width: var(--three-gifts-panel-w);
    max-height: 74vh;
    margin: auto 0 auto calc(var(--three-gifts-panel-w) / -2);
    display: grid;
    container-type: size;
    border: 1px solid var(--foil-line);
    border-radius: 18px;
    background: linear-gradient(180deg, rgba(70, 21, 35, 0.97), rgba(50, 13, 22, 0.98));
    box-shadow: var(--paper-shadow), inset 0 1px 0 rgba(246, 220, 154, 0.18);
    outline: none;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}
.three-gifts-panel.three-gifts-panel--open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}
.three-gifts-sheet {
    grid-area: 1 / 1;
    min-width: 0;
    min-height: 0;
    display: grid;
    padding: 16px;
    visibility: hidden;
}
.three-gifts-sheet.three-gifts-sheet--current { visibility: visible; }

.three-gifts-caption {
    margin: 0;
    text-align: center;
    text-wrap: balance;
}
.three-gifts-caption.three-gifts-caption--strips,
.three-gifts-eyebrow {
    font: 500 0.74rem/1.3 var(--font-body);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-secondary);
}
.three-gifts-eyebrow {
    margin: 0;
    text-align: center;
    color: var(--accent-warm);
}
.three-gifts-caption.three-gifts-caption--song {
    font: italic 400 clamp(1.05rem, 4.6vw, 1.3rem)/1.3 var(--font-display);
    color: var(--text-primary);
}

/* ───── Photo strips ───── */
.three-gifts-sheet.three-gifts-sheet--strips {
    grid-template-rows: auto minmax(0, 1fr) auto;
    justify-items: center;
    gap: 10px;
}
/* The booth's slot the strips slide out of. */
.three-gifts-slotbar {
    width: min(86%, 20rem);
    height: 12px;
    border-radius: 6px;
    border: 1px solid var(--foil-line);
    background: var(--void);
    box-shadow: inset 0 3px 6px rgba(22, 5, 9, 0.9), 0 1px 0 rgba(246, 220, 154, 0.12);
}
.three-gifts-strips-stage {
    width: 100%;
    min-height: 0;
    container-type: size;
    /* clipped at the slot only, so the strips appear out of it */
    clip-path: polygon(-50% 0, 150% 0, 150% 150%, -50% 150%);
    margin-top: -6px;
}
.three-gifts-strips {
    --three-gifts-rows: 3;
    --three-gifts-cols: 2;
    /* frame width: the tallest strip fits the stage's height, the strips its width */
    --three-gifts-fw: min(
        calc((100cqh - 46px - (var(--three-gifts-rows) - 1) * 6px) / (var(--three-gifts-rows) * 1.25)),
        calc((100cqw - (var(--three-gifts-cols) - 1) * 18px) / var(--three-gifts-cols) - 22px),
        132px);
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    gap: 18px;
    padding-top: 2px;
}
.three-gifts-strip {
    flex: none;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 8px 0;
    background:
        linear-gradient(180deg, rgba(184, 134, 47, 0.08), rgba(184, 134, 47, 0)),
        var(--paper);
    box-shadow: inset 0 0 0 1px var(--paper-edge), 0 12px 26px rgba(22, 5, 9, 0.55);
    rotate: var(--three-gifts-tilt, 0deg);
}
.three-gifts-strip-foot {
    display: block;
    height: 26px;
    background: radial-gradient(circle at 50% 50%, var(--accent-warm) 0 2.5px, rgba(226, 177, 85, 0) 3px);
}
.three-gifts-frame {
    position: relative;
    display: block;
    width: var(--three-gifts-fw);
    aspect-ratio: 4 / 5;
    padding: 0;
    border: 0;
    overflow: hidden;
    background: var(--strip-frame);
    cursor: zoom-in;
    -webkit-tap-highlight-color: transparent;
}
.three-gifts-frame:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}
.three-gifts-frame-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 50%;
    -webkit-user-drag: none;
}
.three-gifts-frame-warm,
.three-gifts-frame-flash {
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
}
.three-gifts-frame-warm { background: rgba(226, 177, 85, 0.5); }
.three-gifts-frame-flash { background: var(--strip-flash); }

/* ───── The song ───── */
.three-gifts-sheet.three-gifts-sheet--song {
    /* the player is 0.944 pw tall (0.68 of the record above the sleeve's lip, then
       the sleeve); 5rem is the sheet's padding (32px), its gap (12px) and the
       caption's one line (at most 1.3rem x 1.3), with room to spare */
    --three-gifts-pw: min(80cqw, 19rem, calc((100cqh - 5rem) * 0.93));
    --three-gifts-rd: calc(var(--three-gifts-pw) * 0.8);
    --three-gifts-sh: calc(var(--three-gifts-rd) * 0.5);
    grid-template-rows: minmax(0, 1fr) auto;
    align-items: center;
    justify-items: center;
    gap: 12px;
}
/* With a YouTube link the sleeve holds a 16:9 window, and the record is smaller
   (the player is then 1.04 pw + 28.5px tall). */
.three-gifts-sheet.three-gifts-sheet--song.three-gifts-song--live {
    --three-gifts-pw: min(86cqw, 22rem, calc((100cqh - 5rem - 30px) / 1.04));
    --three-gifts-rd: calc(var(--three-gifts-pw) * 0.7);
    --three-gifts-sh: calc((var(--three-gifts-pw) - 24px) * 0.5625 + 42px);
}
.three-gifts-player {
    position: relative;
    width: var(--three-gifts-pw);
    /* 0.68 of the record stands above the sleeve's lip: the label shows down to its foot */
    height: calc(var(--three-gifts-rd) * 0.68 + var(--three-gifts-sh));
    /* the record rises out of the sleeve: clipped below the player only */
    clip-path: polygon(-20% -20%, 120% -20%, 120% 100%, -20% 100%);
}
.three-gifts-record-rise {
    position: absolute;
    left: 50%;
    top: 0;
    width: var(--three-gifts-rd);
    height: var(--three-gifts-rd);
    margin-left: calc(var(--three-gifts-rd) / -2);
    z-index: 1;
}
.three-gifts-record {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 3px solid var(--accent-warm);
    background:
        conic-gradient(from 20deg, rgba(246, 220, 154, 0) 0deg, rgba(246, 220, 154, 0.16) 32deg, rgba(246, 220, 154, 0) 72deg,
            rgba(246, 220, 154, 0) 180deg, rgba(246, 220, 154, 0.12) 214deg, rgba(246, 220, 154, 0) 254deg),
        repeating-radial-gradient(circle at 50% 50%, rgba(22, 5, 9, 1) 0 1.5px, rgba(50, 13, 22, 1) 1.5px 3px);
    box-shadow: 0 0 0 1px var(--accent-warm-deep), 0 14px 30px rgba(22, 5, 9, 0.6);
}
.three-gifts-record-grooves {
    position: absolute;
    inset: 9%;
    border-radius: 50%;
    border: 1px solid rgba(226, 177, 85, 0.16);
    box-shadow: inset 0 0 0 10px rgba(22, 5, 9, 0.25);
}
.three-gifts-record-label {
    position: absolute;
    left: 50%;
    top: 50%;
    /* a 7-inch single's proportions: the label is about half the record */
    width: 52%;
    height: 52%;
    margin: -26% 0 0 -26%;
    border-radius: 50%;
    display: grid;
    place-items: center;
    container-type: inline-size;
    /* the spindle hole's radius (2.25% of the record), in the label's own units */
    --three-gifts-hr: 4.327cqw;
    background: var(--rosette-ribbon);
    box-shadow: inset 0 0 0 1px var(--foil-line-strong), inset 0 0 0 4px rgba(142, 36, 56, 0.9), inset 0 0 0 5px var(--foil-line-soft);
    color: var(--text-primary);
    text-align: center;
}
/* The label is laid out around the spindle hole, as a real one is: "A song
   for" above it, the name below it. The hole spans 50% +/- --three-gifts-hr;
   the sleeve's lip crosses the record 0.18 of its width below the centre,
   i.e. 34.6cqw below the label's centre (only the label's foot tucks into
   the sleeve), so the name has room for two lines between the hole and the
   lip. The pulse breathes about the name's middle (fitRecordName() measures
   it), so the name never nears the hole. */
.three-gifts-record-label-pulse {
    position: absolute;
    inset: 0;
    transform-origin: 50% var(--three-gifts-name-mid, calc(63.71cqw + 3px));
}
.three-gifts-record-label-for {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(50cqw + var(--three-gifts-hr) + 2.5px);
    white-space: nowrap;
    font: 500 8.4cqw/1.26 var(--font-body);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--accent-celestial);
}
/* 14cqw at most, one line; fitRecordName() shrinks a long name to the label
   ring's chord, or sets it on two balanced lines when that reads larger, and
   sizes this box to fit. */
.three-gifts-record-label-name {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(50cqw + var(--three-gifts-hr) + 3px);
    box-sizing: border-box;
    width: 68cqw;
    margin: 0 auto;
    padding: 0 0.15em;
    overflow: hidden;
    white-space: nowrap;
    font: italic 400 14cqw/1.34 var(--font-display);
    color: var(--text-primary);
}
.three-gifts-record-label-name.three-gifts-record-label-name--two {
    overflow: visible;
    white-space: normal;
    overflow-wrap: normal;
    text-wrap: balance;
    line-height: 1.22;
}
.three-gifts-record-hole {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 4.5%;
    height: 4.5%;
    margin: -2.25% 0 0 -2.25%;
    border-radius: 50%;
    background: var(--void);
    box-shadow: 0 0 0 1px var(--accent-warm-deep);
}
/* The light on the record stays put while it turns. */
.three-gifts-record-sheen {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: linear-gradient(135deg, rgba(249, 238, 219, 0.16), rgba(249, 238, 219, 0) 38%, rgba(249, 238, 219, 0) 62%, rgba(249, 238, 219, 0.07));
    pointer-events: none;
}
/* One slow revolution every 8 beats (two bars, 5.33 s), so the name on the
   label can be read as it turns; only while the song is the open gift. */
.three-gifts-sheet.three-gifts-sheet--current.three-gifts-song--spinning .three-gifts-record {
    animation: three-gifts-spin 5.333s linear infinite;
}
@keyframes three-gifts-spin {
    to { transform: rotate(360deg); }
}
/* The label pulses on the beat (breath, 0.667 s), phased to the score. */
.three-gifts-sheet.three-gifts-sheet--current .three-gifts-record-label-pulse {
    animation: three-gifts-pulse 0.667s var(--ease-breath) var(--three-gifts-beat-phase, 0s) infinite;
}
@keyframes three-gifts-pulse {
    0% { transform: scale(1.05); }
    40%, 100% { transform: scale(1); }
}
@keyframes three-gifts-pulse-calm {
    0% { transform: scale(1.015); }
    40%, 100% { transform: scale(1); }
}

/* The gold tonearm, settling onto the outer grooves. */
.three-gifts-tonearm {
    position: absolute;
    left: calc(50% + var(--three-gifts-rd) * 0.56);
    top: calc(var(--three-gifts-rd) * 0.02);
    width: 14px;
    height: calc(var(--three-gifts-rd) * 0.6);
    margin-left: -7px;
    transform-origin: 50% 7px;
    transform: rotate(22deg);
    z-index: 3;
}
.three-gifts-tonearm-pivot {
    position: absolute;
    left: 0;
    top: 0;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--wax-gold);
    box-shadow: 0 0 0 1px var(--accent-warm-deep), 0 2px 5px rgba(22, 5, 9, 0.5);
}
.three-gifts-tonearm-arm {
    position: absolute;
    left: 5.5px;
    top: 7px;
    width: 3px;
    bottom: 12px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--accent-warm-deep), var(--accent-warm-bright), var(--accent-warm));
}
.three-gifts-tonearm-head {
    position: absolute;
    left: 2px;
    bottom: 0;
    width: 10px;
    height: 15px;
    border-radius: 2px;
    background: var(--btn-fill);
    box-shadow: 0 2px 4px rgba(22, 5, 9, 0.5);
}

/* The sleeve the record came out of. */
.three-gifts-sleeve {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--three-gifts-sh);
    z-index: 2;
    border-radius: 6px;
    background:
        linear-gradient(180deg, rgba(184, 134, 47, 0) 0%, rgba(184, 134, 47, 0.16) 100%),
        var(--paper);
    box-shadow: inset 0 0 0 1px var(--paper-edge), inset 0 0 0 5px var(--paper), inset 0 0 0 6px var(--foil-line), 0 14px 30px rgba(22, 5, 9, 0.55);
}
.three-gifts-sleeve-foil {
    position: absolute;
    left: 50%;
    bottom: 16%;
    width: calc(var(--three-gifts-sh) * 0.42);
    aspect-ratio: 1;
    margin-left: calc(var(--three-gifts-sh) * -0.21);
    border-radius: 50%;
    border: 1.5px solid var(--accent-warm-deep);
    box-shadow: inset 0 0 0 4px var(--paper), inset 0 0 0 5px var(--accent-warm);
}
.three-gifts-sheet.three-gifts-song--live .three-gifts-sleeve-foil {
    bottom: 8px;
    width: 18px;
    margin-left: -9px;
}
/* The gold-framed 16:9 window: the iframe is made only on the recipient's tap. */
.three-gifts-yt {
    position: absolute;
    left: 12px;
    right: 12px;
    top: 12px;
    aspect-ratio: 16 / 9;
    display: none;
    overflow: hidden;
    border: 2px solid var(--accent-warm);
    border-radius: 4px;
    background: var(--void);
    box-shadow: 0 0 0 1px var(--accent-warm-deep), 0 0 18px rgba(226, 177, 85, 0.25);
}
.three-gifts-sheet.three-gifts-song--live .three-gifts-yt { display: block; }
.three-gifts-yt-frame {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

/* ───── Coupons ───── */
.three-gifts-sheet.three-gifts-sheet--coupons {
    grid-template-rows: auto minmax(0, 1fr);
    gap: 12px;
    padding: 16px 10px 0;
}
.three-gifts-tickets {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    touch-action: pan-y;
    -webkit-overflow-scrolling: touch;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 4px 6px 18px;
    scrollbar-width: thin;
    scrollbar-color: var(--foil-line-soft) transparent;
}
.three-gifts-ticket {
    position: relative;
    flex: none;
    display: flex;
    align-items: stretch;
    width: min(100%, 21rem);
    min-height: 96px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--ink);
    text-align: left;
    font: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.three-gifts-ticket:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
    border-radius: 9px;
}
.three-gifts-ticket-body {
    position: relative;
    isolation: isolate;
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-template-rows: 30px auto auto;
    align-content: center;
    gap: 4px;
    padding: 10px 14px 12px 16px;
}
/* The paper is painted by a pseudo-element, so the torn edge clips only the
   paper and never the stamp or its ring of light. */
.three-gifts-ticket-body::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border: 1px solid var(--foil-line);
    border-right: 0;
    border-radius: 8px 0 0 8px;
    background:
        radial-gradient(ellipse 120% 140% at 30% 30%, rgba(184, 134, 47, 0) 55%, var(--paper-shade) 100%),
        var(--paper);
    box-shadow: inset 0 0 0 3px var(--paper), inset 0 0 0 4px var(--foil-line-soft);
}
.three-gifts-ticket-kicker {
    align-self: center;
    font: 600 0.72rem/1.1 var(--font-body);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--wine);
    transition: opacity 0.25s var(--ease-silk);
}
.three-gifts-ticket-promise {
    display: block;
    font: 500 var(--three-gifts-fit, 1rem)/1.3 var(--font-display);
    color: var(--ink);
    overflow-wrap: anywhere;
}
.three-gifts-ticket-from {
    display: block;
    font: 400 1.3rem/1.15 var(--font-script);
    color: var(--ink-script);
    overflow-wrap: anywhere;
}
/* The stub, behind a perforation. */
.three-gifts-ticket-stub {
    position: relative;
    flex: 0 0 3.4rem;
    display: grid;
    place-items: center;
    border: 1px solid var(--foil-line);
    border-left: 2px dashed var(--coupon-perf);
    border-radius: 0 8px 8px 0;
    background:
        linear-gradient(90deg, var(--paper-shade), rgba(184, 134, 47, 0) 40%),
        var(--paper);
    box-shadow: inset 0 0 0 3px var(--paper), inset 0 0 0 4px var(--foil-line-soft);
}
.three-gifts-ticket-stub::before,
.three-gifts-ticket-stub::after {
    content: '';
    position: absolute;
    left: -8px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--bg-primary);
}
.three-gifts-ticket-stub::before { top: -8px; }
.three-gifts-ticket-stub::after { bottom: -8px; }
.three-gifts-ticket-star {
    width: 1.3rem;
    aspect-ratio: 1;
    background: var(--foil-gradient);
    clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%);
}
/* The REDEEMED stamp, in claret ink, with the day it was torn. It lands in
   the kicker's row: "Redeem anytime" gives way to the date it was redeemed. */
.three-gifts-ticket-stamp {
    position: absolute;
    right: 12px;
    top: 14px;
    padding: 0.32rem 0.5rem 0.28rem;
    border: 2px solid var(--coupon-stamp);
    border-radius: 6px;
    box-shadow: inset 0 0 0 2px var(--paper), inset 0 0 0 3px var(--coupon-stamp-ring);
    font: 600 0.72rem/1 var(--font-body);
    letter-spacing: 0.1em;
    white-space: nowrap;
    color: var(--coupon-stamp);
    transform: rotate(-8deg);
    opacity: 0;
    pointer-events: none;
}
/* The ring of light the stamp thuds out (pre-painted; only opacity and scale move). */
.three-gifts-ticket-ring {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 6.5rem;
    height: 6.5rem;
    margin: -3.25rem 0 0 -3.25rem;
    border-radius: 50%;
    border: 2px solid rgba(246, 220, 154, 0.9);
    box-shadow: 0 0 18px rgba(226, 177, 85, 0.55), inset 0 0 14px rgba(246, 220, 154, 0.4);
    opacity: 0;
    pointer-events: none;
}
/* Redeemed: the stub torn away along the perforation, the stamp on. */
.three-gifts-ticket.three-gifts-ticket--redeemed { cursor: default; }
.three-gifts-ticket.three-gifts-ticket--redeemed .three-gifts-ticket-stub {
    opacity: 0;
    transform: translate(28px, 150px) rotate(40deg);
}
.three-gifts-ticket.three-gifts-ticket--redeemed .three-gifts-ticket-body::before {
    clip-path: polygon(0 0, 100% 0, 98.4% 7%, 100% 14%, 98% 21%, 100% 28%, 98.3% 35%, 100% 42%, 98% 50%, 100% 57%,
        98.4% 64%, 100% 71%, 98% 78%, 100% 85%, 98.3% 92%, 100% 100%, 0 100%);
}
.three-gifts-ticket.three-gifts-ticket--redeemed .three-gifts-ticket-kicker { opacity: 0; }
.three-gifts-ticket.three-gifts-ticket--redeemed .three-gifts-ticket-stamp { opacity: 0.92; }

/* ───── The tab slots and the way on ───── */
.three-gifts-slots {
    position: absolute;
    left: 50%;
    bottom: var(--three-gifts-foot);
    display: flex;
    gap: var(--three-gifts-slot-gap);
    transform: translateX(-50%);
    opacity: 0;
    transition: opacity 0.6s var(--ease-silk);
}
.three-gifts-container.three-gifts--panel .three-gifts-slots { opacity: 1; }
.three-gifts-slot {
    display: block;
    width: var(--three-gifts-tab);
    height: var(--three-gifts-tab);
    border-radius: 10px;
    border: 1px dashed var(--foil-line-soft);
    transition: border-color 0.5s var(--ease-silk), background-color 0.5s var(--ease-silk);
}
/* The open gift's own place in the row. */
.three-gifts-slot.three-gifts-slot--current {
    border: 1px solid var(--foil-line-strong);
    background-color: rgba(226, 177, 85, 0.1);
}

.three-gifts-onward {
    position: absolute;
    left: 50%;
    bottom: calc(var(--three-gifts-foot) + var(--three-gifts-tab) + var(--three-gifts-gap));
    min-height: var(--three-gifts-onward-h);
    padding: 0 1.7rem;
    border: 1px solid var(--btn-ghost-border);
    border-radius: 999px;
    background: var(--glass);
    box-shadow: inset 0 1px 0 rgba(246, 220, 154, 0.22), 0 8px 24px rgba(22, 5, 9, 0.45);
    font: 500 0.95rem/1 var(--font-body);
    letter-spacing: 0.06em;
    color: var(--accent-warm-bright);
    cursor: pointer;
    white-space: nowrap;
    transform: translate(-50%, 8px);
    opacity: 0;
    visibility: hidden;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
    transition: opacity 0.5s var(--ease-silk), transform 0.7s var(--ease-expo-out), visibility 0s linear 0.5s;
}
.three-gifts-onward.three-gifts-onward--on {
    transform: translate(-50%, 0);
    opacity: 1;
    visibility: visible;
    transition: opacity 0.6s var(--ease-silk), transform 0.8s var(--ease-expo-out), visibility 0s linear 0s;
}
.three-gifts-onward:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
}

/* ═══════════ 0. The room: one lamp over the envelope (the exit) ═══════════
   Behind the table (the envelope stays lit), spanning -50%..150% of the
   stage vertically so the lowered camera never shows an edge. The-letter's
   room is built on exactly this box and these gradients, so the beat ends
   on its first frame. Pre-painted layers; only their opacity moves
   (20 -> 26 s). The envelope's centre (--env-x, --env-y) lands at 50% / 55%
   of this box. */
.three-gifts-room {
    position: absolute;
    left: -6%;
    right: -6%;
    top: -50%;
    height: 200%;
    z-index: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 6s var(--ease-silk);
}
.three-gifts-room-dim,
.three-gifts-room-lamp {
    position: absolute;
    inset: 0;
}
.three-gifts-room-dim {
    background: radial-gradient(calc(var(--env-w) * 1.05) calc(var(--env-w) * 0.82) at 50% 54%,
        rgba(22, 5, 9, 0) 0%, rgba(22, 5, 9, 0.2) 46%, var(--scrim) 100%);
}
.three-gifts-room-lamp {
    background:
        radial-gradient(calc(var(--env-w) * 0.78) calc(var(--env-w) * 0.5) at 50% 52%, var(--lamp-cone), rgba(246, 220, 154, 0) 100%),
        conic-gradient(from 180deg at 50% 25%, rgba(246, 220, 154, 0) 168deg, var(--lamp-cone) 177deg 183deg, rgba(246, 220, 154, 0) 192deg);
}
.three-gifts-container.three-gifts--lamp .three-gifts-room { opacity: 1; }
.three-gifts-container.three-gifts--lamp .three-gifts-letter { transform: translateY(-40px); }
.three-gifts-container.three-gifts--lamp .three-gifts-letter-glow { opacity: 1; }
.three-gifts-container.three-gifts--lamp .three-gifts-half,
.three-gifts-container.three-gifts--lamp .three-gifts-rest { opacity: 0; }

/* ═══════════ 5. The lines, under the envelope ═══════════ */
.three-gifts-line,
.three-gifts-hint {
    position: absolute;
    left: 16px;
    right: 16px;
    margin: 0;
    text-align: center;
    text-wrap: balance;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 1.2s var(--ease-silk), transform 1.6s var(--ease-expo-out);
}
/* Below the seal's halves on the table (the-seal's own line sat at +0.85 env-h). */
.three-gifts-line {
    top: calc(var(--env-y) + var(--env-h) * 0.9);
    font: italic 400 clamp(1.3rem, 5.6vw, 1.65rem)/1.25 var(--font-display);
    color: var(--text-primary);
    text-shadow: 0 0 22px var(--accent-warm-glow-soft), 0 1px 0 rgba(22, 5, 9, 0.7);
}
.three-gifts-hint {
    top: calc(var(--env-y) + var(--env-h) * 0.9 + 2.9rem);
    font: 500 0.74rem/1.3 var(--font-body);
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--text-secondary);
}
.three-gifts-line.three-gifts--on,
.three-gifts-hint.three-gifts--on {
    opacity: 1;
    transform: none;
}

/* ═══════════ 6. The full view ═══════════ */
.three-gifts-viewer {
    z-index: 6;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.35s var(--ease-silk), visibility 0s linear 0.35s, transform var(--cam-ms, 300ms) ease-out;
}
.three-gifts-viewer.three-gifts-viewer--open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.35s var(--ease-silk), visibility 0s linear 0s, transform var(--cam-ms, 300ms) ease-out;
}
.three-gifts-viewer-backdrop {
    position: absolute;
    inset: -4px;
    background: rgba(22, 5, 9, 0.93);
}
.three-gifts-viewer-track {
    position: absolute;
    inset: 0;
    display: flex;
    touch-action: none;
    transform: translate3d(calc(var(--three-gifts-k, 0) * -100% + var(--three-gifts-dx, 0px)), 0, 0);
    transition: transform 0.45s var(--ease-expo-out);
}
.three-gifts-viewer-track.three-gifts-viewer-track--drag { transition: none; }
.three-gifts-viewer-slide {
    flex: 0 0 100%;
    margin: 0;
    display: grid;
    place-items: center;
    min-width: 0;
}
/* The whole photo, uncropped, inside a gilt hairline: at most 88vw x 66vh. */
.three-gifts-viewer-frame {
    display: block;
    padding: 6px;
    border: 1px solid var(--foil-line-strong);
    background: rgba(50, 13, 22, 0.7);
    box-shadow: inset 0 0 0 1px rgba(226, 177, 85, 0.18), 0 24px 60px rgba(22, 5, 9, 0.7);
}
.three-gifts-viewer-frame img {
    display: block;
    width: auto;
    height: auto;
    max-width: calc(88vw - 14px);
    max-height: calc(66vh - 14px);
    -webkit-user-drag: none;
}
.three-gifts-viewer-btn {
    position: absolute;
    width: 44px;
    height: 44px;
    padding: 0;
    display: grid;
    place-items: center;
    border: 1px solid var(--btn-ghost-border);
    border-radius: 50%;
    background: var(--glass);
    color: var(--accent-warm-bright);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.three-gifts-viewer-btn:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
}
.three-gifts-viewer-close {
    top: calc(14px + env(safe-area-inset-top, 0px));
    left: 14px;
}
.three-gifts-viewer-x {
    position: relative;
    width: 16px;
    height: 16px;
}
.three-gifts-viewer-x::before,
.three-gifts-viewer-x::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 0;
    width: 1.5px;
    height: 100%;
    margin-left: -0.75px;
    background: currentColor;
    transform: rotate(45deg);
}
.three-gifts-viewer-x::after { transform: rotate(-45deg); }
.three-gifts-viewer-nav {
    position: absolute;
    left: 50%;
    bottom: calc(18px + env(safe-area-inset-bottom, 0px));
    width: 132px;
    height: 44px;
    margin-left: -66px;
}
.three-gifts-viewer-prev { left: 0; }
.three-gifts-viewer-next { right: 0; }
.three-gifts-viewer-btn.three-gifts-viewer-btn--off { visibility: hidden; }
.three-gifts-viewer-chev {
    width: 10px;
    height: 10px;
    border-left: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translateX(2px) rotate(45deg);
}
.three-gifts-viewer-next .three-gifts-viewer-chev { transform: translateX(-2px) rotate(-135deg); }

/* ═══════════ Reduced motion: the beat plays in full, calmer ═══════════
   Gifts open as cross-fades (the js fades them), the strips fade in frame by
   frame without a flash, the record does not turn (its label still pulses,
   gently), the tear is a cross-fade and the stamp fades in. */
@media (prefers-reduced-motion: reduce) {
    .three-gifts-gift-bob,
    .three-gifts-container.three-gifts--invite .three-gifts-bow-tail,
    .three-gifts-sheet.three-gifts-sheet--current.three-gifts-song--spinning .three-gifts-record {
        animation: none;
    }
    .three-gifts-sheet.three-gifts-sheet--current .three-gifts-record-label-pulse {
        animation-name: three-gifts-pulse-calm;
    }
    .three-gifts-gift {
        transition: opacity 0.4s var(--ease-silk);
    }
    .three-gifts-gift.three-gifts-gift--home {
        transform: none;
        transition: opacity 0.9s var(--ease-silk), visibility 0s linear 0.9s;
    }
    .three-gifts-gift.three-gifts-gift--open .three-gifts-gift-flap { transform: none; }
    .three-gifts-gift.three-gifts-gift--opened .three-gifts-gift-thread { transform: none; }
    .three-gifts-tag,
    .three-gifts-gift.three-gifts-gift--tagged .three-gifts-tag { transform: translate(-50%, 0); }
    .three-gifts-line,
    .three-gifts-hint { transform: none; }
    .three-gifts-onward,
    .three-gifts-onward.three-gifts-onward--on { transform: translate(-50%, 0); }
    .three-gifts-letter { transition: transform 1.8s var(--ease-silk); }
    .three-gifts-ticket.three-gifts-ticket--redeemed .three-gifts-ticket-stub { transform: none; }
    .three-gifts-viewer-track { transition-duration: 0.2s; }
}
