:root{
  --pink:#FFD6E8;
  --pink-deep:#F7A8C9;
  --lilac:#E3D4FF;
  --lilac-deep:#B79CE4;
  --peach:#FFE3D0;
  --peach-deep:#F5B78F;
  --mint:#BDEFE4;
  --teal:#4EC9B0;
  --teal-deep:#2FA893;
  --ink:#4A3B5C;
  --ink-soft:#8A7A9B;
  --card:rgba(255,255,255,0.55);
  --radius:14px;
}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}
::selection{background:transparent}
::-moz-selection{background:transparent}
button,.photo-slot,#typeTarget{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
button:focus,.photo-slot:focus{outline:none}
button:focus-visible,.photo-slot:focus-visible{outline:3px solid rgba(255,158,196,.55);outline-offset:3px}
#eggClose:active,#uploadChip:active,.photo-slot:active{transform:scale(.95)}
#eggClose,#uploadChip,.photo-slot{transition:transform .15s ease}
html{scroll-behavior:smooth}
body{
  font-family:'Quicksand','Trebuchet MS',sans-serif;
  color:var(--ink);
  font-size:16px;
  line-height:1.6;
  background:
    radial-gradient(circle at 14px 18px,rgba(255,143,188,.4) 2px,transparent 2.6px),
    radial-gradient(circle at 58px 74px,rgba(169,139,214,.34) 2px,transparent 2.6px),
    radial-gradient(circle at 90px 30px,rgba(122,220,198,.3) 1.6px,transparent 2.2px),
    linear-gradient(rgba(227,212,255,0.35) 1px,transparent 1px),
    linear-gradient(90deg,rgba(227,212,255,0.35) 1px,transparent 1px),
    linear-gradient(160deg,#FFF2F8 0%,#F3ECFD 45%,#FFF0E6 80%,#EDFAF6 100%);
  background-size:112px 128px,132px 148px,156px 120px,28px 28px,28px 28px,cover;
  background-attachment:fixed;
  min-height:100vh;
}
.pixel{font-family:'Press Start 2P','Courier New',monospace;line-height:1.6}
svg.pi{display:inline-block;width:1.1em;height:1.1em;vertical-align:-0.15em;shape-rendering:crispEdges}
.pi-pink{color:#FF8FBC}.pi-lilac{color:#A98BD6}.pi-mint{color:#2FA893}.pi-yellow{color:#F0C64F}

/* ---------- twinkling stars ---------- */
.stars{position:fixed;inset:0;pointer-events:none;z-index:0}
.star{
  position:absolute;width:8px;height:8px;
  background:
    conic-gradient(from 0deg, currentColor 0 100%);
  clip-path:polygon(50% 0,62% 38%,100% 50%,62% 62%,50% 100%,38% 62%,0 50%,38% 38%);
  animation:twinkle 3.4s ease-in-out infinite;
  opacity:.5;
}
@keyframes twinkle{0%,100%{opacity:.15;transform:scale(.7)}50%{opacity:.7;transform:scale(1)}}

/* ---------- start overlay ---------- */
#startOverlay{
  position:fixed;top:0;right:0;bottom:0;left:0;inset:0;z-index:50;
  /* Bottom of slide 1's sky lands on the same pink as the cloud image's
     own sky (#FCB7C7-ish), so the hem's faded top edge melts into it with
     no hue band. */
  background:linear-gradient(160deg,#FFE4F1 0%,#EBDFFF 46%,#F8C5D3 76%,#FBBCCB 100%);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:28px;text-align:center;padding:24px;
  transition:opacity .3s ease,transform 1600ms cubic-bezier(.45,0,.12,1);
  will-change:transform;
}
/* Only fires once the overlay has already slid fully off the top of the
   screen (see SLIDE_MS in script.js), so this swap is invisible. */
#startOverlay.hidden{opacity:0;visibility:hidden;pointer-events:none;transition:opacity .3s ease,visibility 0s linear .3s}
#startOverlay .env{width:96px;animation:float 3.4s ease-in-out infinite;filter:drop-shadow(0 8px 18px rgba(247,168,201,.45))}
#startOverlay .env svg{display:block;width:100%;height:auto}
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
/* The whole of slide 1 -- background AND the grass glued to its bottom
   edge -- slides up and off the screen like a curtain being lifted. The
   grass is the curtain's hem. Self-relative -101% (the overlay is inset:0,
   so 100% of itself == the viewport) guarantees it fully clears any screen
   height, while staying in near-perfect lockstep with slide 2's own 100vh
   rise below it (see the pre-start rules), so the two read as one strip. */
#startOverlay.cloud-incoming{transform:translateY(-101%)}

/* ---------- start overlay ground (pixel pink clouds, slide 1 only) ----------
   The curtain hem is now the pixel-cloud artwork (clouds.jpg), softened:
   slightly translucent + desaturated ("agak samar") and mask-faded on its
   top AND bottom edges, so it melts into slide 1's pastel background above
   and hands off cleanly to slide 2 below during the tow. */
#startOverlay .ground{
  position:absolute;left:0;right:0;bottom:0;z-index:-1;
  height:min(26vh,200px);min-height:120px;
  pointer-events:none;
  background:url("clouds.jpg") bottom center / cover no-repeat;
  image-rendering:pixelated;
  opacity:.85;
  filter:saturate(.85);
  -webkit-mask-image:linear-gradient(180deg,transparent 0%,#000 48%,#000 100%);
  mask-image:linear-gradient(180deg,transparent 0%,#000 48%,#000 100%);
}
/* Bottom bridge: the hem's lowest rows (#FEB1B7-ish pink) would otherwise
   meet slide 2's near-white top (#FFF2F8) as a hard color line during the
   tow. This gradient, glued to the overlay's bottom edge above the hem,
   fades the hem into slide 2's own base color so the handoff is seamless. */
#startOverlay::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:96px;
  pointer-events:none;
  background:linear-gradient(180deg,rgba(255,242,248,0) 0%,rgba(255,242,248,.5) 50%,#FFF2F8 100%);
}

/* Slide 1's own text/button fade out fast as the curtain starts lifting,
   so the focus goes to the grass hem and the content it reveals. */
#startOverlay .env,#startOverlay p,#startOverlay .pixel,#startOverlay #startBtn{
  transition:opacity .28s ease,transform .28s ease;
}
#startOverlay.cloud-incoming .env,#startOverlay.cloud-incoming p,#startOverlay.cloud-incoming .pixel,#startOverlay.cloud-incoming #startBtn{
  opacity:0;transform:translateY(-10px);
}

/* ---------- start transition ----------
   Slide 2 starts a FULL viewport (100vh) below its resting place -- i.e.
   parked directly underneath slide 1's grass hem -- and rises to 0 with
   EXACTLY the same duration + easing as the overlay's -101% lift. Because
   both travel ~one viewport in lockstep, slide 2 stays glued just below
   the grass the whole way up: it is literally towed into place by the
   curtain, not revealed behind it. No opacity change -- purely physical. */
body.pre-start .window{transform:translateY(100vh)}
/* .player is a fixed, horizontally-centered bar (translateX(-50%)), so its
   pre-start offset must keep that X centering composed in -- a bare
   translateY here would fling it sideways during the lift. */
body.pre-start .player{transform:translateX(-50%) translateY(100vh)}
.window,.player{
  transition:transform 1600ms cubic-bezier(.45,0,.12,1);
  will-change:transform;
}
/* No scrolling while slide 1's curtain is still down, so slide 2 is always
   revealed from its intended top position. */
body.pre-start{overflow:hidden}
#startOverlay p{color:var(--ink-soft);max-width:420px;font-size:15px}
/* Slide 1's message lines drift gently too (the envelope already floats).
   During the curtain lift the animation keeps running -- the fade-out is
   opacity-only there, so no snap. */
#startOverlay p{animation:floatSoft 5s ease-in-out -1.2s infinite}
#startOverlay .pixel{animation:floatSoft 4.2s ease-in-out -2.6s infinite}
#startBtn{
  font-family:'Press Start 2P','Courier New',monospace;
  font-size:13px;color:#fff;
  background:linear-gradient(180deg,var(--teal) 0%,var(--teal-deep) 100%);
  border:2px solid rgba(255,255,255,.7);
  border-radius:999px;padding:18px 30px;cursor:pointer;
  box-shadow:0 4px 0 rgba(47,168,147,.45),0 8px 24px rgba(78,201,176,.35);
  transition:transform .2s ease,box-shadow .2s ease;
  min-height:44px;
}
#startBtn:hover{transform:translateY(-2px);box-shadow:0 6px 0 rgba(47,168,147,.45),0 12px 28px rgba(78,201,176,.4)}
#startBtn:active{transform:translateY(2px);box-shadow:0 2px 0 rgba(47,168,147,.45)}
#startBtn:disabled{cursor:default;opacity:.85;transform:none;box-shadow:0 4px 0 rgba(47,168,147,.45),0 8px 24px rgba(78,201,176,.35)}

