<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>A Special Gift For You Darling β‘</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@600;700&family=Great+Vibes&family=Montserrat:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,700;1,400&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: radial-gradient(circle at center, #1a0b1a 0%, #0d050e 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: 'Montserrat', sans-serif;
overflow: hidden;
color: #333;
transition: background 1.5s ease-in-out;
position: relative;
}
body:has(.gift-area-decor:not(.hide-box)) { background: radial-gradient(circle at center, #1a0b1a 0%, #0d050e 100%); } body.rose-theme {
background: radial-gradient(circle at center, #fce4ec 0%, #f8bbd0 50%, #f48fb1 100%);
}
#confetti-canvas, #magical-canvas, #stars-canvas {
position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; pointer-events: none;
}
#confetti-canvas { z-index: 300; }
#stars-canvas { z-index: 2; opacity: 1; transition: opacity 1.5s ease; }
#magical-canvas { z-index: 1; opacity: 1; transition: opacity 1.5s ease; }
body.rose-theme #magical-canvas { opacity: 1; }
.top-bar {
position: fixed; top: 20px; right: 20px;
display: flex; align-items: center; gap: 10px; z-index: 400;
}
.top-btn {
background: #ffffff; border: 2px solid #d4af37; color: #701c2e;
padding: 8px 16px; border-radius: 25px; font-size: 0.85rem; font-weight: 600;
cursor: pointer; box-shadow: 0 4px 15px rgba(0,0,0,0.12);
transition: all 0.3s ease;
}
.top-btn:hover { transform: scale(1.05); }
.instruction-text {
position: absolute; top: 8%; font-size: 1.25rem; letter-spacing: 2px;
color: #ffe57f; text-transform: uppercase; font-weight: 700;
z-index: 20; text-align: center; padding: 0 20px; transition: opacity 0.4s ease, color 1s ease;
text-shadow: 0 0 12px rgba(255, 229, 127, 0.6);
}
body.rose-theme .instruction-text { color: #701c2e; text-shadow: none; }
.scene-container {
width: 100vw; height: 100vh; display: flex;
justify-content: center; align-items: center; position: relative;
z-index: 10;
}
/* ENHANCED DECORATED GIFT AREA & BOX */
.gift-area-decor {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 15;
}
.gift-aura-ring {
position: absolute;
width: 540px; height: 540px;
border-radius: 50%;
background: radial-gradient(circle, rgba(212,175,55,0.25) 0%, rgba(212,175,55,0.05) 50%, transparent 70%);
animation: pulseAura 3s ease-in-out infinite;
pointer-events: none;
}
@keyframes pulseAura {
0%, 100% { transform: scale(0.95); opacity: 0.6; }
50% { transform: scale(1.1); opacity: 1; }
}
.gift-sparkles-around {
position: absolute; width: 500px; height: 500px;
pointer-events: none;
animation: rotateDecor 20s linear infinite;
}
@keyframes rotateDecor {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.gift-sparkles-around::before, .gift-sparkles-around::after {
content: 'β¨ π β¨ π';
position: absolute; font-size: 1.5rem;
width: 100%; text-align: center; color: #ffe57f;
text-shadow: 0 0 10px #ffe57f;
}
.gift-sparkles-around::before { top: -20px; }
.gift-sparkles-around::after { bottom: -20px; transform: rotate(180deg); }
.gift-box {
width: 400px; height: 400px;
background: linear-gradient(135deg, #821b30, #4a0c18);
border: 4px solid #d4af37; border-radius: 20px;
box-shadow: 0 25px 60px rgba(0,0,0,0.6), inset 0 0 25px rgba(212,175,55,0.3);
position: relative; display: flex; justify-content: center; align-items: center;
cursor: pointer; transition: all 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
z-index: 20; transform-style: preserve-3d;
}
.gift-box:hover {
transform: scale(1.03);
box-shadow: 0 30px 70px rgba(212,175,55,0.4), inset 0 0 35px rgba(212,175,55,0.5);
}
.ribbon {
position: absolute; background: linear-gradient(135deg, #fff1b8, #d4af37, #aa7c11);
transition: all 0.8s ease; z-index: 5;
box-shadow: 0 0 10px rgba(0,0,0,0.3);
}
.ribbon-v { width: 56px; height: 100%; left: 172px; top: 0; }
.ribbon-h { width: 100%; height: 56px; top: 172px; left: 0; }
.unwrapped .ribbon-v, .unwrapped .ribbon-h { opacity: 0; transform: scale(0); }
.gold-bow {
position: absolute; top: 145px; left: 145px; width: 110px; height: 110px;
font-size: 5.5rem; z-index: 6; line-height: 100px; text-align: center;
filter: drop-shadow(0 6px 12px rgba(0,0,0,0.5));
transition: all 0.8s ease; pointer-events: none;
}
.unwrapped .gold-bow { transform: scale(0) rotate(180deg); opacity: 0; }
.sticky-note {
position: absolute; width: 290px; height: 205px; top: 98px; left: 55px; background: #fffdf5;
padding: 22px; transform: rotate(-4deg); box-shadow: 0 10px 25px rgba(0,0,0,0.3);
cursor: pointer; z-index: 30; transition: all 0.4s ease; display: flex;
justify-content: center; align-items: center; text-align: center;
border-radius: 4px; border: 1px solid #f0e6d2;
}
.sticky-note:hover { transform: rotate(0deg) scale(1.08); }
.sticky-note p { font-family: 'Caveat', cursive; font-size: 1.62rem; line-height: 1.18; color: #222; font-weight: 700; }
.sticky-note.fade-out { opacity: 0; pointer-events: none; transform: scale(0.5) rotate(45deg); }
.gift-area-decor.hide-box { opacity: 0; transform: scale(0.8); pointer-events: none; display: none !important; }
/* BOUQUET & SPECIAL NOTE CARD SCENE */
.bouquet-scene-wrapper {
position: absolute; left: 50%; top: 50%; width: 92vw; max-width: 1050px; height: 82vh; max-height: 660px;
background: rgba(255, 253, 250, 0.96); border: 4px solid #d4af37; border-radius: 20px;
box-shadow: 0 25px 60px rgba(0,0,0,0.25); display: flex; flex-direction: row;
overflow: hidden; opacity: 0; transform: translate(-50%, -50%) scale(0.9); pointer-events: none;
transition: all 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 40;
}
.bouquet-scene-wrapper.active { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; }
.shayari-card { width:100%; height:100%; padding:clamp(26px,5vw,64px); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:18px; position:relative; overflow:hidden; text-align:center; background:radial-gradient(circle at top,#fffdf9,#fff1f4 70%,#f6dce5); }
.shayari-card:before,.shayari-card:after { position:absolute; color:#b7831f; font-size:1.1rem; letter-spacing:12px; content:'β§ β‘ β§'; opacity:.8; }
.shayari-card:before { top:20px; left:24px } .shayari-card:after { bottom:20px; right:24px }
.shayari-kicker { font-size:.8rem; color:#a36a24; letter-spacing:4px; text-transform:uppercase; font-weight:700; }
.shayari-heading { color:#701c2e; font:clamp(2.1rem,5vw,3.3rem) 'Great Vibes',cursive; }
.shayari-lines { white-space:pre-line; color:#5c3540; font:clamp(1.25rem,3vw,1.8rem)/1.62 'Playfair Display',serif; }
.shayari-heart { color:#bb6d81; font-size:1.3rem; letter-spacing:10px; animation:giftPulse 2.5s ease-in-out infinite; }
.shayari-card .proceed-btn { position:relative; bottom:auto; margin-top:6px; }
.bouquet-left-col {
width: 45%; height: 100%; background: linear-gradient(135deg, #fff0f3 0%, #fbe4e8 100%);
border-right: 2px dashed #f48fb1; padding: 25px; display: flex; flex-direction: column;
align-items: center; justify-content: space-between; position: relative; overflow-y: auto;
}
.animated-bouquet-box {
width: 100%; display: flex; flex-direction: column; align-items: center; position: relative;
}
.flower-bouquet-img {
width: min(100%, 330px); height: 245px; display:flex; align-items:center; justify-content:center;
filter: drop-shadow(0 10px 14px rgba(112,28,46,0.18));
animation: floatBouquet 3s ease-in-out infinite;
}
.bouquet-art { width: 100%; height: 100%; overflow: visible; }
@keyframes floatBouquet {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-10px) rotate(3deg); }
}
.bouquet-right-col {
width: 55%; height: 100%; padding: 35px 30px 25px 30px; display: flex;
flex-direction: column; justify-content: space-between; align-items: center;
text-align: center; position: relative; background: #fffdfa; overflow-y: auto;
}
.bouquet-right-col h2 {
font-family: 'Great Vibes', cursive; font-size: 3.5rem; color: #701c2e; margin-bottom: 10px; font-weight: normal;
}
.card-space-text {
font-size: 1.1rem; line-height: 1.7; color: #444; width: 100%; min-height: 100px;
margin-bottom: 15px; word-wrap: break-word; text-align: center;
}
.proceed-btn {
background: linear-gradient(135deg, #701c2e, #821b30); color: #ffffff;
border: 2px solid #d4af37; padding: 12px 28px; border-radius: 30px;
font-size: 1rem; font-weight: 700; cursor: pointer;
box-shadow: 0 6px 20px rgba(112, 28, 46, 0.3); transition: all 0.3s ease;
display: flex; align-items: center; gap: 8px; margin-top: auto;
}
.proceed-btn:hover { transform: translateY(-3px) scale(1.03); box-shadow: 0 10px 25px rgba(112, 28, 46, 0.4); }
/* CHANGE 4 β proposal interlude */
.proposal-scene-wrapper {
position:absolute; left:50%; top:50%; transform:translate(-50%,-50%) scale(.94);
width:min(92vw,760px); min-height:min(78vh,650px); padding:28px 24px 30px;
display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px;
text-align:center; border:3px solid #d4af37; border-radius:28px;
background:radial-gradient(circle at 50% 18%,#fff7f3 0%,#fffaf7 45%,#f7e5e5 100%);
box-shadow:0 25px 70px rgba(39,5,18,.38),inset 0 0 0 7px rgba(112,28,46,.08);
opacity:0; pointer-events:none; z-index:65; transition:opacity .6s ease,transform .6s ease;
overflow:hidden;
}
.proposal-scene-wrapper.active { opacity:1; pointer-events:auto; transform:translate(-50%,-50%) scale(1); }
.page-corners { position:absolute; inset:14px; pointer-events:none; z-index:5; display:block; }
.page-corners span { position:absolute; color:#b7831f; font:700 1.15rem/1 'Playfair Display',serif; text-shadow:0 1px 0 rgba(255,255,255,.9); opacity:.88; }
.page-corners span:nth-child(1) { top:0; left:0; }
.page-corners span:nth-child(2) { top:0; right:0; }
.page-corners span:nth-child(3) { bottom:0; left:0; }
.page-corners span:nth-child(4) { bottom:0; right:0; }
.proposal-question::before { content:'β¦ β‘ β¦'; display:block; margin-bottom:18px; color:#b7831f; font:600 1.1rem/1 'Playfair Display',serif; letter-spacing:.28em; }
.proposal-question::after { content:'β¦'; display:block; margin-top:18px; color:#bb6d81; font:1.3rem/1 'Playfair Display',serif; }
.proposal-continue { display:none; margin-top:4px; }
.proposal-eyebrow { color:#a36a24; font-size:.85rem; letter-spacing:3px; text-transform:uppercase; font-weight:800; }
.proposal-title { font-family:'Playfair Display',serif; color:#701c2e; font-size:clamp(1.65rem,4vw,2.65rem); line-height:1.2; margin:0; }
.proposal-subtitle { color:#805461; font-size:1rem; margin:0; }
.ring-box-button { border:0; background:transparent; cursor:pointer; padding:0; position:relative; margin:4px 0; -webkit-tap-highlight-color:transparent; }
.ring-box { width:130px; height:100px; position:relative; filter:drop-shadow(0 12px 10px rgba(50,0,20,.2)); transition:transform .4s ease; }
.ring-box-button:hover .ring-box { transform:translateY(-5px) rotate(-2deg); }
.ring-box-base { position:absolute; left:9px; right:9px; bottom:0; height:55px; border:3px solid #d4af37; border-radius:9px 9px 18px 18px; background:linear-gradient(135deg,#8e2942,#5a1026 65%,#3e0918); }
.ring-box-lid { position:absolute; left:4px; right:4px; top:20px; height:29px; border:3px solid #e0bd61; border-radius:9px 9px 5px 5px; background:linear-gradient(135deg,#b84b66,#7a1832 70%,#4a0d20); transform-origin:bottom center; transition:transform .65s cubic-bezier(.2,.8,.2,1); z-index:2; }
.ring-box-lid::after { content:'β₯'; color:#f3d375; position:absolute; left:50%; top:2px; transform:translateX(-50%); font-size:17px; }
.ring-box.open .ring-box-lid { transform:rotateX(135deg) translateY(-8px); }
.ring-pop { position:absolute; z-index:3; left:50%; bottom:28px; transform:translate(-50%,15px) scale(.3); opacity:0; font-size:3.3rem; transition:all .65s cubic-bezier(.2,.8,.2,1); pointer-events:none; }
.ring-box.open .ring-pop { opacity:1; transform:translate(-50%,-35px) scale(1); }
.ring-hint { color:#9a6873; font-size:.88rem; }
.proposal-question { display:none; color:#701c2e; font-family:'Playfair Display',serif; font-size:clamp(1.45rem,3.5vw,2.2rem); font-weight:700; margin:4px 0; animation:fadeInContents .7s ease both; }
.proposal-question.visible { display:block; }
.proposal-buttons { display:none; align-items:center; justify-content:center; gap:22px; position:relative; width:min(100%,440px); min-height:100px; margin-top:2px; }
.proposal-buttons.visible { display:flex; }
.proposal-choice { border:2px solid #d4af37; border-radius:999px; padding:12px 30px; font-size:1.08rem; font-weight:800; cursor:pointer; box-shadow:0 6px 16px rgba(112,28,46,.16); transition:transform .2s ease,font-size .2s ease; touch-action:manipulation; }
#proposalYes { color:white; background:linear-gradient(135deg,#8b203c,#5c1026); position:relative; z-index:2; transform:scale(1); }
#proposalNo { color:#701c2e; background:#fff; position:relative; z-index:1; }
.proposal-after { display:none; font-family:'Playfair Display',serif; color:#701c2e; font-size:clamp(1.3rem,3.4vw,2rem); font-weight:700; animation:fadeInContents .8s ease both; } .proposal-after.visible { display:block; }
.yes-memory-scene { position:absolute; left:50%; top:50%; transform:translate(-50%,-50%) scale(.96); width:min(92vw,760px); min-height:360px; padding:70px 30px 34px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:20px; text-align:center; background:radial-gradient(circle at top,#fffdf8,#fff0f3 70%,#f8dfe6); border:4px solid #d4af37; border-radius:24px; box-shadow:0 24px 65px rgba(50,8,22,.32),inset 0 0 0 7px rgba(212,175,55,.12); opacity:0; pointer-events:none; z-index:68; transition:opacity .6s ease,transform .6s ease; }
.yes-memory-scene.active { opacity:1; pointer-events:auto; transform:translate(-50%,-50%) scale(1); }
.yes-memory-flourish { color:#a36a24; letter-spacing:8px; font-size:1.2rem; animation:storyFloat 3s ease-in-out infinite; }
.yes-memory-title { color:#701c2e; font:clamp(1.8rem,4vw,2.8rem) 'Great Vibes',cursive; margin:0; }
.yes-memory-message { width:min(100%,560px); padding:28px; border:2px solid #f0c7d1; border-radius:18px; background:rgba(255,255,255,.82); color:#5e3540; font:1.5rem/1.6 'Caveat',cursive; box-shadow:0 8px 24px rgba(112,28,46,.1); }
.yes-memory-next { margin-top:2px; }
@media(max-width:650px) { .yes-memory-scene { width:92vw; min-height:0; padding:55px 16px 24px; gap:14px; } .yes-memory-message { padding:20px; font-size:1.3rem; } }
.celebration-fall { position:fixed; top:-45px; z-index:350; pointer-events:none; animation:petalShower linear forwards; }
@keyframes petalShower { 0%{transform:translate3d(0,-30px,0) rotate(0deg);opacity:0} 10%{opacity:1} 100%{transform:translate3d(var(--drift),110vh,0) rotate(620deg);opacity:0} }
@media (max-width:600px) {
.proposal-scene-wrapper { width:92vw; min-height:76vh; padding:22px 15px; gap:12px; }
.ring-box { transform:scale(.9); }
.proposal-buttons { gap:12px; min-height:95px; }
.proposal-choice { padding:11px 23px; }
}
/* CERTIFICATE / REWARD CHEST SCENE */
.award-scene-wrapper {
position: absolute; left: 50%; top: 50%; width: 92vw; max-width: 1050px; height: 82vh; max-height: 660px;
background: #fffdf8; border: 4px solid #d4af37; border-radius: 20px;
box-shadow: 0 25px 60px rgba(0,0,0,0.3); display: flex; flex-direction: column;
align-items: center; justify-content: space-between; padding: 25px;
opacity: 0; transform: translate(-50%, -50%) scale(0.9); pointer-events: none; transition: all 0.8s ease; z-index: 60;
}
.award-scene-wrapper.active { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; }
.award-header-title {
font-family: 'Playfair Display', serif; font-size: 2rem; color: #701c2e;
text-align: center; text-transform: uppercase; letter-spacing: 1px; font-weight: 700;
border-bottom: 2px double #d4af37; padding-bottom: 8px; margin-bottom: 10px; width: 100%;
}
.chest-container {
display:flex; flex-direction:column; align-items:center; justify-content:center; cursor:pointer;
transition:transform .35s ease; margin:4px 0 8px;
}
.chest-container:hover { transform:scale(1.04) translateY(-3px); }
.chest-icon { width:170px; height:105px; position:relative; filter:drop-shadow(0 12px 18px rgba(0,0,0,.28)); }
.treasure-chest-body { position:absolute; left:10px; right:10px; bottom:8px; height:60px; border:3px solid #c9a64a; border-radius:8px 8px 14px 14px; background:linear-gradient(135deg,#8f969e,#555d66 58%,#343941); box-shadow:inset 0 0 18px rgba(255,255,255,.12); }
.treasure-chest-lid { position:absolute; left:8px; right:8px; top:18px; height:48px; border:3px solid #c9a64a; border-radius:70px 70px 8px 8px; background:linear-gradient(135deg,#b9bec4,#69717a 55%,#3d4249); transform-origin:bottom center; transition:transform .65s cubic-bezier(.175,.885,.32,1.275); z-index:2; }
.treasure-chest-lock { position:absolute; left:50%; top:53px; transform:translateX(-50%); width:25px; height:31px; border:3px solid #d4af37; border-radius:5px; background:linear-gradient(#ffe57f,#b98920); z-index:4; box-shadow:0 3px 8px rgba(0,0,0,.3); }
.treasure-chest-lock::after { content:'β‘'; color:#701c2e; font-weight:900; position:absolute; left:50%; top:1px; transform:translateX(-50%); font-size:15px; }
.treasure-chest-glow { position:absolute; width:120px; height:55px; left:25px; top:15px; background:radial-gradient(ellipse,rgba(255,229,127,.45),transparent 70%); opacity:0; transition:opacity .5s ease; z-index:1; pointer-events:none; }
.chest-icon.opened .treasure-chest-lid { transform:rotateX(-115deg) translateY(-4px); }
.chest-icon.opened .treasure-chest-glow { opacity:1; }
.chest-prompt { font-size:0.9rem; font-weight:700; color:#8b6b22; letter-spacing:1px; margin-top:2px; font-family:'Playfair Display',serif; font-style:italic; }
.award-contents-grid {
display: none; width: 100%; height: 68%; flex-direction: row; gap: 20px;
}
.award-contents-grid.revealed { display: flex; animation: fadeInContents 0.8s ease forwards; }
@keyframes fadeInContents { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
.award-left-box, .award-right-box {
width: 50%; height: 100%; border: 2px solid #e0c068; border-radius: 12px;
background: #ffffff; padding: 20px; display: flex; flex-direction: column;
align-items: center; justify-content: center; text-align: center; position: relative;
box-shadow: inset 0 0 15px rgba(212, 175, 55, 0.1);
}
.award-right-box {
padding: 0;
overflow: hidden;
flex-direction: row;
}
.certificate-action-half {
width: 50%; height: 100%; padding: 16px 12px;
display: flex; flex-direction: column; align-items: center; justify-content: center;
text-align: center; position: relative; cursor: pointer;
transition: background 0.3s ease, transform 0.3s ease;
}
.certificate-action-half + .certificate-action-half {
}
.certificate-action-half:hover { background: rgba(212,175,55,0.07); }
.certificate-action-half:active { transform: scale(0.98); }
.certificate-action-title {
font-family: 'Playfair Display', serif; color: #701c2e; font-size: 0.9rem;
font-weight: 700; margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0.8px;
}
.maker-label { font-size: 0.72rem; color: #777; margin-top: 10px; line-height: 1.35; }
.winner-label { font-size: 0.72rem; color: #777; margin-top: 10px; line-height: 1.35; }
.winner-signature {
width: 150px; height: 80px; display: flex; align-items: center; justify-content: center;
font-family: 'Great Vibes', cursive; font-size: 3rem; color: #701c2e;
transform: rotate(-7deg) scale(1.7); opacity: 0;
transition: all 0.45s cubic-bezier(0.175, 0.885, 0.32, 1.275);
pointer-events: none;
}
.winner-signature.signed { opacity: 1; transform: rotate(-7deg) scale(1); }
.signature-hint { font-size: 0.75rem; color: #701c2e; font-weight: 600; margin-top: 8px; }
.medal-animation-box {
font-size: 4rem; margin-bottom: 10px;
animation: medalBounce 2s ease-in-out infinite;
}
@keyframes medalBounce {
0%, 100% { transform: translateY(0) scale(1); }
50% { transform: translateY(-12px) scale(1.1); }
}
.stamp-container {
position: relative; width: 100%; height: 100%; display: flex;
flex-direction: column; justify-content: center; align-items: center; cursor: pointer;
}
.official-stamp {
width: 140px; height: 140px; border: 4px double #701c2e; border-radius: 50%;
color: #701c2e; display: flex; flex-direction: column; justify-content: center;
align-items: center; font-weight: 700; transform: rotate(-12deg) scale(2);
opacity: 0; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
background: rgba(112, 28, 46, 0.05); text-transform: uppercase;
}
.official-stamp.stamped { opacity: 1; transform: rotate(-12deg) scale(1); }
.stamp-hint { font-size: 0.85rem; color: #701c2e; font-weight: 600; margin-top: 10px; }
/* FINAL LOVING CLOSING LETTER SCENE */
.final-letter-wrapper {
position: absolute; left: 50%; top: 50%; width: 92vw; max-width: 900px; height: 84vh; max-height: 660px;
background: #fcf9f2; border: 5px double #d4af37; border-radius: 20px;
box-shadow: 0 25px 60px rgba(0,0,0,0.3); display: flex; flex-direction: column;
align-items: center; justify-content: space-between; padding: 25px 25px 20px 25px;
opacity: 0; transform: translate(-50%, -50%) scale(0.9); pointer-events: none; transition: all 0.8s ease; z-index: 70;
position: absolute; overflow: hidden;
}
.final-letter-wrapper.active { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; }
.decorated-letter-page {
width: 100%; height: 86%; background: radial-gradient(circle at center, #ffffff 0%, #fffbf2 100%);
border: 2px dashed #f48fb1; border-radius: 15px; padding: 20px; display: flex;
flex-direction: column; align-items: center; justify-content: center; position: relative;
box-shadow: inset 0 0 20px rgba(212, 175, 55, 0.15); overflow-y: auto;
}
.corner-decor { position: absolute; font-size: 1.5rem; opacity: 0.7; pointer-events: none; }
.corner-tl { top: 10px; left: 15px; }
.corner-tr { top: 10px; right: 15px; }
.corner-bl { bottom: 10px; left: 15px; }
.corner-br { bottom: 10px; right: 15px; }
.page-heading {
font-family: 'Great Vibes', cursive; font-size: 3rem; color: #701c2e;
margin-bottom: 5px; text-align: center;
}
.envelope-container {
position: relative; width: 320px; height: 210px; cursor: pointer;
perspective: 1000px; transition: transform 0.4s ease, opacity 0.5s ease;
margin: 15px 0; z-index: 10;
}
.envelope-container:hover { transform: scale(1.03); }
.envelope-body {
width: 100%; height: 100%; background: linear-gradient(135deg, #701c2e 0%, #4a101d 100%);
border: 2px solid #d4af37; border-radius: 12px; box-shadow: 0 15px 35px rgba(112, 28, 46, 0.4);
position: relative; overflow: hidden; display: flex; justify-content: center; align-items: center;
}
.envelope-flap {
position: absolute; top: 0; left: 0; width: 100%; height: 115px;
background: linear-gradient(145deg, #8b2137 0%, #701c2e 58%, #541322 100%);
clip-path: polygon(0 0, 100% 0, 50% 100%);
transform-origin: top center;
transition: transform 0.6s ease, z-index 0.2s ease; z-index: 5;
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
}
.wax-seal {
position: absolute; width: 58px; height: 58px;
left: 50%; top: 88px; transform: translate(-50%, -50%);
background: radial-gradient(circle, #fff3a5 0%, #f2cf55 62%, #b78720 100%);
border-radius: 50%; border: 3px solid #701c2e; box-shadow: 0 5px 12px rgba(0,0,0,0.32), inset 0 0 0 2px rgba(255,255,255,.35);
display: flex; justify-content: center; align-items: center; font-size: 1.5rem;
z-index: 8; transition: opacity 0.55s ease, transform 0.55s cubic-bezier(.175,.885,.32,1.275);
animation: sealPulse 2s ease-in-out infinite;
transform-origin: center;
}
.envelope-prompt {
position:absolute; bottom:15px; font-size:.78rem; font-weight:600; color:#ffe57f;
letter-spacing:1px; z-index:4; text-align:center; opacity:.85; font-family:'Caveat',cursive;
}
@keyframes sealPulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.06)} }
.envelope-container.open .wax-seal { opacity:0; transform:translate(-50%, -50%) scale(1.55) rotate(18deg); animation:none; }
.unfolded-note-card {
display: none; width: 92%; max-width: 650px; background: #ffffff;
border: 3px double #d4af37; border-radius: 14px; padding: 25px 20px;
box-shadow: 0 15px 40px rgba(0,0,0,0.15); position: relative; text-align: center;
animation: unfoldLetter 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}
@keyframes unfoldLetter {
0% { opacity: 0; transform: scale(0.3) translateY(50px); }
100% { opacity: 1; transform: scale(1) translateY(0); }
}
.unfolded-note-card.active { display: flex; flex-direction: column; align-items: center; }
.envelope-container.open .envelope-flap { transform: rotateX(180deg); z-index: 1; }
.letter-title { font-family: 'Great Vibes', cursive; font-size: 3.2rem; color: #701c2e; margin-bottom: 8px; }
.letter-body-text {
font-family: 'Caveat', cursive; font-size: 1.55rem; line-height: 1.5; color: #333;
text-align: center; width: 100%; outline: none; margin-bottom: 10px; word-wrap: break-word;
}
.word-counter {
font-size: 0.78rem; color: #888; font-family: 'Montserrat', sans-serif;
position: absolute; bottom: 8px; right: 15px; font-weight: 600;
}
.word-counter.exceeded { color: #d32f2f; font-weight: 700; }
.coupon-card { position:absolute; inset:28px; z-index:12; display:none; flex-direction:column; align-items:center; justify-content:center; gap:16px; padding:clamp(25px,5vw,58px); text-align:center; border:3px solid #d4af37; border-radius:20px; background:linear-gradient(135deg,#fffaf0,#fff0f4); box-shadow:0 18px 48px rgba(65,12,28,.22),inset 0 0 0 7px rgba(212,175,55,.12); overflow:hidden; }
.coupon-card.active { display:flex; animation:couponUnfold .7s cubic-bezier(.2,.8,.2,1) both; }
@keyframes couponUnfold { from { opacity:0; transform:scale(.82) rotate(-2deg) } to { opacity:1; transform:scale(1) rotate(0) } }
.coupon-card:before,.coupon-card:after { content:''; position:absolute; top:50%; width:26px; height:26px; border-radius:50%; background:#f8bbd0; transform:translateY(-50%); }
.coupon-card:before { left:-14px } .coupon-card:after { right:-14px }
.coupon-kicker { color:#a36a24; font-size:.78rem; font-weight:800; letter-spacing:4px; }
.coupon-title { color:#701c2e; font:clamp(2rem,5vw,3.2rem) 'Great Vibes',cursive; }
.coupon-note { max-width:570px; color:#57363f; font:clamp(1.15rem,2.8vw,1.55rem)/1.55 'Caveat',cursive; }
.coupon-redeem { padding:12px 20px; border-top:1px dashed #bb8190; border-bottom:1px dashed #bb8190; color:#8b3655; font-weight:700; letter-spacing:.5px; }
@media(max-width:600px) { .shayari-card { gap:14px; padding:30px 18px; } .coupon-card { inset:14px; gap:11px; padding:28px 18px; } .coupon-redeem { font-size:.82rem; } }
@media (max-height:700px) {
.bouquet-scene-wrapper { height:90vh; max-height:none; }
.shayari-card { gap:6px; padding:14px 24px; }
.shayari-kicker { font-size:.66rem; letter-spacing:2px; }
.shayari-heading { font-size:clamp(1.55rem,4vh,2.15rem); line-height:1; }
.shayari-lines { font-size:clamp(.95rem,2.25vh,1.22rem); line-height:1.2; }
.shayari-heart { font-size:.95rem; line-height:1; }
.shayari-card .proceed-btn { padding:8px 20px; font-size:.88rem; margin-top:0; }
}
.music-widget { position:relative; }
.music-panel { position:absolute; top:52px; right:0; width:min(330px,90vw); padding:16px; display:none; gap:9px; background:rgba(255,253,250,.98); border:2px solid #d4af37; border-radius:18px; box-shadow:0 12px 32px rgba(39,5,18,.25); color:#5c3540; text-align:left; z-index:500; }
.music-panel.open { display:grid; }
.music-panel label { color:#701c2e; font-weight:800; font-size:.95rem; }
.music-panel p { font-size:.78rem; line-height:1.4; margin:0; }
.music-panel input { width:100%; min-width:0; border:1px solid #d9b7bf; border-radius:10px; padding:10px; color:#4a2631; background:#fff; font:inherit; font-size:.8rem; }
.music-panel-actions { display:flex; gap:8px; }
.music-action-btn { border:1px solid #d4af37; border-radius:18px; padding:8px 12px; background:#701c2e; color:#fff; font-weight:700; cursor:pointer; }
.music-action-btn.secondary { background:#fff; color:#701c2e; }
.music-status { color:#815566; font-size:.75rem; line-height:1.4; }
.music-frame-wrap { display:none; justify-self:center; width:200px; height:200px; overflow:hidden; border-radius:12px; background:#14070d; }
.music-frame-wrap.playing { display:block; }
.music-frame-wrap iframe { display:block; width:200px; height:200px; border:0; }
@media(max-width:520px) { .top-bar { top:12px; right:12px; gap:6px; } .top-btn { padding:7px 10px; font-size:.72rem; } .music-panel { width:min(300px,92vw); } }
.proposal-scene-wrapper{width:min(96vw,1000px);min-height:min(72vh,560px);display:grid!important;grid-template-columns:1fr 1.2fr 1fr;grid-template-rows:1fr auto;align-items:center;justify-items:center;gap:18px;padding:clamp(18px,4vw,44px);position:relative}.proposal-scene-wrapper .page-corners{position:absolute;inset:0;pointer-events:none}.proposal-scene-wrapper .proposal-eyebrow,.proposal-scene-wrapper .proposal-title,.proposal-scene-wrapper .proposal-subtitle,.proposal-scene-wrapper .ring-hint{display:none!important}.proposal-scene-wrapper .ring-box-button{grid-column:1;grid-row:1/3;z-index:2;background:transparent;border:0;cursor:default}.proposal-scene-wrapper .ring-box{transform:scale(1.05)}.proposal-scene-wrapper .ring-box-lid{transform:rotate(-42deg) translate(-22px,-22px)!important}.proposal-scene-wrapper .ring-pop{display:none!important}.proposal-scene-wrapper:after{content:'π';grid-column:3;grid-row:1/3;font-size:clamp(5rem,12vw,9rem);filter:drop-shadow(0 10px 14px rgba(212,175,55,.45));animation:ringFloat 2.4s ease-in-out infinite;align-self:center}.proposal-scene-wrapper .proposal-question{grid-column:2;grid-row:1;margin:0;text-align:center;font-size:clamp(1.5rem,3.5vw,2.8rem)}.proposal-scene-wrapper .proposal-buttons{grid-column:2;grid-row:2;display:flex;justify-content:center;gap:14px;flex-wrap:wrap}.proposal-scene-wrapper .proposal-choice{z-index:2!important}.proposal-scene-wrapper .proposal-question:not(.visible),.proposal-scene-wrapper .proposal-buttons:not(.visible){visibility:visible;opacity:1;transform:none}.music-frame-wrap{width:320px;height:180px}.music-frame-wrap iframe{width:320px;height:180px}@keyframes ringFloat{50%{transform:translateY(-10px) rotate(8deg)}}@media(max-width:650px){.proposal-scene-wrapper{grid-template-columns:.8fr 1.2fr;grid-template-rows:auto auto auto;gap:10px;padding:16px;min-height:70vh}.proposal-scene-wrapper .ring-box-button{grid-column:1;grid-row:1/3;transform:scale(.78)}.proposal-scene-wrapper .proposal-question{grid-column:2;grid-row:1}.proposal-scene-wrapper .proposal-buttons{grid-column:2;grid-row:2;gap:8px}.proposal-scene-wrapper:after{grid-column:1/3;grid-row:3;font-size:4rem}.music-frame-wrap{width:280px;height:158px}.music-frame-wrap iframe{width:280px;height:158px}}
body{width:100%;min-width:0;overflow:hidden}
.scene-container{position:fixed!important;inset:0!important;width:100vw!important;height:100vh!important;display:block!important;margin:0!important}
.gift-area-decor{position:absolute!important;left:50%!important;top:50%!important;transform:translate(-50%,-50%)!important;margin:0!important}
.bouquet-scene-wrapper,.proposal-scene-wrapper,.yes-memory-scene,.award-scene-wrapper{left:50%!important;top:50%!important}
.proposal-scene-wrapper{width:min(94vw,980px)!important;height:min(76vh,600px)!important;min-height:0!important;box-sizing:border-box!important;grid-template-columns:minmax(0,1fr) minmax(0,1.5fr) minmax(0,1fr)!important;grid-template-rows:minmax(0,1fr) auto!important;gap:clamp(8px,2vw,22px)!important;padding:clamp(18px,4vw,42px)!important;transform:translate(-50%,-50%)!important}
.proposal-scene-wrapper.active{transform:translate(-50%,-50%)!important}
.proposal-scene-wrapper .ring-box-button{margin:0!important}
.proposal-scene-wrapper .proposal-question{width:100%;justify-self:center;align-self:end}
.proposal-scene-wrapper .proposal-buttons{width:100%;justify-self:center;align-self:start}
@media(max-width:650px){.proposal-scene-wrapper{width:96vw!important;height:76vh!important;grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr)!important;grid-template-rows:minmax(0,1fr) auto auto!important}.proposal-scene-wrapper .proposal-box-button{grid-column:1}.proposal-scene-wrapper .proposal-question{grid-column:2}.proposal-scene-wrapper .proposal-buttons{grid-column:2}.proposal-scene-wrapper:after{grid-column:1/3;grid-row:3}.gift-area-decor{transform:translate(-50%,-50%) scale(.78)!important}}
</style>
</head>
<body>
<div class="top-bar">
<button class="top-btn" id="editBtn">βοΈ Edit Mode: OFF</button>
</div>
<canvas id="stars-canvas"></canvas>
<canvas id="magical-canvas"></canvas>
<canvas id="confetti-canvas"></canvas>
<div class="scene-container">
<div class="instruction-text" id="statusText">Tap the golden ribbon to untie π</div>
<!-- CENTERED & DECORATED GIFT BOX AREA -->
<div class="gift-area-decor" id="giftAreaDecor">
<div class="gift-aura-ring"></div>
<div class="gift-sparkles-around"></div>
<div class="gift-box" id="giftBox">
<div class="ribbon ribbon-v" id="ribbonV"></div>
<div class="ribbon ribbon-h" id="ribbonH"></div>
<div class="gold-bow" id="goldBow">π</div>
<div class="sticky-note" id="stickyNote">
<p id="stickyNoteText" contenteditable="false">ππππππ
Dear Om, youπ«΅π»received a giftπ...!!</p>
</div>
</div>
</div>
<!-- STEP 1: A SHAYARI FROM MY HEART -->
<div class="bouquet-scene-wrapper" id="bouquetScene">
<div class="shayari-card">
<div class="shayari-kicker">A little promise, from my heart</div>
<h2 class="shayari-heading">For you, Om β‘</h2>
<div class="shayari-lines" id="shayariText">Iβll love you for four days:
π· Spring β’ βοΈ Summer β’ π Autumn β’ βοΈ Winter;
Oh no⦠for three days:
π
Yesterday β’ π€ Today β’ π Tomorrow;
how about two daysβ¦:
βοΈ Day β’ π Night;
maybe one is enoughβ¦:
π Every day π</div>
<div class="shayari-heart">β§ β‘ β§</div>
<button class="proceed-btn" id="openProposalBtn">Next β</button>
</div>
</div>
<!-- STEP 2: THE RING-BOX REVEAL -->
<!-- STEP 2: THE RING-BOX REVEAL -->
<div class="proposal-scene-wrapper" id="proposalScene" aria-live="polite">
<div class="page-corners" aria-hidden="true"><span>β§ β</span><span>β β§</span><span>β β§</span><span>β§ β</span></div>
<div class="proposal-eyebrow">πΈγβ§γπΈ</div>
<h2 class="proposal-title" id="proposalTitle">A little surprise for you</h2>
<p class="proposal-subtitle" id="proposalSubtitle">Tap the burgundy box to open your surprise.</p>
<button class="ring-box-button" id="ringBoxButton" aria-label="Open the ring box">
<div class="ring-box" id="ringBox">
<div class="ring-box-base"></div><div class="ring-box-lid"></div>
<div class="ring-pop" aria-hidden="true">π</div>
</div>
</button>
<div class="ring-hint" id="ringHint">A little sparkle is waiting inside β¨</div>
<h2 class="proposal-question" id="proposalQuestion">Om, will you marry me? π</h2>
<div class="proposal-buttons" id="proposalButtons">
<button class="proposal-choice" id="proposalYes">YES! π</button>
<button class="proposal-choice" id="proposalNo">No π</button>
</div>
</div>
<!-- AFTER-YES TEXT MEMORY PAGE -->
<div class="yes-memory-scene" id="yesMemoryScene" aria-live="polite">
<div class="yes-memory-flourish">πΈ β¨ π β¨ πΈ</div>
<h2 class="yes-memory-title">A Little Promise for Us β‘</h2>
<div class="yes-memory-message" id="yesMemoryMessage">My favorite answer, from my favorite person. I canβt wait to make a lifetime of memories with you. π</div>
<button class="proceed-btn yes-memory-next" id="yesMemoryNext">Continue to your surprise β¨</button>
</div>
<!-- STEP 4: CERTIFICATE & TREASURE CHEST AWARD SCENE -->
<div class="award-scene-wrapper" id="awardScene">
<div class="award-header-title" id="awardHeader">
π Official Certificate of the Most Handsome & Cutest Boyfriend π
</div>
<div class="chest-container" id="chestBox">
<div class="chest-icon" id="chestIcon">
<div class="treasure-chest-glow"></div>
<div class="treasure-chest-lid"></div>
<div class="treasure-chest-body"></div>
<div class="treasure-chest-lock"></div>
</div>
<div class="chest-prompt" id="chestPrompt">A little treasure awaits Om β‘</div>
</div>
<div class="award-contents-grid" id="awardGrid">
<div class="award-left-box">
<div class="medal-animation-box">π₯</div>
<h3 style="font-family:'Great Vibes', cursive; font-size:2.4rem; color:#701c2e; margin-bottom:5px;">Highest Award</h3>
<p style="font-size:0.95rem; color:#444; line-height:1.5;">
Presented for being the <strong>bestest blessing in my life</strong>, the cutest boyfriend, and having the most precious heart ever!
</p>
</div>
<div class="award-right-box" id="stampBox">
<div class="certificate-action-half maker-half" id="makerStampHalf">
<div class="certificate-action-title">Stamp of the Maker</div>
<div class="official-stamp stamped" id="officialStamp">
<span style="font-size:0.62rem;">STAMP OF</span>
<span style="font-size:0.88rem; margin:2px 0;">MALKIN</span>
<span style="font-size:0.58rem;">PRACHI β‘</span>
</div>
<div class="maker-label">Officially stamped by<br><strong>Malkin [Prachi, (^_^)]</strong></div>
</div>
<div class="certificate-action-half winner-half" id="winnerSignatureHalf">
<div class="certificate-action-title">Signature of the Winner</div>
<div class="winner-signature" id="winnerSignature">Om β‘</div>
<div class="winner-label" id="winnerLabel">Winner: <strong>Om</strong></div>
<div class="signature-hint" id="signatureHint">Tap here to reveal your signature βοΈ</div>
</div>
</div>
</div>
<button class="proceed-btn" id="proceedToLetterBtn" style="margin-top:15px; display:none;">
Read Final Loving Letter βοΈ β
</button>
</div>
<!-- STEP 4: FINAL LOVING CLOSING LETTER -->
<div class="final-letter-wrapper" id="finalLetterScene">
<div class="decorated-letter-page" id="decoratedLetterPage">
<div class="corner-decor corner-tl">πΈ πΏ</div>
<div class="corner-decor corner-tr">πΏ πΈ</div>
<div class="corner-decor corner-bl">πΈ πΏ</div>
<div class="corner-decor corner-br">πΏ πΈ</div>
<h2 class="page-heading" id="pageHeadingTitle">A Secret Message For You β‘</h2>
<div class="envelope-container" id="envelopeBox">
<div class="envelope-flap" id="envelopeFlap">
<div class="wax-seal" id="waxSeal">π</div>
</div>
<div class="envelope-body">
<div class="envelope-prompt" id="envelopePrompt">β‘</div>
</div>
</div>
<div class="unfolded-note-card" id="unfoldedNoteCard">
<div class="washi-tape" style="top:-10px; left:50%; transform:translateX(-50%);"></div>
<h2 class="letter-title">My Last Words For You β‘</h2>
<div class="letter-body-text" id="finalLetterText" contenteditable="false">
My dearest darling, thank you for walking through this little story with me. Distance may keep us apart in miles, but you are in every thought, every prayer, and every beat of my heart. You are my greatest award, my safest home, and my favorite person forever. I love you so much!
</div>
<div class="word-counter" id="wordCounter">Words: 57 / 200 Max</div>
<button class="proceed-btn" id="continueToCouponBtn" style="margin-top:16px;">One last little surprise β¨</button>
</div>
</div>
<div class="coupon-card" id="couponCard" aria-live="polite">
<div class="coupon-kicker">A LITTLE COUPON FOR YOU</div>
<h2 class="coupon-title">Your Forever Pass β‘</h2>
<p class="coupon-note">Thank you for continuing this journey with me. I hope we keep choosing each other, today and always. Thank you for coming into my life. π</p>
<div class="coupon-redeem">GOOD FOR: a lifetime of love, laughter & us β¨</div>
<button class="proceed-btn" id="finishBtn" style="margin-top:8px;">Keep this forever Β· Finish π</button>
</div>
</div>
</div>
<script>
const giftAreaDecor = document.getElementById('giftAreaDecor');
const giftBox = document.getElementById('giftBox');
const ribbonV = document.getElementById('ribbonV');
const ribbonH = document.getElementById('ribbonH');
const stickyNote = document.getElementById('stickyNote');
const stickyNoteText = document.getElementById('stickyNoteText');
const bouquetScene = document.getElementById('bouquetScene');
const openProposalBtn = document.getElementById('openProposalBtn');
const shayariText = document.getElementById('shayariText');
const proposalScene = document.getElementById('proposalScene');
const ringBoxButton = document.getElementById('ringBoxButton');
const ringBox = document.getElementById('ringBox');
const proposalTitle = document.getElementById('proposalTitle');
const proposalSubtitle = document.getElementById('proposalSubtitle');
const ringHint = document.getElementById('ringHint');
const proposalQuestion = document.getElementById('proposalQuestion');
const proposalButtons = document.getElementById('proposalButtons');
const proposalYes = document.getElementById('proposalYes');
const proposalNo = document.getElementById('proposalNo');
const yesMemoryScene = document.getElementById('yesMemoryScene');
const yesMemoryNext = document.getElementById('yesMemoryNext');
let proposalOpened = false;
let proposalAccepted = false;
let noAttemptCount = 0;
const statusText = document.getElementById('statusText');
const editBtn = document.getElementById('editBtn');
const awardScene = document.getElementById('awardScene');
const chestBox = document.getElementById('chestBox');
const chestIcon = document.getElementById('chestIcon');
const chestPrompt = document.getElementById('chestPrompt');
const awardGrid = document.getElementById('awardGrid');
const makerStampHalf = document.getElementById('makerStampHalf');
const winnerSignatureHalf = document.getElementById('winnerSignatureHalf');
const officialStamp = document.getElementById('officialStamp');
const winnerSignature = document.getElementById('winnerSignature');
const signatureHint = document.getElementById('signatureHint');
const proceedToLetterBtn = document.getElementById('proceedToLetterBtn');
const finalLetterScene = document.getElementById('finalLetterScene');
const envelopeBox = document.getElementById('envelopeBox');
const unfoldedNoteCard = document.getElementById('unfoldedNoteCard');
const finalLetterText = document.getElementById('finalLetterText');
const wordCounter = document.getElementById('wordCounter');
const finishBtn = document.getElementById('finishBtn');
const continueToCouponBtn = document.getElementById('continueToCouponBtn');
const couponCard = document.getElementById('couponCard');
const decoratedLetterPage = document.getElementById('decoratedLetterPage');
let isRibbonUntied = false;
let isNoteRemoved = false;
let isBoxOpened = false;
let isEditMode = false;
let isChestOpened = false;
let isStamped = false;
let isWinnerSigned = false;
let isEnvelopeOpened = false;
let romanticMusicContext = null;
let romanticMusicTimer = null;
let romanticMusicStarted = false;
async function startRomanticMusic() {
if (romanticMusicStarted) return;
const AudioContextType = window.AudioContext || window.webkitAudioContext;
if (!AudioContextType) return;
romanticMusicStarted = true;
romanticMusicContext = new AudioContextType();
const ctx = romanticMusicContext;
const master = ctx.createGain();
master.gain.setValueAtTime(0.0001, ctx.currentTime);
master.gain.exponentialRampToValueAtTime(0.45, ctx.currentTime + 1.8);
master.connect(ctx.destination);
await ctx.resume();
const melody = [72,76,79,76,69,72,76,72,67,72,76,79,76,74,67,71];
const chords = [[48,55,60],[45,52,57],[41,48,53],[43,50,55]];
const beatLength = 0.82;
let beat = 0;
let nextBeat = ctx.currentTime + 0.08;
function note(midi, at, length, type, volume) {
const osc = ctx.createOscillator();
const envelope = ctx.createGain();
osc.type = type;
osc.frequency.value = 440 * Math.pow(2, (midi - 69) / 12);
envelope.gain.setValueAtTime(0.0001, at);
envelope.gain.exponentialRampToValueAtTime(volume, at + 0.12);
envelope.gain.exponentialRampToValueAtTime(0.0001, at + length);
osc.connect(envelope); envelope.connect(master);
osc.start(at); osc.stop(at + length + 0.03);
}
romanticMusicTimer = window.setInterval(() => {
if (ctx.state !== 'running') return;
while (nextBeat < ctx.currentTime + 0.22) {
const step = beat % 16;
if (step % 4 === 0) {
const chord = chords[Math.floor(step / 4)];
chord.forEach((pitch, i) => note(pitch, nextBeat, beatLength * 3.7, 'sine', i === 0 ? 0.022 : 0.014));
note(chord[0] - 12, nextBeat, beatLength * 3.5, 'sine', 0.035);
}
note(melody[step], nextBeat, beatLength * 0.78, 'triangle', 0.075);
beat++; nextBeat += beatLength;
}
}, 100);
}
// Gift Box Interactive Unwrapping
giftBox.addEventListener('click', (event) => {
if (event.target === stickyNoteText && isEditMode) return;
if (!isRibbonUntied) {
giftBox.classList.add('unwrapped');
isRibbonUntied = true;
statusText.innerText = "Now tap the sticky note to open the box βοΈ";
spawnShootingStarBurst();
triggerConfetti();
} else if (!isNoteRemoved) {
stickyNote.classList.add('fade-out');
isNoteRemoved = true;
statusText.innerText = "Tap the gift box to open! π";
spawnShootingStarBurst();
} else if (!isBoxOpened) {
startRomanticMusic();
giftAreaDecor.classList.add('hide-box');
isBoxOpened = true;
document.body.classList.add('rose-theme');
statusText.innerText = "";
bouquetScene.classList.add('active');
triggerConfetti();
spawnShootingStarBurst();
}
});
openProposalBtn.addEventListener('click', () => {
bouquetScene.classList.remove('active');
bouquetScene.style.display = 'none';
proposalScene.classList.add('active');
proposalOpened = true;
ringBox.classList.add('open');
proposalTitle.style.display = 'none';
proposalSubtitle.style.display = 'none';
ringHint.style.display = 'none';
proposalQuestion.classList.add('visible');
proposalButtons.classList.add('visible');
triggerConfetti();
});
ringBoxButton.addEventListener('click', () => {
if (proposalOpened) return;
proposalOpened = true;
ringBox.classList.add('open');
proposalTitle.style.display = 'none';
proposalSubtitle.style.display = 'none';
ringHint.style.display = 'none';
proposalQuestion.classList.add('visible');
proposalButtons.classList.add('visible');
triggerConfetti();
});
proposalNo.addEventListener('pointerenter', dodgeNoButton);
proposalNo.addEventListener('pointerdown', (event) => { event.preventDefault(); dodgeNoButton(); });
proposalNo.addEventListener('click', (event) => { event.preventDefault(); dodgeNoButton(); });
function dodgeNoButton(){if(proposalAccepted||!proposalButtons.classList.contains('visible'))return;noAttemptCount++;const b=proposalNo.getBoundingClientRect(),maxX=Math.max(8,innerWidth-b.width-8),maxY=Math.max(8,innerHeight-b.height-8),x=8+Math.random()*(maxX-8),y=8+Math.random()*(maxY-8);proposalNo.style.position='fixed';proposalNo.style.zIndex='500';proposalNo.style.margin='0';proposalNo.style.transition='left .28s ease,top .28s ease,transform .25s ease';const sr=proposalScene.getBoundingClientRect();proposalNo.style.left=(x-sr.left)+'px';proposalNo.style.top=(y-sr.top)+'px';proposalNo.style.transform='rotate('+(Math.random()*18-9)+'deg)';let m=document.getElementById('proposalShyMessage');if(!m){m=document.createElement('div');m.id='proposalShyMessage';m.style.cssText='position:fixed;z-index:501;pointer-events:none;padding:6px 11px;border:1px solid #e8c66a;border-radius:999px;background:#fffaf0;color:#701c2e;font:600 .82rem/1.2 system-ui,sans-serif;box-shadow:0 4px 12px rgba(50,8,22,.16);opacity:0;transition:opacity .18s ease;';document.body.appendChild(m);}const lines=['Noooβ¦ Iβm shy π','Catch me if you can! π¨','Eep, too quick! π'];m.textContent=lines[(noAttemptCount-1)%lines.length];m.style.left=Math.max(8,Math.min(innerWidth-170,x))+'px';m.style.top=Math.max(8,y-34)+'px';m.style.opacity='1';clearTimeout(window.proposalShyTimer);window.proposalShyTimer=setTimeout(()=>m.style.opacity='0',900);const s=Math.min(1.75,1+noAttemptCount*.1);proposalYes.style.transform='scale('+s+')';proposalYes.style.fontSize=(1.08+Math.min(noAttemptCount*.035,.35))+'rem';}
proposalYes.addEventListener('click', () => {
if (proposalAccepted) return;
proposalAccepted = true;
proposalButtons.classList.remove('visible');
proposalQuestion.classList.remove('visible');
proposalScene.classList.remove('active');
proposalScene.style.display = 'none';
triggerConfetti();
showerCelebration();
setTimeout(() => {
yesMemoryScene.classList.add('active');
triggerConfetti();
}, 450);
});
function showerCelebration() {
const symbols = ['πΈ','πΉ','β¨','π','π·','β','π','π'];
for (let i = 0; i < 85; i++) {
const particle = document.createElement('span');
particle.className = 'celebration-fall';
particle.textContent = symbols[Math.floor(Math.random() * symbols.length)];
particle.style.left = Math.random() * 100 + 'vw';
particle.style.fontSize = (16 + Math.random() * 22) + 'px';
particle.style.animationDuration = (2.5 + Math.random() * 3.2) + 's';
particle.style.animationDelay = (Math.random() * 1.3) + 's';
particle.style.setProperty('--drift', (Math.random() * 180 - 90) + 'px');
document.body.appendChild(particle);
particle.addEventListener('animationend', () => particle.remove(), { once: true });
}
} yesMemoryNext.addEventListener('click', () => {
yesMemoryScene.classList.remove('active');
setTimeout(() => {
yesMemoryScene.style.display = 'none';
awardScene.classList.add('active');
triggerConfetti();
}, 550);
});
chestBox.addEventListener('click', () => {
if (!isChestOpened) {
isChestOpened = true;
chestIcon.classList.add('opened');
chestPrompt.innerText = "Your treasure has been revealed β‘";
awardGrid.classList.add('revealed');
triggerConfetti();
}
});
makerStampHalf.addEventListener('click', () => {
if (isChestOpened) {
isStamped = true;
officialStamp.classList.add('stamped');
}
});
winnerSignatureHalf.addEventListener('click', () => {
if (!isChestOpened || isWinnerSigned) return;
isWinnerSigned = true;
winnerSignature.classList.add('signed');
signatureHint.innerText = "Signed by Om with love β€οΈ";
proceedToLetterBtn.style.display = 'flex';
triggerConfetti();
});
proceedToLetterBtn.addEventListener('click', () => {
awardScene.classList.remove('active');
setTimeout(() => {
awardScene.style.display = 'none';
finalLetterScene.classList.add('active');
updateWordCount();
}, 600);
});
envelopeBox.addEventListener('click', () => {
if (!isEnvelopeOpened) {
isEnvelopeOpened = true;
envelopeBox.classList.add('open');
triggerConfetti();
setTimeout(() => {
envelopeBox.style.display = 'none';
unfoldedNoteCard.classList.add('active');
}, 700);
}
});
continueToCouponBtn.addEventListener('click', () => {
decoratedLetterPage.style.visibility = 'hidden';
couponCard.classList.add('active');
finishBtn.style.display = 'inline-flex';
triggerConfetti();
});
finalLetterText.addEventListener('input', updateWordCount);
function updateWordCount() {
const text = finalLetterText.innerText.trim();
const words = text ? text.split(/\s+/).length : 0;
wordCounter.innerText = `Words: ${words} / 200 Max`;
if (words > 200) {
wordCounter.classList.add('exceeded');
} else {
wordCounter.classList.remove('exceeded');
}
}
finishBtn.addEventListener('click', () => {
alert("Replaying your gift experience! β‘");
location.reload();
});
editBtn.addEventListener('click', () => {
isEditMode = !isEditMode;
editBtn.innerText = isEditMode ? "βοΈ Edit Mode: ON" : "βοΈ Edit Mode: OFF";
editBtn.style.background = isEditMode ? "#d4af37" : "#ffffff";
editBtn.style.color = isEditMode ? "#ffffff" : "#701c2e";
document.body.classList.toggle('is-editing', isEditMode);
shayariText.contentEditable = isEditMode;
shayariText.classList.toggle('editable-active', isEditMode);
stickyNoteText.contentEditable = isEditMode;
stickyNoteText.classList.toggle('editable-active', isEditMode);
finalLetterText.contentEditable = isEditMode;
finalLetterText.classList.toggle('editable-active', isEditMode);
});
/* CONFETTI ANIMATION */
function triggerConfetti() {
const canvas = document.getElementById('confetti-canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const particles = [];
const colors = ['#f48fb1', '#d4af37', '#701c2e', '#ffffff', '#ffe57f'];
for (let i = 0; i < 80; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height - canvas.height,
size: Math.random() * 8 + 4,
color: colors[Math.floor(Math.random() * colors.length)],
speedY: Math.random() * 3 + 2,
speedX: Math.random() * 2 - 1
});
}
let animationFrame;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach(p => {
p.y += p.speedY;
p.x += p.speedX;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
});
if (particles.some(p => p.y < canvas.height)) {
animationFrame = requestAnimationFrame(animate);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height);
cancelAnimationFrame(animationFrame);
}
}
animate();
}
/* STARS & SHOOTING STARS ANIMATION ENGINE */
const starsCanvas = document.getElementById('stars-canvas');
const sCtx = starsCanvas.getContext('2d');
starsCanvas.width = window.innerWidth;
starsCanvas.height = window.innerHeight;
let staticStars = [];
let shootingStars = [];
function initStars() {
staticStars = [];
for (let i = 0; i < 240; i++) {
staticStars.push({
x: Math.random() * starsCanvas.width,
y: Math.random() * starsCanvas.height,
radius: Math.random() * 2.4 + 0.6,
alpha: Math.random(),
twinkleSpeed: Math.random() * 0.035 + 0.008
});
}
}
initStars();
function spawnShootingStarBurst() {
for (let i = 0; i < 5; i++) {
setTimeout(() => {
shootingStars.push({
x: Math.random() * starsCanvas.width * 0.8,
y: Math.random() * starsCanvas.height * 0.4,
length: Math.random() * 120 + 80,
speed: Math.random() * 10 + 12,
angle: Math.PI / 4,
alpha: 1
});
}, i * 200);
}
}
function animateStars() {
sCtx.clearRect(0, 0, starsCanvas.width, starsCanvas.height);
// Render static twinkling stars
staticStars.forEach(s => {
s.alpha += s.twinkleSpeed;
if (s.alpha > 1 || s.alpha < 0.1) s.twinkleSpeed = -s.twinkleSpeed;
sCtx.fillStyle = `rgba(255, 229, 127, ${s.alpha})`;
sCtx.beginPath();
sCtx.arc(s.x, s.y, s.radius, 0, Math.PI * 2);
sCtx.fill();
});
// Render shooting stars
for (let i = shootingStars.length - 1; i >= 0; i--) {
const star = shootingStars[i];
const endX = star.x + Math.cos(star.angle) * star.length;
const endY = star.y + Math.sin(star.angle) * star.length;
const grad = sCtx.createLinearGradient(star.x, star.y, endX, endY);
grad.addColorStop(0, `rgba(255, 255, 255, ${star.alpha})`);
grad.addColorStop(0.5, `rgba(212, 175, 55, ${star.alpha * 0.6})`);
grad.addColorStop(1, 'rgba(255, 255, 255, 0)');
sCtx.strokeStyle = grad;
sCtx.lineWidth = 2.5;
sCtx.beginPath();
sCtx.moveTo(star.x, star.y);
sCtx.lineTo(endX, endY);
sCtx.stroke();
star.x += Math.cos(star.angle) * star.speed;
star.y += Math.sin(star.angle) * star.speed;
star.alpha -= 0.015;
if (star.alpha <= 0 || star.y > starsCanvas.height) {
shootingStars.splice(i, 1);
}
}
requestAnimationFrame(animateStars);
}
animateStars();
// Periodically generate a ambient shooting star in the gift opening phase
setInterval(() => {
if (Math.random() > 0.15) {
shootingStars.push({
x: Math.random() * starsCanvas.width * 0.6,
y: Math.random() * starsCanvas.height * 0.3,
length: Math.random() * 100 + 60,
speed: Math.random() * 8 + 10,
angle: Math.PI / 4,
alpha: 1
});
}
}, 1400);
/* MAGICAL PARTICLES + CONTINUOUS HEART / FLOWER FALL */
const magicalCanvas = document.getElementById('magical-canvas');
const mCtx = magicalCanvas.getContext('2d');
magicalCanvas.width = window.innerWidth;
magicalCanvas.height = window.innerHeight;
const magicalParticles = Array.from({ length: 70 }, () => ({
x: Math.random() * magicalCanvas.width,
y: Math.random() * magicalCanvas.height,
radius: Math.random() * 3 + 1,
alpha: Math.random() * 0.65 + 0.2,
speed: Math.random() * 0.6 + 0.2
}));
const fallingDecor = Array.from({ length: 34 }, (_, i) => ({
x: Math.random() * magicalCanvas.width,
y: Math.random() * magicalCanvas.height,
speed: Math.random() * 0.8 + 0.35,
drift: Math.random() * 0.5 - 0.25,
size: Math.random() * 10 + 9,
rotation: Math.random() * Math.PI * 2,
rotationSpeed: Math.random() * 0.015 - 0.0075,
type: i % 3 === 0 ? 'flower' : 'heart',
alpha: Math.random() * 0.4 + 0.35
}));
function drawHeart(ctx, x, y, size, rotation, alpha) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(rotation);
ctx.globalAlpha = alpha;
ctx.fillStyle = '#f48fb1';
ctx.beginPath();
const s = size;
ctx.moveTo(0, s * 0.35);
ctx.bezierCurveTo(-s * 0.9, -s * 0.2, -s * 0.65, -s, 0, -s * 0.45);
ctx.bezierCurveTo(s * 0.65, -s, s * 0.9, -s * 0.2, 0, s * 0.35);
ctx.fill();
ctx.restore();
}
function drawFlower(ctx, x, y, size, rotation, alpha) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(rotation);
ctx.globalAlpha = alpha;
ctx.fillStyle = '#ffd1e1';
for (let i = 0; i < 5; i++) {
ctx.save();
ctx.rotate((Math.PI * 2 * i) / 5);
ctx.beginPath();
ctx.ellipse(0, -size * 0.42, size * 0.27, size * 0.48, 0, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
ctx.fillStyle = '#ffe57f';
ctx.beginPath();
ctx.arc(0, 0, size * 0.18, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
function animateMagical() {
mCtx.clearRect(0, 0, magicalCanvas.width, magicalCanvas.height);
magicalParticles.forEach(p => {
p.y -= p.speed;
if (p.y < 0) p.y = magicalCanvas.height;
mCtx.fillStyle = `rgba(212, 175, 55, ${p.alpha})`;
mCtx.beginPath();
mCtx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
mCtx.fill();
});
fallingDecor.forEach(p => {
p.y += p.speed;
p.x += p.drift + Math.sin(p.y * 0.01) * 0.12;
p.rotation += p.rotationSpeed;
if (p.y > magicalCanvas.height + 30) {
p.y = -30;
p.x = Math.random() * magicalCanvas.width;
}
if (p.x < -30) p.x = magicalCanvas.width + 30;
if (p.x > magicalCanvas.width + 30) p.x = -30;
if (p.type === 'heart') {
drawHeart(mCtx, p.x, p.y, p.size, p.rotation, p.alpha);
} else {
drawFlower(mCtx, p.x, p.y, p.size, p.rotation, p.alpha);
}
});
requestAnimationFrame(animateMagical);
}
animateMagical();
window.addEventListener('resize', () => {
starsCanvas.width = window.innerWidth;
starsCanvas.height = window.innerHeight;
magicalCanvas.width = window.innerWidth;
magicalCanvas.height = window.innerHeight;
initStars();
fallingDecor.forEach(p => {
p.x = Math.random() * magicalCanvas.width;
p.y = Math.random() * magicalCanvas.height;
});
});
</script>
</body>
</html>