/* Performance rules for this file: everything that moves while scrolling animates only
   transform / opacity (compositor-only). No filter blur, no backdrop-filter, no animated
   gradients or box-shadows — those repaint every frame and stutter on iPhone. */
:root {
  --bg: #fbfaf7; --ink: #111116; --ink-2: #3a3a44; --muted: #7a7a86; --line: rgba(17,17,22,.09);
  --holo: #b9c3ff, #d9c2ff, #ffc6e2, #ffe3b0, #c6f1e0, #b9d8ff, #b9c3ff;
  --serif: 'Instrument Serif', 'Times New Roman', serif;
  --sans: 'Geist', -apple-system, system-ui, sans-serif;
  --mono: 'Geist Mono', ui-monospace, monospace;
  --ease: cubic-bezier(.2,.7,.2,1);
  --out: cubic-bezier(.25,.75,.3,1);
  --spring: cubic-bezier(.34,1.56,.64,1);
}
* { box-sizing: border-box; margin: 0; }
html { -webkit-text-size-adjust: 100%; overflow-x: clip; }
body { background: var(--bg); color: var(--ink); font-family: var(--sans); overflow-x: clip; -webkit-font-smoothing: antialiased; -webkit-tap-highlight-color: transparent; }
button, input, textarea { font: inherit; color: inherit; }
::selection { background: #ffd6ec; }

.names .amp, h2 em, .words em, .tagline em, .mono-mark em, .intro em, .end-names em {
  background: linear-gradient(100deg, #8b93f8, #e879b8 45%, #d9a441); -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ---------- intro ---------- */
.intro { position: fixed; inset: 0; z-index: 100; background: var(--bg); display: grid; place-items: center; pointer-events: none;
  animation: introOut .6s 1.3s ease forwards; }
.intro-in { display: grid; justify-items: center; gap: 18px; animation: introZoom .9s 1.15s cubic-bezier(.6,0,.2,1) forwards; }
.intro svg { width: 150px; overflow: visible; }
.intro circle { fill: none; stroke-width: 4; stroke-linecap: round; stroke-dasharray: 227; stroke-dashoffset: 227; animation: draw 1s var(--ease) forwards; }
.intro .ib { animation-delay: .2s; }
.intro p { font: 400 28px/1 var(--serif); opacity: 0; animation: fadeUp .7s .45s var(--ease) forwards; }
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes introOut { to { opacity: 0; visibility: hidden; } }
@keyframes introZoom { to { transform: scale(1.18); } }
@keyframes fadeUp { from { opacity: 0; transform: translate3d(0, 10px, 0); } to { opacity: 1; transform: none; } }

/* ---------- ambient ---------- */
.aura { position: fixed; inset: 0; z-index: -3; overflow: hidden; }
.aura i { position: absolute; border-radius: 50%; will-change: transform; }
.aura i:nth-child(1) { width: 90vmax; height: 90vmax; left: -45vmax; top: -40vmax; background: radial-gradient(closest-side, #e2e6ff, rgba(226,230,255,0)); animation: drift 20s ease-in-out infinite alternate; }
.aura i:nth-child(2) { width: 80vmax; height: 80vmax; right: -42vmax; top: 20svh; background: radial-gradient(closest-side, #ffdfee, rgba(255,223,238,0)); animation: drift 24s -8s ease-in-out infinite alternate-reverse; }
.aura i:nth-child(3) { width: 75vmax; height: 75vmax; left: -18vmax; bottom: -45vmax; background: radial-gradient(closest-side, #fff0d2, rgba(255,240,210,0)); animation: drift 22s -14s ease-in-out infinite alternate; }
@keyframes drift { to { transform: translate3d(8vmax, 6vmax, 0); } }
.grain { position: fixed; inset: 0; z-index: -2; pointer-events: none; opacity: .55;
  background-image: radial-gradient(rgba(17,17,22,.08) 1px, transparent 1.2px); background-size: 22px 22px;
  -webkit-mask: radial-gradient(ellipse 90% 60% at 50% 40%, #000, transparent 80%); mask: radial-gradient(ellipse 90% 60% at 50% 40%, #000, transparent 80%); }
.dust { position: fixed; inset: 0; z-index: -1; pointer-events: none; }
.dust i { position: absolute; width: var(--s); height: var(--s); border-radius: 50%; background: var(--c); opacity: 0; will-change: transform, opacity;
  animation: twinkle var(--t) var(--dl) ease-in-out infinite alternate; }
@keyframes twinkle { from { opacity: 0; transform: translate3d(0, 24px, 0); } to { opacity: .75; transform: translate3d(0, -24px, 0); } }
#fx { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 40; pointer-events: none; }

.progress { position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 60; }
.progress i { display: block; height: 100%; transform-origin: 0 50%; transform: scaleX(0); background: linear-gradient(90deg, #a5b4fc, #f9a8d4, #e0b35a); will-change: transform; }
.sda .progress i { animation-name: grow; animation-timing-function: linear; animation-fill-mode: both; animation-duration: auto; animation-timeline: scroll(root); }
@keyframes grow { to { transform: scaleX(1); } }

.topbar { position: fixed; z-index: 50; top: max(10px, env(safe-area-inset-top)); left: 12px; right: 12px; display: flex; justify-content: space-between; pointer-events: none; }
.topbar > * { pointer-events: auto; display: inline-flex; align-items: center; padding: 9px 13px; border-radius: 999px; background: rgba(251,250,247,.88);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.9), 0 6px 20px -12px rgba(30,30,60,.3); font: 500 11px/1 var(--mono); letter-spacing: .14em; color: var(--ink); text-decoration: none; }
.topbar .mono-mark { font: 400 18px/1 var(--serif); letter-spacing: .02em; padding: 6px 13px; }
.pulse { position: relative; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: #f472b6; margin-right: 8px; flex: none; }
.pulse::after { content: ''; position: absolute; inset: 0; border-radius: 50%; background: #f472b6; animation: ping 2s ease-out infinite; }
@keyframes ping { from { transform: scale(1); opacity: .55; } 70%, to { transform: scale(3.2); opacity: 0; } }

.eyebrow { font: 500 11px/1 var(--mono); letter-spacing: .32em; text-transform: uppercase; color: var(--muted); }
.in { display: inline-block; opacity: 0; animation: fadeUp 1s calc(1.45s + var(--d, 0) * 90ms) var(--ease) forwards; }

/* ---------- scroll-scrubbed animations ----------
   Every [data-r="a b"] element plays its keyframes while its section scrolls from a to b
   (0 = section's sticky stage pins, 1 = it unpins; negatives = while the section scrolls in).
   Modern browsers (Safari 26+, Chrome) run this on the compositor via scroll timelines;
   older ones get the same keyframes driven from JS (fx.js). */
[data-r] { animation-duration: 1000ms; animation-timing-function: linear; animation-fill-mode: both; animation-play-state: paused; }
.sda [data-r] { animation-play-state: running; animation-duration: auto; }
.s1 { view-timeline: --s1 block; } .sda .s1 [data-r] { animation-timeline: --s1; }
.s2 { view-timeline: --s2 block; } .sda .s2 [data-r] { animation-timeline: --s2; }
.s3 { view-timeline: --s3 block; } .sda .s3 [data-r] { animation-timeline: --s3; }

.fade-out { animation-name: fadeOut; } @keyframes fadeOut { to { opacity: 0; visibility: hidden; } }
.fade-in { animation-name: fadeIn; } @keyframes fadeIn { from { opacity: 0; } }
.rise { animation-name: rise; } @keyframes rise { from { opacity: 0; transform: translate3d(0, 22px, 0); animation-timing-function: cubic-bezier(.25,.75,.3,1); } to { opacity: 1; transform: none; } }
@keyframes show { from { opacity: 0; } to { opacity: 1; } }

/* ---------- scenes ---------- */
.scene { position: relative; }
.stage { position: sticky; top: 0; height: 100svh; overflow: hidden; display: grid; place-items: center; text-align: center; }

/* 1 · names + rings */
.s1 { height: 200svh; }
.s1 .stage { --rw: min(118vw, 900px, 110svh); grid-template-rows: 1fr auto 1fr; padding: 70px 16px 30px; }
.s1 .eyebrow { align-self: end; margin-bottom: 4svh; }
.names { position: relative; z-index: 2; width: min(92vw, 820px); display: grid; justify-items: center; font: 400 clamp(64px, min(25vw, 24svh), 210px)/.82 var(--serif); letter-spacing: -.02em; }
.names > span { display: block; will-change: transform, opacity; }
.names .n1 { justify-self: start; animation-name: n1; }
.names .n2 { justify-self: end; animation-name: n2; }
.names .amp { font-style: italic; font-size: .7em; line-height: .95; animation-name: amp; }
@keyframes n1 { from { transform: none; opacity: 1; animation-timing-function: cubic-bezier(.25,.75,.3,1); } 40% { opacity: 1; } to { transform: translate3d(24vw, 16svh, 0) rotate(-4deg); opacity: 0; } }
@keyframes n2 { from { transform: none; opacity: 1; animation-timing-function: cubic-bezier(.25,.75,.3,1); } 40% { opacity: 1; } to { transform: translate3d(-24vw, -16svh, 0) rotate(-4deg); opacity: 0; } }
@keyframes amp { from { transform: none; opacity: 1; animation-timing-function: cubic-bezier(.25,.75,.3,1); } 15% { opacity: 1; } 60% { opacity: 0; } to { transform: translate3d(0, -8svh, 0) rotate(-20deg); opacity: 0; } }
.ch { display: inline-block; opacity: 0; transform: translate3d(0, 55%, 0) rotate(6deg); animation: chIn 1.1s calc(1.4s + var(--i) * 55ms) var(--ease) forwards; }
.amp .ch { padding: 0 .08em; }
@keyframes chIn { to { opacity: 1; transform: none; } }
.names.settled .ch { animation: none; opacity: 1; transform: none; }

.rings { position: absolute; left: 50%; top: 50%; width: var(--rw); aspect-ratio: 4 / 3; translate: -50% -50%; z-index: 1; pointer-events: none; will-change: transform, opacity; animation-name: rings; }
@keyframes rings {
  from { opacity: .3; transform: rotate(-14deg); animation-timing-function: cubic-bezier(.25,.75,.3,1); }
  40% { opacity: 1; }
  60%, to { transform: none; opacity: 1; }
}
.ring { position: absolute; left: 50%; top: 50%; width: 35%; aspect-ratio: 1; margin: -17.5% 0 0 -17.5%; will-change: transform; }
.ring svg { display: block; width: 100%; height: 100%; overflow: visible; }
.ring .rbody { fill: none; stroke-width: 11; }
.ring .rhl { fill: none; stroke: rgba(255,255,255,.78); stroke-width: 1.1; }
.spin { animation: spin 18s linear infinite; will-change: transform; }
.spin.rev { animation-direction: reverse; animation-duration: 22s; }
@keyframes spin { to { transform: rotate(360deg); } }
.ra { animation-name: ra; }
.rb { animation-name: rb; }
@keyframes ra { from { transform: translate3d(-122.86%, 0, 0); animation-timing-function: cubic-bezier(.25,.75,.3,1); } to { transform: translate3d(-27.14%, 0, 0); } }
@keyframes rb { from { transform: translate3d(122.86%, 0, 0); animation-timing-function: cubic-bezier(.25,.75,.3,1); } to { transform: translate3d(27.14%, 0, 0); } }
/* a copy of the gold ring, clipped to the top crossing and drawn over the other ring: that's the interlock */
.weave { transform: translate3d(-27.14%, 0, 0); clip-path: circle(10% at 77.14% 15%); animation-name: show; }
.gem { position: absolute; left: 50%; top: 33.67%; width: 6%; aspect-ratio: 1; margin: -3% 0 0 -3%; animation-name: gem; }
.gem i { display: block; width: 100%; height: 100%; background: radial-gradient(circle, #fff 30%, #fff5da 60%, #ffd6ec);
  clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%); animation: gemTw 1.6s ease-in-out infinite alternate; }
@keyframes gem { from { opacity: 0; transform: scale(.2) rotate(-90deg); animation-timing-function: cubic-bezier(.25,.75,.3,1); } to { opacity: 1; transform: none; } }
@keyframes gemTw { from { transform: scale(.7) rotate(0deg); } to { transform: scale(1.15) rotate(45deg); } }
.spark { position: absolute; left: 50%; top: 33.67%; width: 0; height: 0; }
.spark i { position: absolute; left: 0; top: 0; transform: rotate(var(--r)); }
.spark b { position: absolute; left: -8px; top: -8px; width: 16px; height: 16px; opacity: 0; background: var(--c);
  clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); }
.spark.pop b { animation: sparkOut var(--t) cubic-bezier(.15,.75,.3,1) forwards; }
@keyframes sparkOut { from { opacity: 1; transform: translate3d(0, 0, 0) scale(1.2); } 70% { opacity: .9; } to { opacity: 0; transform: translate3d(125px, 0, 0) scale(.2); } }
.glow { position: absolute; inset: 18% 22%; border-radius: 50%; background: radial-gradient(closest-side, rgba(255,226,170,.6), rgba(249,168,212,.28) 55%, rgba(249,168,212,0)); animation-name: show; }

/* pinned just under the locked rings, whatever the screen shape */
.tagline { position: absolute; left: 12px; right: 12px; top: calc(50% + var(--rw) * .2 + 2svh); font: 400 clamp(28px, 7.6vw, 46px)/1.15 var(--serif); z-index: 2; }
.tagline span { display: inline-block; animation-name: rise; }
/* "scroll down" cue: tappable, takes you through the rings animation */
.hint { position: absolute; bottom: max(92px, calc(env(safe-area-inset-bottom) + 80px)); left: 50%; translate: -50% 0; z-index: 3; }
.cue { display: flex; flex-direction: column; align-items: center; gap: 10px; border: 0; background: none; padding: 6px 10px; cursor: pointer; color: var(--ink); -webkit-tap-highlight-color: transparent; }
.cue-t { padding: 10px 16px; border-radius: 999px; background: rgba(255,255,255,.88); box-shadow: inset 0 0 0 1px rgba(255,255,255,.95), 0 10px 26px -14px rgba(30,30,60,.45);
  font: 500 11px/1 var(--mono); letter-spacing: .2em; text-transform: uppercase; white-space: nowrap; }
.chev { position: relative; display: block; width: 20px; height: 30px; }
.chev i { position: absolute; left: 50%; width: 11px; height: 11px; margin-left: -5.5px; border-right: 1.8px solid var(--ink); border-bottom: 1.8px solid var(--ink); opacity: 0;
  transform: rotate(45deg); animation: chev 1.5s ease-in-out infinite; }
.chev i:nth-child(1) { top: 0; }
.chev i:nth-child(2) { top: 8px; animation-delay: .18s; }
.chev i:nth-child(3) { top: 16px; animation-delay: .36s; }
@keyframes chev { 0% { opacity: 0; transform: translate3d(0, -5px, 0) rotate(45deg); } 40% { opacity: 1; } 80%, 100% { opacity: 0; transform: translate3d(0, 6px, 0) rotate(45deg); } }
/* if nobody scrolls for a few seconds, the names hop up a little: "there's more below" */
.nudge .names { animation: nudge 1.3s cubic-bezier(.3,.7,.3,1); }
@keyframes nudge { 0%, 100% { transform: none; } 22% { transform: translate3d(0, -26px, 0); } 45% { transform: none; } 60% { transform: translate3d(0, -10px, 0); } 75% { transform: none; } }

/* 2 · date odometer */
.s2 { height: 138svh; margin-top: -25svh; } /* slides in under the tagline while scene 1 is still pinned */
.s2 .stage { align-content: center; gap: 22px; padding: 70px 16px 40px; }
.odo { display: grid; animation-name: tilt; will-change: transform, opacity; }
@keyframes tilt { from { opacity: 0; transform: translate3d(0, 70px, 0); animation-timing-function: cubic-bezier(.25,.75,.3,1); } 35% { opacity: 1; } to { opacity: 1; transform: none; } }
.odo .row { display: flex; align-items: center; justify-content: center; gap: 12px; }
.odo .lbl { font: 500 10px/1 var(--mono); letter-spacing: .3em; text-transform: uppercase; color: var(--muted); writing-mode: vertical-rl; transform: rotate(180deg); }
.digits { display: inline-flex; font: 200 clamp(64px, min(27vw, 19svh), 200px)/1 var(--sans); letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
/* clip-path (not mask) keeps Safari from drawing the rolling strip outside its window */
.digit { position: relative; display: block; height: 1em; width: .6em; overflow: hidden; clip-path: inset(0); }
.digit i { position: absolute; left: 0; right: 0; top: 0; display: block; font-style: normal; will-change: transform; }
.digit i b { display: block; height: 1em; font-weight: inherit; text-align: center; }
.row:nth-child(2) .digit i b { background: linear-gradient(160deg, #8b93f8, #e879b8 50%, #d9a441); -webkit-background-clip: text; background-clip: text; color: transparent; }
.weekday { font: 400 italic 25px/1 var(--serif); color: var(--ink-2); }
.live { display: inline-flex; align-items: center; gap: 2px; padding: 12px 17px; border-radius: 999px; background: rgba(255,255,255,.82);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.95), 0 10px 30px -18px rgba(30,30,60,.4); font: 500 12px/1 var(--mono); letter-spacing: .05em; font-variant-numeric: tabular-nums; }
.live .pulse { width: 7px; height: 7px; margin-right: 10px; }
.live.party { font-family: var(--serif); font-size: 19px; letter-spacing: 0; padding: 11px 20px; }

/* 3 · words lighting up */
.s3 { height: 165svh; margin-top: -30svh; }
.s3 .stage { padding: 70px 22px; }
.words { max-width: 12em; font: 400 clamp(42px, 12vw, 86px)/1.04 var(--serif); letter-spacing: -.01em; animation-name: grow; }
@keyframes grow { from { transform: translate3d(0, 40px, 0); animation-timing-function: cubic-bezier(.25,.75,.3,1); } to { transform: none; } }
.words .w { display: inline-block; animation-name: lit; will-change: opacity, transform; }
@keyframes lit { from { opacity: .1; transform: translate3d(0, .14em, 0); animation-timing-function: cubic-bezier(.25,.75,.3,1); } to { opacity: 1; transform: none; } }

/* 4 · marquee (pure CSS loop) */
.marquee { padding: 6svh 0 2svh; overflow: hidden; display: grid; gap: 2px; }
.mq { display: flex; width: max-content; white-space: nowrap; will-change: transform; animation: mq 40s linear infinite; }
.mq div { flex: none; padding-right: .3em; }
.m1 { font: 400 italic clamp(46px, 13vw, 110px)/1.1 var(--serif); }
.m2 { font: 300 clamp(40px, 12vw, 100px)/1.05 var(--sans); letter-spacing: -.02em; color: transparent; -webkit-text-stroke: 1px rgba(17,17,22,.32); animation-duration: 30s; animation-direction: reverse; }
@keyframes mq { to { transform: translate3d(-50%, 0, 0); } }

/* ---------- upload ---------- */
.upload { width: min(100%, 480px); margin: 0 auto; padding: 6svh 16px 20px; scroll-margin-top: 30px; }
.up-head { text-align: center; margin-bottom: 26px; }
.up-head h2 { margin-top: 14px; font: 400 clamp(48px, 13.5vw, 74px)/.95 var(--serif); letter-spacing: -.015em; }
.up-head .sub { margin: 16px auto 0; max-width: 30ch; color: var(--ink-2); font-size: 15.5px; line-height: 1.55; }
.reveal { opacity: 0; transform: translate3d(0, 40px, 0); transition: opacity 1s var(--ease), transform 1s var(--ease); }
.reveal.on { opacity: 1; transform: none; }

.card { position: relative; border-radius: 30px; padding: 16px; background: rgba(255,255,255,.74); box-shadow: inset 0 1px 0 #fff, 0 40px 80px -40px rgba(40,40,90,.38); }
.card::before, .send::before, .fab::before { content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1.2px; pointer-events: none;
  background: conic-gradient(from 210deg, var(--holo));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; }
.card.drag { box-shadow: 0 0 0 6px rgba(196,181,253,.35), 0 40px 80px -40px rgba(40,40,90,.38); }
.st { display: none; }
.card[data-state=pick] .st-pick, .card[data-state=sending] .st-sending, .card[data-state=done] .st-done, .card[data-state=full] .st-full { display: block; animation: stIn .55s var(--ease); }
@keyframes stIn { from { opacity: 0; transform: translate3d(0, 10px, 0) scale(.98); } }

.tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; perspective: 700px; }
.tile { position: relative; overflow: hidden; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 16px 14px 15px; border-radius: 22px; cursor: pointer; background: #fff;
  box-shadow: 0 1px 0 rgba(17,17,22,.04), 0 14px 30px -20px rgba(40,40,90,.45), inset 0 0 0 1px var(--line);
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--s, 1)); transition: transform .4s var(--ease); }
.tile input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.tile:focus-within { outline: 2px solid #c4b5fd; outline-offset: 2px; }
.foil { position: absolute; inset: 0; pointer-events: none; opacity: var(--fo, 0); transition: opacity .5s; mix-blend-mode: multiply;
  background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), transparent 0, rgba(255,255,255,.9) 70%), conic-gradient(from var(--fa, 0deg) at var(--mx, 50%) var(--my, 50%), var(--holo)); }
.ico { position: relative; width: 44px; height: 44px; border-radius: 15px; display: grid; place-items: center; margin-bottom: 12px; background: var(--bg); }
.ico::before { content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1.2px; background: conic-gradient(from 200deg, var(--holo));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; }
.ico svg, .send svg, .fab svg { position: relative; width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.t1 { position: relative; font-weight: 600; font-size: 16px; letter-spacing: -.01em; }
.t2 { position: relative; font: 400 11px/1.3 var(--mono); letter-spacing: .03em; color: var(--muted); }

.thumbs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.thumbs:not(:empty) { margin-top: 12px; }
.th { position: relative; aspect-ratio: 1; border-radius: 14px; overflow: hidden; background: #efeef3; animation: pop .45s var(--spring) both; }
@keyframes pop { from { transform: scale(.6); opacity: 0; } }
.th img, .th video { position: relative; width: 100%; height: 100%; object-fit: cover; display: block; }
.th .ph { position: absolute; inset: 0; display: grid; place-items: center; font: 500 10px/1 var(--mono); color: var(--muted); }
.th .play { position: absolute; left: 6px; bottom: 6px; font: 500 9px/1 var(--mono); color: #fff; background: rgba(0,0,0,.45); padding: 3px 5px; border-radius: 6px; }
.rm { position: absolute; top: 4px; right: 4px; width: 26px; height: 26px; border-radius: 50%; border: 0; background: rgba(255,255,255,.94); font-size: 17px; line-height: 1; cursor: pointer; display: grid; place-items: center; box-shadow: 0 2px 8px rgba(0,0,0,.15); }
.count { font: 500 11px/1 var(--mono); letter-spacing: .03em; color: var(--muted); text-align: right; }
.count:not(:empty) { margin-top: 9px; }

.msg { display: block; margin-top: 14px; }
.msg > span { display: block; font: 500 10.5px/1 var(--mono); letter-spacing: .22em; text-transform: uppercase; color: var(--muted); margin: 0 0 9px 6px; }
.msg small { font-size: inherit; letter-spacing: .04em; text-transform: none; opacity: .8; }
textarea { width: 100%; resize: none; border-radius: 20px; border: 0; background: #fff; box-shadow: inset 0 0 0 1px var(--line); padding: 14px 16px; font-size: 16px; line-height: 1.45; outline: none; transition: box-shadow .25s; }
textarea:focus { box-shadow: inset 0 0 0 1.5px #c4b5fd, 0 0 0 5px rgba(196,181,253,.22); }
textarea::placeholder { color: #a6a6b0; }
.err { color: #c2415d; font-size: 13.5px; text-align: center; }
.err:not(:empty) { margin-top: 10px; }

.send { position: relative; overflow: hidden; margin-top: 14px; width: 100%; height: 58px; border: 0; border-radius: 999px; background: var(--ink); color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 10px; font-weight: 500; font-size: 16px; text-decoration: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 18px 36px -16px rgba(17,17,22,.6); transition: transform .3s var(--spring), opacity .3s; }
.send::before { opacity: .75; }
.send::after { content: ''; position: absolute; inset: 0; background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.3) 48%, rgba(249,168,212,.28) 52%, transparent 70%); transform: translate3d(-100%, 0, 0); animation: sheen 3.4s var(--ease) infinite; will-change: transform; }
@keyframes sheen { 55%, 100% { transform: translate3d(100%, 0, 0); } }
.send:active { transform: scale(.97); }
.send:disabled { opacity: .22; cursor: default; box-shadow: none; }
.send:disabled::after, .send:disabled::before { display: none; }

.st-sending, .st-done, .st-full { text-align: center; padding: 16px 8px 8px; }
.prog-ring { position: relative; width: 140px; height: 140px; margin: 4px auto 18px; }
.prog-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.prog-ring circle { fill: none; stroke-width: 5; }
.trk { stroke: rgba(17,17,22,.06); }
.bar { stroke: url(#pg); stroke-linecap: round; stroke-dasharray: 326.7; stroke-dashoffset: 326.7; transition: stroke-dashoffset .3s; }
.prog-ring b { position: absolute; inset: 0; display: grid; place-items: center; font: 200 34px/1 var(--sans); font-variant-numeric: tabular-nums; }
.big { font: 400 32px/1.15 var(--serif); }
.small { margin-top: 8px; font-size: 14.5px; line-height: 1.55; color: var(--muted); }
.small a { color: var(--ink); font-weight: 600; }
.check { width: 80px; height: 80px; margin: 6px auto 16px; }
.check svg { width: 100%; height: 100%; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.check circle { stroke: url(#pg); stroke-dasharray: 151; stroke-dashoffset: 151; animation: draw .8s var(--ease) forwards; }
.check path { stroke: var(--ink); stroke-dasharray: 40; stroke-dashoffset: 40; animation: draw .5s .55s var(--ease) forwards; }
.ghost { margin-top: 20px; border: 0; background: #fff; box-shadow: inset 0 0 0 1px var(--line); border-radius: 999px; padding: 13px 22px; font-size: 14.5px; cursor: pointer; }
.wa { margin-top: 20px; }
.mine { text-align: center; margin-top: 14px; font: 500 11px/1.5 var(--mono); letter-spacing: .03em; color: var(--muted); min-height: 1em; }

/* ---------- footer ---------- */
.end { text-align: center; padding: 12svh 16px max(130px, calc(env(safe-area-inset-bottom) + 120px)); }
.end-rings { width: 116px; overflow: visible; }
.end-rings circle { fill: none; stroke-width: 3.5; stroke-dasharray: 164; stroke-dashoffset: 164; transition: stroke-dashoffset 1.8s var(--ease); }
.end.on .end-rings circle { stroke-dashoffset: 0; }
.end.on .end-rings circle + circle { transition-delay: .3s; }
.end-names { margin-top: 18px; font: 400 clamp(50px, 14vw, 92px)/1 var(--serif); }
.end-date { margin-top: 14px; font: 500 12px/1 var(--mono); letter-spacing: .3em; color: var(--muted); }
.end-love { margin-top: 10px; font: 400 italic 21px/1 var(--serif); color: var(--ink-2); }

/* ---------- floating button ---------- */
.fab { position: fixed; z-index: 55; left: 50%; bottom: max(18px, calc(env(safe-area-inset-bottom) + 6px)); display: flex; align-items: center; gap: 10px; padding: 15px 22px 15px 19px; border-radius: 999px;
  background: #1a1a20; color: #fff; text-decoration: none; font-weight: 500; font-size: 15px; white-space: nowrap;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 20px 40px -14px rgba(17,17,22,.55);
  transform: translate3d(-50%, 0, 0); opacity: 0; transition: transform .6s var(--spring); animation: fabIn .8s 2.2s var(--spring) forwards; will-change: transform; }
.fab::before { opacity: .85; }
.fab::after { content: ''; position: absolute; inset: -3px; border-radius: inherit; border: 1.5px solid rgba(232,121,184,.75); opacity: 0; pointer-events: none;
  animation: fabPing 2.6s 3.2s ease-out infinite; will-change: transform, opacity; }
@keyframes fabPing { from { opacity: .9; transform: scale(1); } 70%, to { opacity: 0; transform: scale(1.12, 1.45); } }
.fab:active { scale: .96; }
@keyframes fabIn { from { opacity: 0; translate: 0 30px; } to { opacity: 1; translate: 0 0; } }
.fab.hide { transform: translate3d(-50%, 160%, 0); }

@media (min-width: 760px) {
  .names .n1 { margin-left: 4vw; } .names .n2 { margin-right: 4vw; }
  .topbar { left: 24px; right: 24px; top: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  .intro, .dust { display: none; }
  .in, .ch, .fab { animation: none; opacity: 1; }
  .ch { transform: none; }
  .spin, .mq, .aura i { animation: none; }
}