/* ---------- browser window ---------- */
.window{
  position:relative;z-index:1;
  max-width:780px;margin:48px auto 130px;
  border:2px solid rgba(183,156,228,.5);
  border-radius:16px;overflow:hidden;
  background:
    linear-gradient(rgba(227,212,255,.14) 1px,transparent 1px),
    linear-gradient(90deg,rgba(227,212,255,.14) 1px,transparent 1px),
    radial-gradient(120% 55% at 50% 0%,rgba(255,214,232,.4) 0%,rgba(255,214,232,0) 60%),
    radial-gradient(120% 55% at 50% 100%,rgba(189,239,228,.3) 0%,rgba(189,239,228,0) 60%),
    linear-gradient(rgba(255,255,255,.62),rgba(255,255,255,.62));
  background-size:26px 26px,26px 26px,cover,cover,cover;
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  box-shadow:0 1px 2px rgba(74,59,92,.06),0 18px 48px rgba(183,156,228,.25);
}
.titlebar{
  display:flex;align-items:center;gap:12px;
  padding:12px 16px;
  background:linear-gradient(90deg,var(--pink) 0%,var(--lilac) 50%,var(--peach) 100%);
  border-bottom:2px solid rgba(183,156,228,.35);
}
.dots{display:flex;gap:8px}
.dot{width:14px;height:14px;border-radius:50%;border:1.5px solid rgba(74,59,92,.25)}
.dot.p{background:#FF9EC4}.dot.o{background:#FFC79E}.dot.t{background:#7ADCC6}
.titlebar .title{
  flex:1;text-align:center;font-size:10px;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.titlebar .spacer{width:58px}
.progress-track{height:6px;background:rgba(227,212,255,.5)}
.progress-fill{height:100%;width:0%;background:linear-gradient(90deg,var(--teal),#7ADCC6);transition:width .15s linear}

/* ---------- content ---------- */
.inner{padding:64px 52px 76px}
section{margin-bottom:88px}
section:last-of-type{margin-bottom:0}
.reveal{opacity:0;transform:translateY(22px) scale(.92);transition:opacity .75s ease,transform .75s cubic-bezier(.34,1.56,.64,1)}
.reveal.from-top{transform:translateY(-22px) scale(.96)}

/* word-by-word text reveal (spans injected by script.js) */
.w{
  display:inline-block;opacity:0;
  transform:translateY(9px) scale(.9);
  transition:opacity .5s ease,transform .5s cubic-bezier(.34,1.56,.5,1);
  transition-delay:var(--d,0ms);
}
.reveal.visible .w{opacity:1;transform:none}
.reveal:not(.visible) .w{transition-delay:0ms;transition-duration:.22s}
/* inline pixel icons keep bobbing after they pop in */
.reveal.visible .w > .pi{animation:pxbob 2.8s ease-in-out infinite;animation-delay:calc(var(--d,0ms) + .6s)}
@keyframes pxbob{0%,100%{transform:none}50%{transform:translateY(-2px)}}
@media (prefers-reduced-motion: reduce){
  .w{opacity:1;transform:none;transition:none}
  .reveal.visible .w > .pi{animation:none}
}
.reveal.visible{opacity:1;transform:none}

/* hero */
.hero{text-align:center;padding-top:16px}
.hero .badge{
  display:inline-block;font-size:9px;color:var(--teal-deep);
  background:rgba(189,239,228,.6);border:1px solid rgba(78,201,176,.4);
  border-radius:999px;padding:8px 14px;margin-bottom:28px;
}
.hero h1{
  font-family:'Press Start 2P','Courier New',monospace;
  font-size:clamp(20px,4.6vw,34px);
  line-height:1.7;
  background:linear-gradient(90deg,#E86FA7 10%,var(--lilac-deep) 55%,var(--teal-deep) 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  min-height:2.2em;
}
.hero h1 .caret{color:var(--lilac-deep);animation:blink 1s steps(1) infinite}
.hero-heart{width:.85em !important;height:.85em !important;margin-left:6px;opacity:0;transition:opacity .6s ease}
.hero-heart.show{opacity:1}
@keyframes blink{50%{opacity:0}}
.hero .subtitle{
  margin-top:22px;color:var(--ink-soft);font-size:16px;font-weight:600;
  opacity:0;animation:fadeUp 1.2s ease 2.8s forwards;
}
@keyframes fadeUp{to{opacity:1}}
.hero .deco{margin-top:26px;font-size:18px;letter-spacing:14px;color:var(--pink-deep)}

/* section headings */
h2{
  font-family:'Press Start 2P','Courier New',monospace;
  font-size:clamp(13px,2.4vw,17px);line-height:1.8;
  color:var(--ink);margin-bottom:20px;
}
h2 .tag{color:var(--teal-deep)}
h2::after{content:"\2726";color:var(--pink-deep);opacity:.4;margin-left:10px;font-size:.7em}

/* glass cards */
.glass{
  background:var(--card);
  border:1px solid rgba(255,255,255,.8);
  border-radius:var(--radius);
  padding:28px 30px;
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  box-shadow:0 1px 2px rgba(74,59,92,.05),0 8px 24px rgba(183,156,228,.18),inset 0 1px 0 rgba(255,255,255,.9);
  position:relative;
}
.glass::before{
  content:"";position:absolute;top:0;left:8%;right:55%;height:1px;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.95),transparent);
}
.glass p{font-size:16.5px;font-weight:500}
.glass p + p{margin-top:14px}
.thanks .glass{background:linear-gradient(160deg,rgba(255,214,232,.5),rgba(255,255,255,.55))}
.sorry .glass{background:linear-gradient(160deg,rgba(227,212,255,.5),rgba(255,255,255,.5))}
.sorry .glass{border:1px solid rgba(227,212,255,.9)}
.section-deco{font-size:13px;color:var(--lilac-deep);letter-spacing:10px;margin-top:16px;text-align:right;animation:decoPulse 3.2s ease-in-out infinite}
@keyframes decoPulse{0%,100%{opacity:.5}50%{opacity:1}}

/* polaroid */
/* The float lives on the wrapper so the polaroid keeps its own tilt +
   hover-straighten transform untouched. */
.photo-wrap{display:flex;justify-content:center;animation:floatSoft 6.4s ease-in-out infinite}
@keyframes floatSoft{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
.polaroid{
  position:relative;
  background:#fff;
  border:2px solid rgba(183,156,228,.45);
  border-radius:10px;
  padding:12px 12px 0;
  width:min(340px,100%);
  box-shadow:0 1px 2px rgba(74,59,92,.06),0 14px 34px rgba(247,168,201,.28);
  transform:rotate(-1.5deg);
  transition:transform .35s ease;
}
.polaroid:hover{transform:rotate(0deg) translateY(-4px)}
.polaroid::before,.polaroid::after{content:"";position:absolute;width:14px;height:14px;pointer-events:none}
.polaroid::before{top:-7px;left:-7px;border-top:4px solid var(--lilac-deep);border-left:4px solid var(--lilac-deep)}
.polaroid::after{bottom:-7px;right:-7px;border-bottom:4px solid var(--pink-deep);border-right:4px solid var(--pink-deep)}
.polaroid .mini-titlebar{
  display:flex;align-items:center;gap:6px;
  background:linear-gradient(90deg,var(--peach),var(--pink));
  border-radius:6px 6px 0 0;padding:6px 10px;
  border:1px solid rgba(183,156,228,.3);border-bottom:none;
}
.polaroid .mini-titlebar i{width:8px;height:8px;border-radius:50%;display:block}
.polaroid .mini-titlebar i:nth-child(1){background:#FF9EC4}
.polaroid .mini-titlebar i:nth-child(2){background:#FFC79E}
.polaroid .mini-titlebar i:nth-child(3){background:#7ADCC6}
.polaroid .mini-titlebar span{font-size:7px;margin-left:auto;color:var(--ink-soft)}
.photo-slot{
  aspect-ratio:1/1;
  border:1px solid rgba(183,156,228,.3);border-top:none;
  background:
    linear-gradient(rgba(227,212,255,.4) 1px,transparent 1px),
    linear-gradient(90deg,rgba(227,212,255,.4) 1px,transparent 1px),
    linear-gradient(160deg,#FDF3F9,#F2EDFC);
  background-size:16px 16px,16px 16px,cover;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:12px;cursor:pointer;overflow:hidden;
}
.photo-slot img{width:100%;height:100%;object-fit:cover}
.photo-slot .ph-icon{font-size:34px}
.photo-slot .ph-text{font-size:8px;color:var(--ink-soft);text-align:center;line-height:1.9;padding:0 18px}
.polaroid .caption{
  text-align:center;font-size:9px;color:var(--ink-soft);padding:14px 4px 16px;
}

/* signature */
.signature{text-align:center}
.signature .line{width:64px;height:2px;background:linear-gradient(90deg,var(--pink-deep),var(--lilac-deep));margin:0 auto 24px;border-radius:2px}
.signature .sincerely{font-size:11px;color:var(--teal-deep);margin-bottom:16px}
.signature .name{font-size:20px;font-weight:700;color:var(--ink)}
.signature .role{color:var(--ink-soft);font-size:15px;margin-top:6px}

/* footer */
.footer{
  text-align:center;font-size:8px;color:var(--ink-soft);
  padding:20px 16px 26px;border-top:1px dashed rgba(183,156,228,.4);
}

/* ---------- music player ---------- */
.player{
  position:fixed;left:50%;bottom:18px;transform:translateX(-50%);
  z-index:40;width:min(400px,calc(100% - 32px));
  display:flex;align-items:center;gap:12px;
  background:rgba(255,255,255,.72);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border:2px solid rgba(183,156,228,.45);
  border-radius:999px;padding:8px 18px 8px 8px;
  box-shadow:0 6px 24px rgba(183,156,228,.3),inset 0 1px 0 rgba(255,255,255,.9);
}
#playBtn{
  width:44px;height:44px;border-radius:50%;flex:none;
  border:2px solid rgba(255,255,255,.8);cursor:pointer;
  background:linear-gradient(180deg,var(--teal),var(--teal-deep));
  color:#fff;font-size:15px;display:flex;align-items:center;justify-content:center;
  box-shadow:0 3px 0 rgba(47,168,147,.4);
  transition:transform .2s ease;
}
#playBtn:hover{transform:scale(1.06)}
#playBtn:active{transform:scale(.96)}
#playBtn svg{display:block;width:18px;height:18px;image-rendering:pixelated}
#playBtn svg.pix-play{margin-left:2px}
.player .meta{flex:1;min-width:0}
.player .song{font-size:7px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:7px}
.player .track{height:8px;border-radius:999px;background:rgba(227,212,255,.6);overflow:hidden;cursor:pointer;border:1px solid rgba(183,156,228,.35)}
.player .fill{height:100%;width:0%;border-radius:999px;background:linear-gradient(90deg,var(--teal),#7ADCC6)}
.player .time{font-size:7px;color:var(--ink-soft);flex:none}
#uploadChip{
  display:none;font-family:'Quicksand',sans-serif;font-size:12px;font-weight:700;
  color:var(--teal-deep);background:rgba(189,239,228,.7);
  border:1px solid rgba(78,201,176,.5);border-radius:999px;
  padding:6px 12px;cursor:pointer;flex:none;
}
#uploadChip.show{display:block}

/* ---------- sticky notes ---------- */
.notes-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:20px;margin-top:8px}
.note-wrap{opacity:0;transform:translateY(16px);transition:opacity .6s ease,transform .6s ease}
.notes.visible .note-wrap{opacity:1;transform:none}
.notes.visible .note-wrap:nth-child(2){transition-delay:.12s}
.notes.visible .note-wrap:nth-child(3){transition-delay:.24s}
.notes.visible .note-wrap:nth-child(4){transition-delay:.36s}
.note{
  border-radius:4px;padding:22px 16px 18px;position:relative;
  font-size:14.5px;font-weight:600;line-height:1.55;color:var(--ink);
  border:1px solid rgba(255,255,255,.75);
  box-shadow:3px 3px 0 rgba(74,59,92,.07),0 8px 18px rgba(183,156,228,.14);
}
.note .tape{position:absolute;top:-8px;left:50%;transform:translateX(-50%);width:52px;height:15px;background:rgba(255,255,255,.6);border:1px solid rgba(183,156,228,.3);border-radius:2px}
.note .from{display:block;margin-top:12px;font-size:7px;color:var(--ink-soft)}
.note.n1{background:#FFE4F0;transform:rotate(-1.4deg)}
.note.n2{background:#EDE3FF;transform:rotate(1.2deg)}
.note.n3{background:#FFEDD9;transform:rotate(-.8deg)}
.note.n4{background:#DFF6EF;transform:rotate(1.5deg)}
/* idle sway: each note swings gently around its washi tape (pivot above the
   top edge), keeping its own base tilt (--rot) as the center of the swing.
   Staggered durations/offsets so they never move in unison. */
.note{transform-origin:50% -8px;animation:noteSway var(--swayd,5.6s) ease-in-out var(--swayo,0s) infinite}
@keyframes noteSway{
  0%,100%{transform:rotate(calc(var(--rot,0deg) - .9deg))}
  50%{transform:rotate(calc(var(--rot,0deg) + .9deg))}
}
.note.n1{--rot:-1.4deg;--swayd:5.2s}
.note.n2{--rot:1.2deg;--swayd:6.3s;--swayo:-2.1s}
.note.n3{--rot:-.8deg;--swayd:5.7s;--swayo:-3.4s}
.note.n4{--rot:1.5deg;--swayd:6.8s;--swayo:-1.2s}

/* ---------- tap for love ---------- */
.love{text-align:center}
#loveBtn{
  font-family:'Press Start 2P','Courier New',monospace;font-size:11px;color:#fff;
  background:linear-gradient(180deg,#FF9EC4 0%,#E86FA7 100%);
  border:2px solid rgba(255,255,255,.75);border-radius:999px;
  padding:17px 28px;cursor:pointer;min-height:44px;
  box-shadow:0 4px 0 rgba(232,111,167,.4),0 8px 22px rgba(247,168,201,.35);
  transition:transform .15s ease,box-shadow .15s ease;
}
#loveBtn:hover{transform:translateY(-2px)}
#loveBtn:active{transform:scale(.94);box-shadow:0 2px 0 rgba(232,111,167,.4)}
#loveCount{margin-top:16px;font-size:14.5px;font-weight:600;color:var(--ink-soft)}
.love-heart{position:fixed;z-index:45;pointer-events:none;opacity:0;animation:loveUp 1.1s ease-out forwards;will-change:transform,opacity}
.love-heart svg{display:block;width:100%;height:auto}
@keyframes loveUp{0%{opacity:0;transform:translate(0,0) scale(.6)}15%{opacity:1}100%{opacity:0;transform:translate(var(--dx,0px),-110px) scale(1.05)}}

/* ---------- signature heart burst (one-time closing moment) ----------
   Fixed-position, pointer-transparent pixels appended to <body> by
   script.js when the signature first scrolls into view: zero layout shift,
   they drift up softly (--dx/--dy set per-pixel) and fade out in ~1.5s,
   then script.js removes the nodes. Hidden for prefers-reduced-motion
   (script.js also never spawns them there -- belt and suspenders). */
.sig-burst{position:fixed;z-index:45;pointer-events:none;opacity:0;animation:sigBurst 1.5s ease-out forwards;will-change:transform,opacity}
.sig-burst svg{display:block;width:100%;height:auto}
@keyframes sigBurst{
  0%{opacity:0;transform:translate(0,0) scale(.4)}
  18%{opacity:1;transform:translate(calc(var(--dx,0px)*.3),calc(var(--dy,-60px)*.3)) scale(1)}
  100%{opacity:0;transform:translate(var(--dx,0px),var(--dy,-60px)) scale(.9)}
}
@media (prefers-reduced-motion: reduce){.sig-burst{display:none}}

/* ---------- coupons ---------- */
.coupon-list{display:flex;flex-direction:column;gap:18px}
.coupon{
  display:flex;align-items:stretch;overflow:hidden;
  background:rgba(255,255,255,.55);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  border:2px dashed rgba(183,156,228,.65);border-radius:10px;
  box-shadow:0 1px 2px rgba(74,59,92,.05),0 8px 20px rgba(183,156,228,.15);
  animation:couponFloat 5.8s ease-in-out infinite;
}
.coupon:nth-child(2){animation-duration:6.6s;animation-delay:-1.9s}
.coupon:nth-child(3){animation-duration:7.2s;animation-delay:-3.8s}
@keyframes couponFloat{
  0%,100%{transform:translateY(0) rotate(0deg)}
  50%{transform:translateY(-5px) rotate(.35deg)}
}
.coupon .stub{
  flex:none;width:84px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  padding:16px 8px;border-right:2px dashed rgba(183,156,228,.6);
}
.coupon:nth-child(1) .stub{background:linear-gradient(160deg,var(--pink),rgba(255,255,255,.4))}
.coupon:nth-child(2) .stub{background:linear-gradient(160deg,var(--lilac),rgba(255,255,255,.4))}
.coupon:nth-child(3) .stub{background:linear-gradient(160deg,var(--mint),rgba(255,255,255,.4))}
.coupon .stub svg{display:block}
.coupon .stub .no{font-size:7px;color:var(--ink)}
.coupon .body{flex:1;padding:18px 20px;display:flex;flex-direction:column;justify-content:center}
.coupon .body .t{font-weight:700;font-size:15.5px;color:var(--ink)}
.coupon .body .v{font-size:7px;color:var(--ink-soft);margin-top:10px}

/* ---------- memories timeline ---------- */
.timeline{list-style:none;position:relative;padding-left:30px;margin-top:8px}
.timeline::before{content:"";position:absolute;left:7px;top:6px;bottom:6px;width:2px;background:linear-gradient(180deg,var(--pink-deep),var(--lilac-deep),var(--teal))}
.timeline li{position:relative;padding-bottom:24px}
.timeline li:last-child{padding-bottom:0}
.timeline li::before{content:"";position:absolute;left:-27px;top:5px;width:8px;height:8px;background:var(--pink-deep);border:2px solid #fff;box-shadow:0 0 0 1px rgba(183,156,228,.55)}
.timeline li:nth-child(2)::before{background:var(--peach-deep)}
.timeline li:nth-child(3)::before{background:var(--lilac-deep)}
.timeline li:nth-child(4)::before{background:var(--teal)}
.timeline li:nth-child(5)::before{background:var(--pink-deep)}
.timeline .when{display:block;font-size:8px;color:var(--teal-deep);margin-bottom:5px}
.timeline .what{font-size:15.5px;font-weight:600}

/* ---------- easter egg popup ---------- */
.egg{
  position:fixed;inset:0;z-index:70;padding:20px;
  display:flex;align-items:center;justify-content:center;
  background:rgba(74,59,92,.22);
  opacity:0;visibility:hidden;transition:opacity .3s ease,visibility .3s ease;
}
.egg.open{opacity:1;visibility:visible}
.egg-win{
  width:min(340px,100%);overflow:hidden;
  background:rgba(255,255,255,.94);
  border:2px solid rgba(183,156,228,.55);border-radius:12px;
  box-shadow:0 18px 48px rgba(74,59,92,.25);
  transform:scale(.9) translateY(10px);transition:transform .3s ease;
}
.egg.open .egg-win{transform:none}
.egg-bar{display:flex;align-items:center;gap:6px;padding:9px 12px;background:linear-gradient(90deg,var(--pink),var(--lilac));border-bottom:2px solid rgba(183,156,228,.35)}
.egg-bar i{width:9px;height:9px;border-radius:50%;display:block;border:1px solid rgba(74,59,92,.2)}
.egg-bar i:nth-child(1){background:#FF9EC4}
.egg-bar i:nth-child(2){background:#FFC79E}
.egg-bar i:nth-child(3){background:#7ADCC6}
.egg-bar span{margin-left:auto;font-size:7px;color:var(--ink-soft)}
.egg-body{padding:28px 24px;text-align:center}
.egg-body .msg{font-size:10px;line-height:2.1;color:var(--ink)}
#eggClose{
  margin-top:22px;font-family:'Press Start 2P','Courier New',monospace;font-size:10px;color:#fff;
  background:linear-gradient(180deg,#FF9EC4,#E86FA7);
  border:2px solid rgba(255,255,255,.75);border-radius:999px;
  padding:13px 22px;cursor:pointer;min-height:44px;
  box-shadow:0 3px 0 rgba(232,111,167,.4);
  transition:transform .15s ease;
}
#eggClose:hover{transform:translateY(-1px)}

/* ---------- y2k lofi extras ---------- */
body::after{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;background:radial-gradient(130% 90% at 50% -10%,rgba(255,255,255,.55) 0%,rgba(255,255,255,0) 55%),radial-gradient(150% 100% at 50% 115%,rgba(247,168,201,.16) 0%,rgba(247,168,201,0) 55%)}
@keyframes wiggle{0%,100%{transform:rotate(-5deg)}50%{transform:rotate(5deg)}}
h2 .tag .pi{animation:wiggle 3.4s ease-in-out infinite;transform-origin:50% 60%}
.sakura{position:fixed;inset:0;z-index:55;pointer-events:none;overflow:hidden}
.sakura-fall{position:absolute;top:-40px;display:block;opacity:.5;animation:sakuraFallB linear infinite;will-change:transform;image-rendering:pixelated}
.sakura-fall svg{display:block;width:100%;height:auto}
.sakura-sway{display:block;animation:sakuraSway ease-in-out infinite}
@keyframes sakuraFallA{from{transform:translate(0,-4vh)}to{transform:translate(-7vw,108vh)}}
@keyframes sakuraFallB{from{transform:translate(0,-4vh)}to{transform:translate(5vw,108vh)}}
@keyframes sakuraFallC{from{transform:translate(0,-4vh)}to{transform:translate(11vw,108vh)}}
.sakura-fall.fa{animation-name:sakuraFallA}
.sakura-fall.fc{animation-name:sakuraFallC}
@keyframes sakuraSway{0%,100%{transform:translateX(-26px) rotate(-17deg)}25%{transform:translateX(12px) rotate(8deg)}50%{transform:translateX(26px) rotate(17deg)}75%{transform:translateX(-12px) rotate(-8deg)}}
.song-row{display:flex;align-items:center;gap:6px;min-width:0}
.eq{display:inline-flex;align-items:flex-end;gap:2px;height:10px;flex:none}
.eq i{width:3px;height:4px;background:var(--teal);border-radius:1px}
.player.playing .eq i{animation:eqBounce .9s ease-in-out infinite}
.player.playing .eq i:nth-child(2){animation-delay:.18s}
.player.playing .eq i:nth-child(3){animation-delay:.36s}
@keyframes eqBounce{0%,100%{height:4px}50%{height:10px}}
@media (min-width:641px) and (max-width:920px){.window{max-width:580px}.inner{padding:56px 38px 64px}}

/* ---------- responsive ---------- */
@media (max-width:640px){
  .window{margin:16px 14px 130px;border-radius:14px}
  .inner{padding:40px 22px 48px}
  section{margin-bottom:52px}
  .glass{padding:22px 20px}
  .glass p{font-size:15.5px}
  .titlebar .title{font-size:8px}
  .titlebar .spacer{display:none}
  .hero .deco{letter-spacing:10px}
  .notes-grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}
  .coupon .stub{width:64px}
  .coupon .body{padding:16px}
  #startOverlay .ground{height:min(16vh,110px);min-height:72px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
  html{scroll-behavior:auto}
  .reveal{opacity:1;transform:none}
  .hero .subtitle{opacity:1}
}
/* FIX: Mematikan interaksi foto agar tidak bisa di-download, disalin, atau ditekan */
.photo-slot,
.photo-slot img {
  pointer-events: none !important;
  -webkit-touch-callout: none !important;
  -webkit-user-select: none !important;
  user-select: none !important;
}
