<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
    <title>С днём рождения, Полина! 🦄💖</title>
    <style>
        :root {
            --pink-hot: #ff4088;
            --pink-soft: #ffb3c6;
            --pink-light: #ffe0ec;
            --lavender: #e8d5f5;
            --white: #ffffff;
            --gold: #ffd700;
            --card-bg: rgba(255, 255, 255, 0.75);
            --shadow: 0 8px 32px rgba(255, 105, 135, 0.2);
            --shadow-lg: 0 20px 60px rgba(255, 105, 135, 0.3);
            --font-main: 'Segoe UI', 'SF Pro Display', 'Helvetica Neue', system-ui, -apple-system, sans-serif;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html,
        body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            font-family: var(--font-main);
            -webkit-tap-highlight-color: transparent;
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            user-select: none;
            -webkit-user-select: none;
            -webkit-touch-callout: none;
            touch-action: manipulation;
        }

        body {
            background: linear-gradient(160deg, #fce4ec 0%, #f8d5e4 15%, #f3e5f5 35%, #fce4f0 55%, #e8d5f5 75%, #fce4ec 100%);
            background-size: 400% 400%;
            animation: bgShift 18s ease-in-out infinite;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            overflow: hidden;
            min-height: 100dvh;
            height: 100dvh;
        }

        @keyframes bgShift {
            0%,
            100% {
                background-position: 0% 50%;
            }
            25% {
                background-position: 100% 0%;
            }
            50% {
                background-position: 100% 100%;
            }
            75% {
                background-position: 0% 100%;
            }
        }

        /* Floating particles layer */
        .particles-layer {
            position: fixed;
            inset: 0;
            pointer-events: none;
            z-index: 0;
        }

        .floating-emoji {
            position: absolute;
            font-size: clamp(20px, 5vw, 36px);
            animation: floatUp var(--dur) var(--delay) linear infinite;
            opacity: 0;
            will-change: transform, opacity;
            filter: drop-shadow(0 2px 6px rgba(255, 150, 180, 0.35));
        }

        @keyframes floatUp {
            0% {
                transform: translateY(105vh) translateX(var(--drift-start)) rotate(0deg) scale(0.6);
                opacity: 0;
            }
            8% {
                opacity: var(--peak-opacity, 0.85);
                transform: translateY(88vh) translateX(calc(var(--drift-start) * 0.7)) rotate(15deg) scale(1);
            }
            40% {
                opacity: var(--peak-opacity, 0.85);
                transform: translateY(40vh) translateX(var(--drift-mid)) rotate(120deg) scale(1.05);
            }
            75% {
                opacity: 0.55;
                transform: translateY(10vh) translateX(var(--drift-end)) rotate(280deg) scale(0.85);
            }
            100% {
                transform: translateY(-8vh) translateX(var(--drift-end)) rotate(360deg) scale(0.4);
                opacity: 0;
            }
        }

        /* Sparkle burst dots */
        .sparkle-dot {
            position: absolute;
            width: clamp(3px, 1vw, 6px);
            height: clamp(3px, 1vw, 6px);
            border-radius: 50%;
            background: var(--gold);
            animation: sparkleFloat var(--dur) var(--delay) linear infinite;
            opacity: 0;
            will-change: transform, opacity;
            box-shadow: 0 0 6px 2px rgba(255, 215, 0, 0.7), 0 0 12px 4px rgba(255, 180, 200, 0.5);
        }

        @keyframes sparkleFloat {
            0% {
                transform: translateY(105vh) translateX(0);
                opacity: 0;
            }
            10% {
                opacity: 0.9;
            }
            35% {
                opacity: 0.9;
            }
            70% {
                opacity: 0.3;
            }
            100% {
                transform: translateY(-10vh) translateX(var(--drift));
                opacity: 0;
            }
        }

        /* Main card */
        .main-card {
            position: relative;
            z-index: 10;
            background: var(--card-bg);
            backdrop-filter: blur(24px);
            -webkit-backdrop-filter: blur(24px);
            border-radius: clamp(24px, 5vw, 36px);
            padding: clamp(28px, 5vw, 44px) clamp(20px, 4vw, 38px);
            box-shadow: var(--shadow-lg);
            text-align: center;
            max-width: 92vw;
            width: 400px;
            border: 2px solid rgba(255, 255, 255, 0.6);
            animation: cardEntry 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) both;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }

        @keyframes cardEntry {
            0% {
                transform: translateY(60px) scale(0.85);
                opacity: 0;
            }
            100% {
                transform: translateY(0) scale(1);
                opacity: 1;
            }
        }

        .main-card:active {
            transform: scale(0.97);
            box-shadow: var(--shadow);
        }

        /* Decorative ribbon-like top accent */
        .card-accent {
            position: absolute;
            top: -3px;
            left: 50%;
            transform: translateX(-50%);
            width: 65%;
            height: 6px;
            border-radius: 8px;
            background: linear-gradient(90deg, #ff9ab5, #ff4088, #ff6b9d, #ff4088, #ff9ab5);
            animation: shimmer 2.5s ease-in-out infinite;
        }

        @keyframes shimmer {
            0%,
            100% {
                opacity: 0.85;
                filter: brightness(1);
            }
            50% {
                opacity: 1;
                filter: brightness(1.3);
            }
        }

        /* Title */
        .title {
            font-size: clamp(22px, 5.5vw, 32px);
            font-weight: 800;
            letter-spacing: 0.02em;
            background: linear-gradient(135deg, #e91e63, #c2185b, #e91e63);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            color: transparent;
            margin-bottom: 4px;
            animation: titleGlow 3s ease-in-out infinite;
        }

        @keyframes titleGlow {
            0%,
            100% {
                filter: drop-shadow(0 0 6px rgba(233, 30, 99, 0.3));
            }
            50% {
                filter: drop-shadow(0 0 16px rgba(233, 30, 99, 0.6));
            }
        }

        .subtitle {
            font-size: clamp(14px, 3.5vw, 18px);
            color: #b34e6b;
            font-weight: 500;
            margin-bottom: 16px;
            letter-spacing: 0.04em;
        }

        .pony-row {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 8px;
            margin-bottom: 14px;
            font-size: clamp(36px, 9vw, 52px);
            animation: ponyBounce 2s ease-in-out infinite;
        }

        @keyframes ponyBounce {
            0%,
            100% {
                transform: translateY(0);
            }
            30% {
                transform: translateY(-16px);
            }
            50% {
                transform: translateY(0);
            }
            70% {
                transform: translateY(-8px);
            }
            85% {
                transform: translateY(0);
            }
        }

        .pony-row span {
            display: inline-block;
            animation: ponyWiggle 0.6s ease-in-out infinite;
            animation-delay: var(--wiggle-delay, 0s);
            filter: drop-shadow(0 4px 10px rgba(255, 150, 190, 0.5));
        }

        @keyframes ponyWiggle {
            0%,
            100% {
                transform: rotate(0deg);
            }
            25% {
                transform: rotate(8deg);
            }
            75% {
                transform: rotate(-8deg);
            }
        }

        /* Lipstick decorative */
        .lipstick-decor {
            font-size: clamp(28px, 7vw, 42px);
            margin-bottom: 10px;
            animation: lipPop 2.5s ease-in-out infinite;
            filter: drop-shadow(0 3px 8px rgba(255, 100, 130, 0.5));
        }

        @keyframes lipPop {
            0%,
            100% {
                transform: scale(1) rotate(0deg);
            }
            15% {
                transform: scale(1.2) rotate(-5deg);
            }
            30% {
                transform: scale(1) rotate(0deg);
            }
            45% {
                transform: scale(1.15) rotate(5deg);
            }
            60% {
                transform: scale(1) rotate(0deg);
            }
        }

        /* THE BUTTON */
        .btn-reveal {
            display: inline-block;
            position: relative;
            padding: clamp(15px, 3.5vw, 20px) clamp(32px, 7vw, 48px);
            font-size: clamp(16px, 3.8vw, 20px);
            font-weight: 700;
            letter-spacing: 0.04em;
            color: #fff;
            background: linear-gradient(135deg, #ff4088 0%, #ff1a6c 40%, #ff4088 70%, #ff6090 100%);
            background-size: 300% 300%;
            border: none;
            border-radius: 60px;
            cursor: pointer;
            box-shadow: 0 8px 30px rgba(255, 64, 136, 0.45), 0 0 0 0 rgba(255, 64, 136, 0.5);
            animation: btnPulse 2.2s ease-in-out infinite, btnShimmer 3s ease infinite;
            transition: transform 0.15s ease, box-shadow 0.15s ease;
            -webkit-tap-highlight-color: transparent;
            touch-action: manipulation;
            outline: none;
            z-index: 1;
        }

        @keyframes btnPulse {
            0%,
            100% {
                box-shadow: 0 8px 30px rgba(255, 64, 136, 0.45), 0 0 0 0 rgba(255, 64, 136, 0.5);
            }
            50% {
                box-shadow: 0 8px 30px rgba(255, 64, 136, 0.45), 0 0 0 18px rgba(255, 64, 136, 0);
            }
        }

        @keyframes btnShimmer {
            0%,
            100% {
                background-position: 0% 50%;
            }
            50% {
                background-position: 100% 50%;
            }
        }

        .btn-reveal:active {
            transform: scale(0.9);
            box-shadow: 0 4px 15px rgba(255, 64, 136, 0.6);
            transition: transform 0.08s ease, box-shadow 0.08s ease;
        }

        .btn-reveal::after {
            content: '';
            position: absolute;
            inset: -3px;
            border-radius: 63px;
            background: linear-gradient(135deg, #ff9ab5, #ffd700, #ff9ab5);
            z-index: -1;
            opacity: 0;
            animation: borderGlow 2.5s ease-in-out infinite;
            filter: blur(4px);
        }

        @keyframes borderGlow {
            0%,
            100% {
                opacity: 0;
            }
            50% {
                opacity: 0.5;
            }
        }

        .btn-emoji {
            display: inline-block;
            animation: btnEmojiBounce 0.7s ease-in-out infinite;
            animation-delay: 0.1s;
        }
        @keyframes btnEmojiBounce {
            0%,
            100% {
                transform: translateY(0);
            }
            50% {
                transform: translateY(-6px);
            }
        }

        /* MODAL OVERLAY */
        .modal-overlay {
            position: fixed;
            inset: 0;
            z-index: 100;
            background: rgba(30, 10, 20, 0.55);
            backdrop-filter: blur(8px);
            -webkit-backdrop-filter: blur(8px);
            display: flex;
            align-items: center;
            justify-content: center;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.35s ease;
            padding: 16px;
        }

        .modal-overlay.active {
            opacity: 1;
            pointer-events: auto;
        }

        /* MODAL CARD */
        .modal-card {
            background: #fffdfd;
            border-radius: clamp(22px, 5vw, 30px);
            padding: clamp(24px, 5vw, 36px) clamp(18px, 4vw, 28px);
            max-width: 94vw;
            width: 420px;
            text-align: center;
            position: relative;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25), 0 0 80px rgba(255, 130, 160, 0.3);
            transform: scale(0.5) translateY(40px);
            transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
            border: 2.5px solid rgba(255, 180, 200, 0.5);
            overflow: visible;
        }

        .modal-overlay.active .modal-card {
            transform: scale(1) translateY(0);
        }

        /* Confetti burst inside modal */
        .modal-confetti {
            position: absolute;
            inset: 0;
            pointer-events: none;
            overflow: visible;
            z-index: 0;
        }

        .confetti-piece {
            position: absolute;
            width: clamp(6px, 2vw, 10px);
            height: clamp(6px, 2vw, 10px);
            border-radius: 3px;
            opacity: 0;
            animation: confettiBurst 1.2s var(--c-delay, 0s) ease-out forwards;
            will-change: transform, opacity;
        }

        @keyframes confettiBurst {
            0% {
                transform: translate(0, 0) rotate(0deg) scale(0);
                opacity: 1;
            }
            60% {
                opacity: 1;
            }
            100% {
                transform: translate(var(--cx), var(--cy)) rotate(var(--cr)) scale(1.2);
                opacity: 0;
            }
        }

        .modal-emoji-top {
            font-size: clamp(42px, 10vw, 56px);
            margin-bottom: 8px;
            animation: modalEmojiPop 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) both;
            animation-delay: 0.25s;
            filter: drop-shadow(0 4px 12px rgba(255, 150, 180, 0.6));
            position: relative;
            z-index: 1;
        }

        @keyframes modalEmojiPop {
            0% {
                transform: scale(0) rotate(-30deg);
                opacity: 0;
            }
            100% {
                transform: scale(1) rotate(0deg);
                opacity: 1;
            }
        }

        .modal-title {
            font-size: clamp(20px, 5vw, 26px);
            font-weight: 800;
            color: #c2185b;
            margin-bottom: 10px;
            position: relative;
            z-index: 1;
            letter-spacing: 0.03em;
        }

        .modal-message {
            font-size: clamp(14px, 3.4vw, 17px);
            color: #4a2035;
            line-height: 1.65;
            font-weight: 500;
            position: relative;
            z-index: 1;
            padding: 0 6px;
        }

        .modal-message .highlight {
            color: #e91e63;
            font-weight: 700;
        }

        .modal-close {
            display: inline-block;
            margin-top: 18px;
            padding: 10px 28px;
            font-size: clamp(14px, 3.2vw, 16px);
            font-weight: 600;
            color: #fff;
            background: linear-gradient(135deg, #ff6090, #e91e63);
            border: none;
            border-radius: 50px;
            cursor: pointer;
            position: relative;
            z-index: 1;
            letter-spacing: 0.03em;
            box-shadow: 0 6px 20px rgba(255, 64, 136, 0.35);
            transition: transform 0.15s ease, box-shadow 0.15s ease;
            -webkit-tap-highlight-color: transparent;
        }
        .modal-close:active {
            transform: scale(0.9);
            box-shadow: 0 3px 10px rgba(255, 64, 136, 0.5);
        }

        /* Responsive tweaks */
        @media (max-width: 380px) {
            .main-card {
                padding: 20px 14px;
                border-radius: 20px;
            }
            .btn-reveal {
                padding: 14px 28px;
                font-size: 15px;
            }
            .modal-card {
                padding: 18px 14px;
                border-radius: 18px;
            }
            .floating-emoji {
                font-size: 18px;
            }
        }

        @media (min-width: 768px) {
            .main-card {
                width: 440px;
            }
            .modal-card {
                width: 460px;
            }
        }

        /* Accessibility: reduced motion */
        @media (prefers-reduced-motion: reduce) {
            .floating-emoji,
            .sparkle-dot,
            .confetti-piece {
                animation-duration: 0.01s !important;
            }
            .btn-reveal {
                animation: none;
            }
            .modal-card {
                transition: transform 0.2s ease;
            }
        }
    </style>
</head>
<body>

    <!-- Audio element with Base64 source (generated dynamically) -->
    <audio id="bg-audio" loop preload="auto" playsinline></audio>

    <!-- Floating particles -->
    <div class="particles-layer" id="particlesLayer" aria-hidden="true"></div>

    <!-- Sparkle dots -->
    <div class="particles-layer" id="sparklesLayer" aria-hidden="true"></div>

    <!-- MAIN CARD -->
    <div class="main-card" id="mainCard">
        <div class="card-accent"></div>
        <div class="lipstick-decor">💄✨💋✨💄</div>
        <div class="pony-row">
            <span style="--wiggle-delay:0s;">🦄</span>
            <span style="--wiggle-delay:0.2s;">🌸</span>
            <span style="--wiggle-delay:0.4s;">🦄</span>
        </div>
        <h1 class="title">С днём рождения!</h1>
        <p class="subtitle">Полина, этот день — твой! 💅</p>
        <button class="btn-reveal" id="btnReveal" aria-label="Открыть поздравление">
            <span class="btn-emoji">🎀</span> НАЖМИ СЮДА <span class="btn-emoji">🎀</span>
        </button>
        <div style="margin-top:10px;font-size:clamp(20px,5vw,30px);opacity:0.7;">💖🦄💖</div>
    </div>

    <!-- MODAL -->
    <div class="modal-overlay" id="modalOverlay" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
        <div class="modal-card" id="modalCard">
            <div class="modal-confetti" id="modalConfetti" aria-hidden="true"></div>
            <div class="modal-emoji-top">🦄💖🎉</div>
            <h2 class="modal-title" id="modalTitle">Полина, ты — легенда! ✨</h2>
            <p class="modal-message" id="modalMessage">
                С днём рождения, <span class="highlight">Полина</span>! 💅<br><br>
                Ты настоящая <span class="highlight">имба</span> — стильная, яркая и неповторимая! Твой вайб всегда на высоте, а улыбка способна зажечь любую комнату 🔥<br><br>
                Желаю, чтобы жизнь была как любимый плейлист — только <span class="highlight">хиты</span>, а каждый день приносил новые поводы для счастья. Пусть учёба не бесит, друзья будут <span class="highlight">топовыми</span>, а мечты сбываются быстрее, чем загружается любимая игра 🎮✨<br><br>
                Оставайся собой — <span class="highlight">уникальной, крутой и настоящей</span>! И пусть в твоей жизни всегда будет место для волшебства и маленьких радостей 🦄💖<br><br>
                <span style="font-size:1.3em;">💋 С любовью и обнимашками! 💋</span>
            </p>
            <button class="modal-close" id="modalClose" aria-label="Закрыть">💖 Закрыть 💖</button>
        </div>
    </div>

    <script>
        (function() {
            // ──────────────────────────────────────
            // 1. FLOATING EMOJI PARTICLES
            // ──────────────────────────────────────
            const particlesLayer = document.getElementById('particlesLayer');
            const emojis = ['🦄', '💖', '⭐', '✨', '💄', '💋', '🌸', '🎀', '💕', '🩷', '🌟', '💝', '🦄', '💖', '✨', '💄',
                '🌸', '🎀', '💋', '💕', '🦄', '⭐', '💖', '✨', '💄'
            ];
            const emojiFrag = document.createDocumentFragment();

            emojis.forEach((emoji, i) => {
                const el = document.createElement('span');
                el.className = 'floating-emoji';
                el.textContent = emoji;
                el.setAttribute('aria-hidden', 'true');
                const dur = 9 + Math.random() * 16; // 9-25 seconds
                const delay = Math.random() * 18;
                const driftStart = (Math.random() - 0.5) * 50;
                const driftMid = (Math.random() - 0.5) * 80;
                const driftEnd = (Math.random() - 0.5) * 60;
                const peakOpacity = 0.5 + Math.random() * 0.45;
                const leftPos = 2 + Math.random() * 92;
                el.style.cssText = `
                    --dur: ${dur}s;
                    --delay: -${delay}s;
                    --drift-start: ${driftStart}px;
                    --drift-mid: ${driftMid}px;
                    --drift-end: ${driftEnd}px;
                    --peak-opacity: ${peakOpacity};
                    left: ${leftPos}%;
                    bottom: -10%;
                `;
                emojiFrag.appendChild(el);
            });
            particlesLayer.appendChild(emojiFrag);

            // ──────────────────────────────────────
            // 2. SPARKLE DOTS
            // ──────────────────────────────────────
            const sparklesLayer = document.getElementById('sparklesLayer');
            const sparkleFrag = document.createDocumentFragment();
            const sparkleColors = ['#ffd700', '#ffb3c6', '#ff9ab5', '#fff', '#ffd1e0', '#ffe0ec', '#ffc0cb',
            '#ff4088'];

            for (let i = 0; i < 30; i++) {
                const dot = document.createElement('div');
                dot.className = 'sparkle-dot';
                dot.setAttribute('aria-hidden', 'true');
                const dur = 4 + Math.random() * 10;
                const delay = Math.random() * 12;
                const drift = (Math.random() - 0.5) * 40;
                const leftPos = 3 + Math.random() * 94;
                const color = sparkleColors[Math.floor(Math.random() * sparkleColors.length)];
                dot.style.cssText = `
                    --dur: ${dur}s;
                    --delay: -${delay}s;
                    --drift: ${drift}px;
                    left: ${leftPos}%;
                    bottom: -6%;
                    background: ${color};
                    width: ${2 + Math.random()*4}px;
                    height: ${2 + Math.random()*4}px;
                    box-shadow: 0 0 ${4+Math.random()*8}px ${2+Math.random()*4}px ${color}44;
                `;
                sparkleFrag.appendChild(dot);
            }
            sparklesLayer.appendChild(sparkleFrag);

            // ──────────────────────────────────────
            // 3. MODAL LOGIC
            // ──────────────────────────────────────
            const btnReveal = document.getElementById('btnReveal');
            const modalOverlay = document.getElementById('modalOverlay');
            const modalCard = document.getElementById('modalCard');
            const modalClose = document.getElementById('modalClose');
            const modalConfetti = document.getElementById('modalConfetti');
            const bgAudio = document.getElementById('bg-audio');
            let audioStarted = false;
            let audioContext = null;
            let chiptuneInterval = null;

            // Generate confetti inside modal
            function spawnConfetti() {
                modalConfetti.innerHTML = '';
                const frag = document.createDocumentFragment();
                const confettiColors = [
                    '#ff4088', '#ff6b9d', '#ffb3c6', '#ffd700', '#ffe0ec',
                    '#e91e63', '#ff9ab5', '#ffc0cb', '#ffd1e0', '#fff',
                    '#f8bbd0', '#ff6090', '#ffd54f', '#ff80ab'
                ];
                for (let i = 0; i < 55; i++) {
                    const piece = document.createElement('div');
                    piece.className = 'confetti-piece';
                    const cx = (Math.random() - 0.5) * 380;
                    const cy = -(60 + Math.random() * 340);
                    const cr = (Math.random() - 0.5) * 720;
                    const cDelay = Math.random() * 0.45;
                    const color = confettiColors[Math.floor(Math.random() * confettiColors.length)];
                    const size = 5 + Math.random() * 10;
                    piece.style.cssText = `
                        --cx: ${cx}px;
                        --cy: ${cy}px;
                        --cr: ${cr}deg;
                        --c-delay: ${cDelay}s;
                        background: ${color};
                        width: ${size}px;
                        height: ${size}px;
                        border-radius: ${Math.random() > 0.5 ? '50%' : '2px'};
                        left: 50%;
                        top: 50%;
                    `;
                    frag.appendChild(piece);
                }
                modalConfetti.appendChild(frag);
            }

            function openModal() {
                spawnConfetti();
                modalOverlay.classList.add('active');
                // Re-trigger confetti animation
                modalConfetti.querySelectorAll('.confetti-piece').forEach(p => {
                    p.style.animation = 'none';
                    p.offsetHeight;
                    p.style.animation = '';
                });
                // Also re-trigger emoji pop
                const emojiTop = modalCard.querySelector('.modal-emoji-top');
                if (emojiTop) {
                    emojiTop.style.animation = 'none';
                    emojiTop.offsetHeight;
                    emojiTop.style.animation = '';
                }
                document.body.style.overflow = 'hidden';
            }

            function closeModal() {
                modalOverlay.classList.remove('active');
                document.body.style.overflow = '';
            }

            btnReveal.addEventListener('click', (e) => {
                e.preventDefault();
                // Start audio on first interaction
                if (!audioStarted) {
                    startAllAudio();
                    audioStarted = true;
                }
                // Play a short "ding" via Web Audio
                playDingSound();
                openModal();
            });

            modalClose.addEventListener('click', (e) => {
                e.preventDefault();
                closeModal();
            });

            modalOverlay.addEventListener('click', (e) => {
                if (e.target === modalOverlay) {
                    closeModal();
                }
            });

            // Close on Escape key
            document.addEventListener('keydown', (e) => {
                if (e.key === 'Escape' && modalOverlay.classList.contains('active')) {
                    closeModal();
                }
            });

            // ──────────────────────────────────────
            // 4. AUDIO - Web Audio API 8-bit chiptune
            // ──────────────────────────────────────
            function startAllAudio() {
                try {
                    // Initialize Web Audio chiptune
                    initChiptune();
                    // Also attempt to play the Base64 audio element
                    const playPromise = bgAudio.play();
                    if (playPromise && playPromise.catch) {
                        playPromise.catch(() => {
                            // Autoplay blocked, that's ok - Web Audio will handle it
                        });
                    }
                } catch (e) {
                    // Silently fail
                }
            }

            function initChiptune() {
                try {
                    audioContext = new(window.AudioContext || window.webkitAudioContext)();
                } catch (e) {
                    return;
                }

                // Chiptune melody notes (frequencies in Hz)
                const melodyNotes = [
                    261.63, 329.63, 392.00, 523.25, // C4 E4 G4 C5
                    493.88, 440.00, 392.00, 329.63, // B4 A4 G4 E4
                    349.23, 392.00, 440.00, 523.25, // F4 G4 A4 C5
                    493.88, 523.25, 587.33, 659.25, // B4 C5 D5 E5
                    523.25, 493.88, 440.00, 392.00, // C5 B4 A4 G4
                    349.23, 329.63, 293.66, 261.63, // F4 E4 D4 C4
                ];

                const bassNotes = [
                    130.81, 130.81, 164.81, 164.81, // C3 C3 E3 E3
                    146.83, 146.83, 130.81, 130.81, // D3 D3 C3 C3
                    174.61, 174.61, 164.81, 164.81, // F3 F3 E3 E3
                    146.83, 146.83, 130.81, 130.81, // D3 D3 C3 C3
                ];

                const noteDuration = 0.16; // seconds per note (≈150 BPM eighth notes)
                const totalNotes = melodyNotes.length;
                const loopDuration = totalNotes * noteDuration;

                let noteIndex = 0;
                let lastNoteTime = 0;

                function scheduleNotes() {
                    if (!audioContext || audioContext.state === 'closed') return;
                    const now = audioContext.currentTime;
                    const scheduleAhead = 0.3;

                    while (lastNoteTime < now + scheduleAhead) {
                        const noteStartTime = lastNoteTime;
                        const idx = noteIndex % totalNotes;

                        // Melody (square wave)
                        const melOsc = audioContext.createOscillator();
                        const melGain = audioContext.createGain();
                        melOsc.type = 'square';
                        melOsc.frequency.value = melodyNotes[idx];
                        melGain.gain.setValueAtTime(0.09, noteStartTime);
                        melGain.gain.exponentialRampToValueAtTime(0.001, noteStartTime + noteDuration * 0.75);
                        melOsc.connect(melGain);
                        melGain.connect(audioContext.destination);
                        melOsc.start(noteStartTime);
                        melOsc.stop(noteStartTime + noteDuration * 0.8);

                        // Bass (square wave, lower)
                        const bassOsc = audioContext.createOscillator();
                        const bassGain = audioContext.createGain();
                        bassOsc.type = 'square';
                        bassOsc.frequency.value = bassNotes[idx] || 130.81;
                        bassGain.gain.setValueAtTime(0.05, noteStartTime);
                        bassGain.gain.exponentialRampToValueAtTime(0.001, noteStartTime + noteDuration * 0.7);
                        bassOsc.connect(bassGain);
                        bassGain.connect(audioContext.destination);
                        bassOsc.start(noteStartTime);
                        bassOsc.stop(noteStartTime + noteDuration * 0.75);

                        // Hi-hat tick (noise burst)
                        if (idx % 2 === 0) {
                            const noiseBuffer = audioContext.createBuffer(1, Math.floor(audioContext.sampleRate * 0.03),
                                audioContext.sampleRate);
                            const noiseData = noiseBuffer.getChannelData(0);
                            for (let i = 0; i < noiseData.length; i++) {
                                noiseData[i] = (Math.random() * 2 - 1) * 0.08;
                            }
                            const noiseSource = audioContext.createBufferSource();
                            noiseSource.buffer = noiseBuffer;
                            const noiseGain = audioContext.createGain();
                            noiseGain.gain.setValueAtTime(0.06, noteStartTime);
                            noiseGain.gain.exponentialRampToValueAtTime(0.001, noteStartTime + 0.025);
                            noiseSource.connect(noiseGain);
                            noiseGain.connect(audioContext.destination);
                            noiseSource.start(noteStartTime);
                            noiseSource.stop(noteStartTime + 0.03);
                        }

                        noteIndex++;
                        lastNoteTime = noteStartTime + noteDuration;
                    }

                    // Loop: reset index when we've played all notes
                    if (noteIndex >= totalNotes) {
                        noteIndex = 0;
                        lastNoteTime = Math.max(lastNoteTime, audioContext.currentTime);
                    }
                }

                // Start scheduling
                lastNoteTime = audioContext.currentTime;
                scheduleNotes();
                chiptuneInterval = setInterval(() => {
                    if (audioContext && audioContext.state !== 'closed') {
                        scheduleNotes();
                    } else {
                        clearInterval(chiptuneInterval);
                    }
                }, 200);
            }

            function playDingSound() {
                if (!audioContext || audioContext.state === 'closed') {
                    try {
                        audioContext = new(window.AudioContext || window.webkitAudioContext)();
                    } catch (e) {
                        return;
                    }
                }
                const now = audioContext.currentTime;
                const dingFreqs = [587.33, 783.99, 1046.5]; // D5 G5 C6
                dingFreqs.forEach((freq, i) => {
                    const osc = audioContext.createOscillator();
                    const gain = audioContext.createGain();
                    osc.type = 'square';
                    osc.frequency.value = freq;
                    const t = now + i * 0.08;
                    gain.gain.setValueAtTime(0.12, t);
                    gain.gain.exponentialRampToValueAtTime(0.001, t + 0.14);
                    osc.connect(gain);
                    gain.connect(audioContext.destination);
                    osc.start(t);
                    osc.stop(t + 0.16);
                });
            }

            // ──────────────────────────────────────
            // 5. GENERATE BASE64 WAV FOR <AUDIO> TAG
            // ──────────────────────────────────────
            function generateWavBase64() {
                const sampleRate = 8000;
                const duration = 2.2;
                const numSamples = Math.floor(sampleRate * duration);
                const samples = new Uint8Array(numSamples);

                // Simple cheerful melody: sequence of note frequencies
                const noteSeq = [
                    { freq: 523.25, dur: 0.2 },
                    { freq: 659.25, dur: 0.2 },
                    { freq: 783.99, dur: 0.2 },
                    { freq: 1046.5, dur: 0.3 },
                    { freq: 987.77, dur: 0.2 },
                    { freq: 880.00, dur: 0.2 },
                    { freq: 783.99, dur: 0.2 },
                    { freq: 1046.5, dur: 0.35 },
                    { freq: 1174.7, dur: 0.2 },
                    { freq: 1046.5, dur: 0.25 },
                ];

                let sampleIdx = 0;
                for (const note of noteSeq) {
                    const noteSamples = Math.floor(note.dur * sampleRate);
                    for (let i = 0; i < noteSamples && sampleIdx < numSamples; i++, sampleIdx++) {
                        const t = i / sampleRate;
                        const phase = (t * note.freq) % 1;
                        // Square wave
                        const raw = phase < 0.5 ? 0.7 : -0.7;
                        // Apply slight decay within note
                        const env = Math.max(0, 1 - (i / noteSamples) * 0.35);
                        const val = raw * env;
                        // Convert to unsigned 8-bit (0-255, center 128)
                        samples[sampleIdx] = Math.round(128 + val * 70);
                    }
                }
                // Fill remaining with near-silence
                for (; sampleIdx < numSamples; sampleIdx++) {
                    samples[sampleIdx] = 128 + Math.round((Math.random() - 0.5) * 2);
                }

                // Build WAV file
                const dataSize = numSamples;
                const fileSize = 44 + dataSize;
                const buffer = new ArrayBuffer(fileSize);
                const view = new DataView(buffer);

                function writeStr(offset, str) {
                    for (let i = 0; i < str.length; i++) {
                        view.setUint8(offset + i, str.charCodeAt(i));
                    }
                }

                writeStr(0, 'RIFF');
                view.setUint32(4, fileSize - 8, true);
                writeStr(8, 'WAVE');
                writeStr(12, 'fmt ');
                view.setUint32(16, 16, true); // fmt chunk size
                view.setUint16(20, 1, true); // PCM format
                view.setUint16(22, 1, true); // mono
                view.setUint32(24, sampleRate, true);
                view.setUint32(28, sampleRate * 1, true); // byte rate
                view.setUint16(32, 1, true); // block align
                view.setUint16(34, 8, true); // bits per sample
                writeStr(36, 'data');
                view.setUint32(40, dataSize, true);

                // Write samples
                const sampleView = new Uint8Array(buffer, 44, dataSize);
                sampleView.set(samples);

                // Convert to Base64
                const bytes = new Uint8Array(buffer);
                let binary = '';
                for (let i = 0; i < bytes.length; i++) {
                    binary += String.fromCharCode(bytes[i]);
                }
                return btoa(binary);
            }

            // Set the audio source
            try {
                const base64Wav = generateWavBase64();
                bgAudio.src = 'data:audio/wav;base64,' + base64Wav;
                bgAudio.volume = 0.5;
            } catch (e) {
                // Fallback: audio element won't have Base64 but Web Audio will still work
                bgAudio.src = '';
            }

            // ──────────────────────────────────────
            // 6. ATTEMPT AUTOPLAY ON FIRST TOUCH
            // ──────────────────────────────────────
            function attemptAutoplayOnInteraction() {
                if (!audioStarted) {
                    startAllAudio();
                    audioStarted = true;
                }
            }

            // Listen for any user interaction to start audio
            const interactionEvents = ['touchstart', 'touchend', 'click', 'pointerdown'];
            interactionEvents.forEach(evtName => {
                document.addEventListener(evtName, attemptAutoplayOnInteraction, { once: false,
                passive: true });
            });

            // Clean up the extra listeners after first activation
            let interactionListenerRemoved = false;

            function removeInteractionListeners() {
                if (interactionListenerRemoved) return;
                interactionListenerRemoved = true;
                interactionEvents.forEach(evtName => {
                    document.removeEventListener(evtName, attemptAutoplayOnInteraction);
                });
            }
            // Override startAllAudio to also remove listeners
            const originalStartAllAudio = startAllAudio;
            startAllAudio = function() {
                originalStartAllAudio();
                removeInteractionListeners();
            };

            // ──────────────────────────────────────
            // 7. HANDLE PAGE VISIBILITY / BLUR
            // ──────────────────────────────────────
            document.addEventListener('visibilitychange', () => {
                if (document.hidden && chiptuneInterval) {
                    clearInterval(chiptuneInterval);
                    chiptuneInterval = null;
                } else if (!document.hidden && audioStarted && !chiptuneInterval) {
                    if (audioContext && audioContext.state !== 'closed') {
                        lastNoteTime = audioContext.currentTime;
                        scheduleNotes();
                        chiptuneInterval = setInterval(() => {
                            if (audioContext && audioContext.state !== 'closed') {
                                scheduleNotes();
                            } else {
                                clearInterval(chiptuneInterval);
                            }
                        }, 200);
                    }
                }
            });

            // Fix: make scheduleNotes accessible in the closure
            let lastNoteTime = 0;

            function scheduleNotes() {
                if (!audioContext || audioContext.state === 'closed') return;
                const now = audioContext.currentTime;
                const scheduleAhead = 0.3;
                const melodyNotes = [
                    261.63, 329.63, 392.00, 523.25,
                    493.88, 440.00, 392.00, 329.63,
                    349.23, 392.00, 440.00, 523.25,
                    493.88, 523.25, 587.33, 659.25,
                    523.25, 493.88, 440.00, 392.00,
                    349.23, 329.63, 293.66, 261.63,
                ];
                const bassNotes = [
                    130.81, 130.81, 164.81, 164.81,
                    146.83, 146.83, 130.81, 130.81,
                    174.61, 174.61, 164.81, 164.81,
                    146.83, 146.83, 130.81, 130.81,
                ];
                const noteDuration = 0.16;
                const totalNotes = melodyNotes.length;
                let noteIndex = 0;
                // Recalculate noteIndex from lastNoteTime
                const elapsedSinceStart = Math.max(0, lastNoteTime - (audioContext.currentTime - scheduleAhead -
                    0.5));
                noteIndex = Math.floor(elapsedSinceStart / noteDuration) % totalNotes;
                if (noteIndex < 0) noteIndex = 0;

                while (lastNoteTime < now + scheduleAhead) {
                    const noteStartTime = lastNoteTime;
                    const idx = noteIndex % totalNotes;

                    const melOsc = audioContext.createOscillator();
                    const melGain = audioContext.createGain();
                    melOsc.type = 'square';
                    melOsc.frequency.value = melodyNotes[idx];
                    melGain.gain.setValueAtTime(0.09, noteStartTime);
                    melGain.gain.exponentialRampToValueAtTime(0.001, noteStartTime + noteDuration * 0.75);
                    melOsc.connect(melGain);
                    melGain.connect(audioContext.destination);
                    melOsc.start(noteStartTime);
                    melOsc.stop(noteStartTime + noteDuration * 0.8);

                    const bassOsc = audioContext.createOscillator();
                    const bassGain = audioContext.createGain();
                    bassOsc.type = 'square';
                    bassOsc.frequency.value = bassNotes[idx] || 130.81;
                    bassGain.gain.setValueAtTime(0.05, noteStartTime);
                    bassGain.gain.exponentialRampToValueAtTime(0.001, noteStartTime + noteDuration * 0.7);
                    bassOsc.connect(bassGain);
                    bassGain.connect(audioContext.destination);
                    bassOsc.start(noteStartTime);
                    bassOsc.stop(noteStartTime + noteDuration * 0.75);

                    if (idx % 2 === 0) {
                        const noiseBuffer = audioContext.createBuffer(1, Math.floor(audioContext.sampleRate * 0.03),
                            audioContext.sampleRate);
                        const noiseData = noiseBuffer.getChannelData(0);
                        for (let i = 0; i < noiseData.length; i++) {
                            noiseData[i] = (Math.random() * 2 - 1) * 0.08;
                        }
                        const noiseSource = audioContext.createBufferSource();
                        noiseSource.buffer = noiseBuffer;
                        const noiseGain = audioContext.createGain();
                        noiseGain.gain.setValueAtTime(0.06, noteStartTime);
                        noiseGain.gain.exponentialRampToValueAtTime(0.001, noteStartTime + 0.025);
                        noiseSource.connect(noiseGain);
                        noiseGain.connect(audioContext.destination);
                        noiseSource.start(noteStartTime);
                        noiseSource.stop(noteStartTime + 0.03);
                    }

                    noteIndex++;
                    lastNoteTime = noteStartTime + noteDuration;
                }
                if (noteIndex >= totalNotes) {
                    lastNoteTime = Math.max(lastNoteTime, audioContext.currentTime);
                }
            }

            // Re-bind scheduleNotes in initChiptune
            const origInitChiptune = initChiptune;
            initChiptune = function() {
                origInitChiptune();
                if (audioContext && audioContext.state !== 'closed') {
                    lastNoteTime = audioContext.currentTime;
                    scheduleNotes();
                    if (chiptuneInterval) clearInterval(chiptuneInterval);
                    chiptuneInterval = setInterval(() => {
                        if (audioContext && audioContext.state !== 'closed') {
                            scheduleNotes();
                        } else {
                            clearInterval(chiptuneInterval);
                            chiptuneInterval = null;
                        }
                    }, 200);
                }
            };

            console.log('🎀🦄 Сайт готов! С днём рождения, Полина! 💖✨');
            console.log('💋 Нажми на розовую кнопку, чтобы увидеть поздравление!');
            console.log('🎮 8-битная музыка запустится при первом касании экрана.');
        })();
    </script>
</body>
</html>