/* Not My Event: the shared base of the envelope cards (The Gold Seal, The Emerald Letter, Kitchen Table Mail, The Crayon Envelope, each as an invitation card and a thank-you card).
   A card is one screen and never scrolls: a closed envelope, a tap, the flap lifts, the card slides out, grows and settles in the middle of the screen with the words on it. That is all.
   A design (card-designs.css) sets its colours and fonts as variables on body.d-<name> and draws its own paper, seal and extras.
   Variables a design sets: --bg, --env-back, --env-l, --env-r, --env-b (the three pieces of the front pocket), --flap (outside of the flap), --flap-in (its inside), --edge (the outline),
   --paper, --ink, --ink-soft, --accent, --display, --body, --script.
   The page needs: .bg, .drift#drift, #mute, main.scene#scene holding .ev-back (with .f2), article.card#card, button.ev-front#env (with .pocket and .f1) and .cue. The behaviour is /assets/envelope-card.js.
   The stages of the opening are classes on the scene: go (the flap lifts), out (the card slides out), pop (it grows to full size and the envelope drops away), done (settled). */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
html, body { height: 100%; }
body { margin: 0; overflow: hidden; background: var(--bg, #1a1a1a); color: var(--ink, #222); font-family: var(--body, system-ui, sans-serif); -webkit-font-smoothing: antialiased; }
h1, p { margin: 0; }
button { font: inherit; color: inherit; cursor: pointer; }
:focus-visible { outline: 3px solid var(--accent, #c9a24b); outline-offset: 3px; }

/* The back layer and the front layer */
.bg { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.drift { position: fixed; inset: 0; z-index: 30; overflow: hidden; pointer-events: none; }
.dr { position: absolute; left: var(--l); top: -8vh; width: var(--s); height: var(--s); background: var(--c); opacity: 0; animation: dr-fall var(--d) linear var(--dl) infinite; will-change: transform; }
.drift.up .dr { top: auto; bottom: -8vh; animation-name: dr-rise; }
.dr-dot { border-radius: 50%; box-shadow: 0 0 calc(var(--s) * 1.3) var(--c); }
.dr-leaf { border-radius: 70% 0 70% 0; }
.dr-petal { border-radius: 60% 0 60% 0; }
.dr-chip { height: calc(var(--s) * .55); border-radius: 2px; }
.dr-star { clip-path: polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }
@keyframes dr-fall { 0% { transform: translate3d(0, 0, 0) rotate(0); opacity: 0; } 8% { opacity: var(--o, .85); } 50% { transform: translate3d(var(--w), 55vh, 0) rotate(190deg); } 92% { opacity: var(--o, .85); } 100% { transform: translate3d(calc(var(--w) * -1), 112vh, 0) rotate(380deg); opacity: 0; } }
@keyframes dr-rise { 0% { transform: translate3d(0, 0, 0) rotate(0); opacity: 0; } 10% { opacity: var(--o, .85); } 50% { transform: translate3d(var(--w), -55vh, 0) rotate(120deg); } 90% { opacity: var(--o, .85); } 100% { transform: translate3d(calc(var(--w) * -1), -112vh, 0) rotate(240deg); opacity: 0; } }
.mute { position: fixed; z-index: 150; top: calc(12px + env(safe-area-inset-top, 0px)); left: max(12px, env(safe-area-inset-left, 0px)); width: 46px; height: 46px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, .35); background: rgba(0, 0, 0, .42); color: #fff; font-size: 20px; line-height: 1; }
.mute[hidden] { display: none; }

/* ---------- The scene: everything is sized from the width of the envelope, so it fits any screen. --u is one hundredth of the card's width ---------- */
.scene { --H: 100svh; --ew: min(88vw, 470px, calc(var(--H) * .72 - 28px)); --eh: calc(var(--ew) * .66); --cw: calc(var(--ew) * 1.04); --ch: calc(var(--cw) * 1.3); --u: calc(var(--cw) / 100);
  position: fixed; inset: 0; z-index: 10; pointer-events: none; }
.scene > .ev-front, .scene > .card, .scene > .cue { pointer-events: auto; }
html.nme-edit .scene { --H: 54svh; bottom: 46svh; }

.ev-back, .ev-front { position: absolute; left: 50%; top: 50%; width: var(--ew); height: var(--eh); margin: calc(var(--eh) / -2) 0 0 calc(var(--ew) / -2); perspective: 1200px; }
.ev-back { z-index: 1; }
.ev-front { z-index: 3; padding: 0; border: 0; background: none; border-radius: 3px; -webkit-tap-highlight-color: transparent; }
.ev-front:disabled { cursor: default; }
.ev-back .body { position: absolute; inset: 0; border-radius: 3px; background: var(--env-back, #444); box-shadow: 0 24px 46px -16px rgba(0, 0, 0, .6), 0 0 0 1px var(--edge, rgba(0, 0, 0, .3)); }
.pocket { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* A solid layer under the pocket's three pieces, so nothing of the card can ever show through the closed envelope (a seam between the pieces, a pale colour, a shadow). It stops at the V-shaped opening, which the flap covers and which shows the card once the flap is lifted. */
.under { position: absolute; inset: 0; border-radius: 3px; background: var(--env-b, #666); clip-path: polygon(0 0, 50% 60%, 100% 0, 100% 100%, 0 100%); pointer-events: none; }
.pocket polygon, .flap polygon { stroke: var(--edge, rgba(0, 0, 0, .3)); stroke-width: 1.2; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.pocket .pl { fill: var(--env-l, #555); } .pocket .pr { fill: var(--env-r, #555); } .pocket .pb { fill: var(--env-b, #666); }
.flap { position: absolute; left: 0; top: 0; width: 100%; height: 60.6%; overflow: visible; transform-origin: 50% 0; }
.flap.f1 polygon { fill: var(--flap, #666); }
.flap.f2 { opacity: 0; transform: rotateX(-90deg); }
.flap.f2 polygon { fill: var(--flap-in, #333); }
.seal { position: absolute; z-index: 4; left: 50%; top: 60.6%; width: calc(var(--ew) * .17); height: calc(var(--ew) * .17); margin: calc(var(--ew) * -.085) 0 0 calc(var(--ew) * -.085); display: grid; place-items: center; border-radius: 50%; }
.ev-from { position: absolute; z-index: 2; left: 0; right: 0; bottom: 5%; text-align: center; font-size: calc(var(--ew) * .036); letter-spacing: .12em; text-transform: uppercase; opacity: .85; }

/* The card's shadow would spill out under a pale envelope, so it only comes on once the card starts to slide out */
.scene:not(.out):not(.pop):not(.done) .card { box-shadow: none !important; }
.card { position: absolute; z-index: 2; left: 50%; top: 50%; width: var(--cw); height: var(--ch); margin: calc(var(--ch) / -2) 0 0 calc(var(--cw) / -2); transform: scale(.435); transform-origin: 50% 50%; }
.card-in { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(var(--u) * 2.4); padding: calc(var(--u) * 8) calc(var(--u) * 8); overflow: hidden; text-align: center; }

/* Idle: the envelope breathes a little, so it looks like something to tap */
.scene:not(.go):not(.done) .ev-back, .scene:not(.go):not(.done) .ev-front, .scene:not(.go):not(.done) .card { animation: bob 3.8s ease-in-out infinite; }
@keyframes bob { 0%, 100% { translate: 0 0; } 50% { translate: 0 -5px; } }

/* The opening */
.go .ev-front .f1 { animation: f1flip .45s ease-in forwards; }
.go .ev-back .f2 { animation: f2flip .5s ease-out .44s forwards; }
@keyframes f1flip { 0% { transform: rotateX(0); opacity: 1; } 99% { transform: rotateX(-90deg); opacity: 1; } 100% { transform: rotateX(-90deg); opacity: 0; } }
@keyframes f2flip { 0% { transform: rotateX(-90deg); opacity: 1; } 100% { transform: rotateX(-180deg); opacity: 1; } }
.go .seal { animation: sealgo .42s ease-in forwards; }
@keyframes sealgo { 35% { transform: scale(1.22); opacity: 1; } 100% { transform: scale(.2) rotate(50deg); opacity: 0; } }
.out .card { animation: cardout 1s cubic-bezier(.3, .7, .3, 1) forwards; }
@keyframes cardout { from { transform: translateY(0) scale(.435); } to { transform: translateY(calc(var(--ew) * -.66)) scale(.435); } }
.pop .card { z-index: 5; animation: cardpop 1.25s cubic-bezier(.22, 1.2, .36, 1) forwards; }
@keyframes cardpop { from { transform: translateY(calc(var(--ew) * -.66)) scale(.435); } to { transform: translateY(0) scale(1); } }
.pop .ev-back, .pop .ev-front { animation: envdrop 1.2s cubic-bezier(.55, 0, .9, .6) .1s forwards; }
@keyframes envdrop { to { transform: translateY(80svh) rotate(6deg); opacity: 0; } }
.done .ev-back, .done .ev-front { display: none; }
.done .card { transform: none; animation: cardfloat 7s ease-in-out infinite; }
@keyframes cardfloat { 0%, 100% { translate: 0 0; } 50% { translate: 0 -4px; } }

/* What to tap, under the envelope */
.cue { position: absolute; z-index: 6; left: 0; right: 0; top: calc(50% + var(--eh) / 2 + 26px); display: grid; justify-items: center; gap: 8px; padding: 0 20px; text-align: center; transition: opacity .5s ease; }
.go .cue, .done .cue, html.nme-edit .cue { opacity: 0; pointer-events: none; }
.tap-hint { font-size: clamp(13px, 2.6vw, 16px); letter-spacing: .22em; text-transform: uppercase; animation: hint 2.2s ease-in-out infinite; }
@keyframes hint { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
.quiet { min-height: 44px; padding: 6px 14px; border: 0; background: none; font-size: 14px; text-decoration: underline; text-underline-offset: 3px; opacity: .8; }

/* The words on the card. Sizes are fractions of the card's width, so the card looks the same on a phone and on a desktop. */
.kicker { font-size: calc(var(--u) * 3.9); letter-spacing: .16em; text-transform: uppercase; line-height: 1.35; max-width: 26ch; }
.title { font-size: calc(var(--u) * var(--t1, 12.5)); font-weight: 400; line-height: 1.04; text-wrap: balance; overflow-wrap: anywhere; }
.t-m .title { font-size: calc(var(--u) * var(--t2, 10.2)); }
.t-l .title { font-size: calc(var(--u) * var(--t3, 8.2)); }
.invited { font-size: calc(var(--u) * 7.2); line-height: 1.15; }
.rule { display: flex; align-items: center; justify-content: center; gap: calc(var(--u) * 3); width: 62%; }
.rule span { flex: 1; height: 1px; background: currentColor; opacity: .5; }
.facts { display: grid; gap: calc(var(--u) * 1.6); }
.when, .where { font-size: calc(var(--u) * 5.3); line-height: 1.25; text-wrap: balance; }
.note { font-size: calc(var(--u) * 4.2); font-style: italic; line-height: 1.4; max-width: 31ch; text-wrap: balance; }
.n-l .note { font-size: calc(var(--u) * 3.6); }
.note[hidden], .to[hidden] { display: none; }
.hope, .sign { font-size: calc(var(--u) * 6.6); line-height: 1.2; }
.to { font-size: calc(var(--u) * 6); line-height: 1.2; }
.thanks-line { font-size: calc(var(--u) * 5.6); line-height: 1.3; text-wrap: balance; }
.thanks-line b { font-weight: inherit; display: block; font-size: 1.28em; line-height: 1.1; margin-top: .1em; }

@media (prefers-reduced-motion: reduce) {
  .drift { display: none; }
  .tap-hint, .dr, .done .card, .scene:not(.go):not(.done) .ev-back, .scene:not(.go):not(.done) .ev-front, .scene:not(.go):not(.done) .card { animation: none; }
  .go .ev-front .f1, .go .ev-back .f2, .go .seal, .out .card, .pop .card, .pop .ev-back, .pop .ev-front { animation-duration: .01ms; animation-delay: 0s; }
}

/* ---------- The scratch-off: a circle of foil over a prize (kind "scratch") ---------- */
.scratch { position: relative; flex: none; width: calc(var(--u) * 36); height: calc(var(--u) * 36); border-radius: 50%; touch-action: none; }
.t-m .scratch, .t-l .scratch, .n-l .scratch { width: calc(var(--u) * 31); height: calc(var(--u) * 31); }
.prize { position: absolute; inset: 0; z-index: 1; display: grid; place-content: center; justify-items: center; gap: calc(var(--u) * 1); padding: calc(var(--u) * 3.5); border-radius: 50%; overflow: hidden; text-align: center; }
.prize::before { content: ""; position: absolute; inset: -40%; z-index: -1; background: repeating-conic-gradient(var(--ray1, #fff1c2) 0 9deg, var(--ray2, #ffe29a) 9deg 18deg); opacity: 0; transition: opacity .8s ease; }
.revealed .prize::before { opacity: 1; animation: rays 30s linear infinite; }
@keyframes rays { to { transform: rotate(360deg); } }
.p-label { font-size: calc(var(--u) * 2.9); letter-spacing: .22em; text-transform: uppercase; }
.p-text { font-size: calc(var(--u) * 11.5); font-weight: 400; line-height: 1.02; overflow-wrap: anywhere; text-wrap: balance; }
.p-m .p-text { font-size: calc(var(--u) * 8.4); } .p-l .p-text { font-size: calc(var(--u) * 6.3); } .p-xl .p-text { font-size: calc(var(--u) * 5); }
.foil { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; border-radius: 50%; cursor: pointer; touch-action: none; -webkit-touch-callout: none; user-select: none; transition: opacity .7s ease; }
.revealed .foil { opacity: 0; pointer-events: none; }
.revealed.instant .foil, .revealed.instant .prize::before { transition: none; }
.revealed .p-text { animation: prize-in .85s cubic-bezier(.2, 1.5, .4, 1) both; }
.revealed.instant .p-text { animation: none; }
@keyframes prize-in { from { opacity: 0; transform: scale(.4) rotate(-6deg); } to { opacity: 1; transform: none; } }
.scratch:not(.revealed)::before { content: ""; position: absolute; inset: 0; z-index: 3; border-radius: 50%; pointer-events: none; background: linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, .6) 50%, transparent 62%) 0 0 / 260% 100%; background-position: 130% 0; mix-blend-mode: soft-light; animation: glint 3.6s ease-in-out 1.2s infinite; }
@keyframes glint { 0% { background-position: 130% 0; } 55%, 100% { background-position: -30% 0; } }
.scratch:not(.revealed):not(.touched)::after { content: ""; position: absolute; inset: -5%; z-index: 0; border-radius: 50%; border: 2px solid var(--ring, rgba(255, 220, 140, .8)); pointer-events: none; animation: ringout 2.2s ease-out infinite; }
@keyframes ringout { 0% { transform: scale(.96); opacity: .9; } 100% { transform: scale(1.22); opacity: 0; } }
.fl { position: absolute; z-index: 4; width: 5px; height: 5px; margin: -2px 0 0 -2px; border-radius: 1px; background: var(--flake, #f0cf75); pointer-events: none; animation: flake .85s ease-in forwards; }
@keyframes flake { to { transform: translate(var(--dx), calc(var(--dy) + 44px)) rotate(var(--r)); opacity: 0; } }
.scratch-hint { font-size: calc(var(--u) * 3.5); letter-spacing: .16em; text-transform: uppercase; line-height: 1.3; max-width: 30ch; animation: hint 2.2s ease-in-out infinite; }
.scratch-hint.claim { animation: none; text-transform: none; letter-spacing: .02em; font-style: italic; font-size: calc(var(--u) * 4.3); }
@media (prefers-reduced-motion: reduce) {
  .scratch::before, .scratch::after, .revealed .prize::before, .scratch-hint { animation: none; }
  .revealed .p-text { animation-duration: .01ms; } .fl { display: none; }
}

/* ---------- A live back layer: things to tap (data-prop), and a speech bubble when one talks ---------- */
.prop { position: absolute; z-index: 1; padding: 0; border: 0; background: none; cursor: pointer; pointer-events: auto; -webkit-tap-highlight-color: transparent; transition: opacity .4s ease, scale .4s ease; }
.prop svg { display: block; width: 100%; height: auto; overflow: visible; pointer-events: none; }
.prop.gone { opacity: 0; scale: .2; pointer-events: none; }
.prop.hit { animation: prop-hit .7s cubic-bezier(.3, 1.6, .5, 1); }
@keyframes prop-hit { 0% { transform: scale(1); } 22% { transform: scale(1.22, .8) rotate(-4deg); } 55% { transform: scale(.92, 1.1) rotate(4deg); } 100% { transform: scale(1); } }
.bub { position: fixed; z-index: 40; max-width: 190px; padding: 6px 12px; border-radius: 14px; background: #fff; color: #2a1a10; font: 700 14px / 1.25 system-ui, sans-serif; text-align: center; box-shadow: 0 6px 16px rgba(0, 0, 0, .35); pointer-events: none; transform: translate(-50%, calc(-100% - 8px)); animation: bub-in 2.4s ease both; }
.bub::after { content: ""; position: absolute; left: 50%; bottom: -6px; width: 12px; height: 12px; margin-left: -6px; background: inherit; transform: rotate(45deg); border-radius: 0 0 3px 0; }
@keyframes bub-in { 0% { opacity: 0; transform: translate(-50%, calc(-100% + 4px)) scale(.7); } 10%, 82% { opacity: 1; transform: translate(-50%, calc(-100% - 8px)) scale(1); } 100% { opacity: 0; transform: translate(-50%, calc(-100% - 20px)) scale(1); } }
@media (prefers-reduced-motion: reduce) { .prop.hit, .bub { animation-duration: .01ms; } }
