Full Code of hhaayykk/BlessedWizard for AI

main 3ee882c03c65 cached
11 files
141.4 KB
38.9k tokens
65 symbols
1 requests
Download .txt
Repository: hhaayykk/BlessedWizard
Branch: main
Commit: 3ee882c03c65
Files: 11
Total size: 141.4 KB

Directory structure:
gitextract_to00y2ya/

├── .gitattributes
├── .gitignore
├── README.md
├── config.js
├── index.html
├── main.js
├── main.py
├── promocodes.js
├── requirements.txt
├── spooky.m4a
└── style.css

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto


================================================
FILE: .gitignore
================================================
spooky.mp4


================================================
FILE: README.md
================================================
# 🧙‍♂️ Blessed Wizard

**Blessed Wizard** is a **Telegram Mini App slot machine game** combined with a **Python Telegram Bot** that launches the app, manages referrals, and processes payments.

⚠️ Gambling-style mechanics. **18+ only.** Ensure compliance with local laws and regulations.

---

Official website - blessedwizard.site
<img width="2091" height="899" alt="изображение" src="https://github.com/user-attachments/assets/15dc0eba-b6ed-4fb2-bb30-b863323a1a69" />


## Overview

- Telegram Mini App slot game
- Entry via Telegram Bot (`/start`)
- Referral system with bonuses
- Telegram Stars deposits
- Cryptocurrency withdrawals
- Firebase backend

---

## Features

- 🎰 5 reels / 20 paylines
- 📊 Configurable RTP (default 96%)
- 🔗 Referral system (`/start ref<user_id>`)
- 🎁 Promocodes & bonuses
- 💰 Telegram Stars payments
- 🔔 Withdrawal notifications via bot
- 🌍 TON / BTC / ETH / USDT withdrawals
- 📱 Mobile-first Mini App UI

---

## Architecture

Telegram Bot (Python) → Telegram Mini App (Web) → Firebase Firestore

---

## Tech Stack

WebApp: HTML, CSS, JavaScript, Telegram WebApp API  
Bot: Python 3, python-telegram-bot v20.7  
Backend: Firebase Firestore  

---

## Installation

git clone https://github.com/hhaayykk/BlessedWizard.git 
cd BlessedWizard

---

## Configuration

- config.js — Firebase credentials  
- main.js — Game logic and RTP  
- main.py — Bot token and Mini App URL  

---

## Usage

1. Open the Telegram bot  
2. Run /start  
3. Mini App launches  
4. Play slot machine  
5. Deposit via Telegram Stars  
6. Withdraw winnings  

---

## Deployment

- WebApp: Netlify / Vercel / GitHub Pages  
- Bot: python bot.py  
- Set Mini App URL via @BotFather  

---

## Security Notes

- Never commit real API keys  
- Validate withdrawals  
- Apply limits and anti-abuse checks  


================================================
FILE: config.js
================================================
// Firebase Configuration
export const firebaseConfig = {
  apiKey: "###",
  authDomain: "###",
  projectId: "###",
  storageBucket: "###",
  messagingSenderId: "###",
  appId: "###",
  measurementId: "###"
};


================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Blessed Wizard</title>
    <link rel="stylesheet" href="style.css">
    <script defer src="https://telegram.org/js/telegram-web-app.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <!-- Firebase SDK -->
    <script src="https://www.gstatic.com/firebasejs/10.14.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/10.14.1/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/10.14.1/firebase-firestore.js"></script>
</head>
<body>
    <!-- Unified Page Header -->
    <div class="page-header">
        <img src="images/logo 1.png" alt="Blessed Wizard" class="logo">
        <div class="wallet-balance" id="currentBalance">⭐ 0</div>
    </div>

    <div id="dimmedOverlay" class="dimmed-overlay"></div>
    <div id="resultOverlay" class="result-overlay">
        <span id="resultText" class="result-text"></span>
    </div>

    <!-- Game Container -->
    <div id="gameContainer" class="casino-container">
        <div class="info-panel">
            <div class="info-box">
                <h3>Bet</h3>
                <div class="value" id="betLevel">1</div>
            </div>
            <div class="info-box">
                <h3>Star Value</h3>
                <div class="value" id="coinValue">1.00</div>
            </div>
            <div class="info-box">
                <h3>Total Bet</h3>
                <div class="value" id="totalBet">20.00</div>
            </div>
        </div>
        <img src="images/valshebnik.png" class="character-image">
        <div class="slot-machine">
            <div class="slot-frame">
                <div class="reel-container"><div class="reel" id="reel1"></div></div>
                <div class="reel-container"><div class="reel" id="reel2"></div></div>
                <div class="reel-container"><div class="reel" id="reel3"></div></div>
                <div class="reel-container"><div class="reel" id="reel4"></div></div>
                <div class="reel-container"><div class="reel" id="reel5"></div></div>
            </div>
        </div>
        <div class="controls">
            <div class="right-controls">
                <button class="paytable-button button-table" id="paytableButton">Pay<br>Table</button>
            </div>
            <div class="btnCombo">
                <div class="left-controls">
                    <button class="control-button bet-settings-button button" id="betSettingsButton">
                        <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-suit-spade-fill" viewBox="0 0 16 16">
                            <path d="M7.184 11.246A3.5 3.5 0 0 1 1 9c0-1.602 1.14-2.633 2.66-4.008C4.986 3.792 6.602 2.33 8 0c1.398 2.33 3.014 3.792 4.34 4.992C13.86 6.367 15 7.398 15 9a3.5 3.5 0 0 1-6.184 2.246 20 20 0 0 0 1.582 2.907c.231.35-.02.847-.438.847H6.04c-.419 0-.67-.497-.438-.847a20 20 0 0 0 1.582-2.907"/>
                        </svg>
                        <p>Bet</p>
                    </button>
                    <button class="control-button auto-button button" id="autoButton">
                        <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 640 640">
                            <path d="M552 256L408 256C398.3 256 389.5 250.2 385.8 241.2C382.1 232.2 384.1 221.9 391 215L437.7 168.3C362.4 109.7 253.4 115 184.2 184.2C109.2 259.2 109.2 380.7 184.2 455.7C259.2 530.7 380.7 530.7 455.7 455.7C463.9 447.5 471.2 438.8 477.6 429.6C487.7 415.1 507.7 411.6 522.2 421.7C536.7 431.8 540.2 451.8 530.1 466.3C521.6 478.5 511.9 490.1 501 501C401 601 238.9 601 139 501C39.1 401 39 239 139 139C233.3 44.7 382.7 39.4 483.3 122.8L535 71C541.9 64.1 552.2 62.1 561.2 65.8C570.2 69.5 576 78.3 576 88L576 232C576 245.3 565.3 256 552 256z"/>
                        </svg>
                        <p>Auto</p>
                    </button>
                </div>
                <div class="centerright">
                    <button class="spin-button" id="spinButton">
                        <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 640 640">
                            <path d="M129.9 292.5C143.2 199.5 223.3 128 320 128C373 128 421 149.5 455.8 184.2C456 184.4 456.2 184.6 456.4 184.8L464 192L416.1 192C398.4 192 384.1 206.3 384.1 224C384.1 241.7 398.4 256 416.1 256L544.1 256C561.8 256 576.1 241.7 576.1 224L576.1 96C576.1 78.3 561.8 64 544.1 64C526.4 64 512.1 78.3 512.1 96L512.1 149.4L500.8 138.7C454.5 92.6 390.5 64 320 64C191 64 84.3 159.4 66.6 283.5C64.1 301 76.2 317.2 93.7 319.7C111.2 322.2 127.4 310 129.9 292.6zM573.4 356.5C575.9 339 563.7 322.8 546.3 320.3C528.9 317.8 512.6 330 510.1 347.4C496.8 440.4 416.7 511.9 320 511.9C267 511.9 219 490.4 184.2 455.7C184 455.5 183.8 455.3 183.6 455.1L176 447.9L223.9 447.9C241.6 447.9 255.9 433.6 255.9 415.9C255.9 398.2 241.6 383.9 223.9 383.9L96 384C87.5 384 79.3 387.4 73.3 393.5C67.3 399.6 63.9 407.7 64 416.3L65 543.3C65.1 561 79.6 575.2 97.3 575C115 574.8 129.2 560.4 129 542.7L128.6 491.2L139.3 501.3C185.6 547.4 249.5 576 320 576C449 576 555.7 480.6 573.4 356.5z"/>
                        </svg>
                    </button>
                </div>
            </div>
        </div>
        <div id="betSettingsModal" class="bet-settings-modal">
            <div class="bet-settings-row">
                <div class="bet-settings-label">Bet (Stars/Line)</div>
                <div class="adjust-group">
                    <button class="bet-adjust-button" id="decreaseBetLevel">−</button>
                    <div class="bet-settings-value" id="betLevelModal">1</div>
                    <button class="bet-adjust-button" id="increaseBetLevel">+</button>
                </div>
            </div>
            <div class="bet-settings-row">
                <div class="bet-settings-label">Star Value</div>
                <div class="adjust-group">
                    <button class="bet-adjust-button" id="decreaseCoinValue">−</button>
                    <div class="bet-settings-value" id="coinValueModal">1.00</div>
                    <button class="bet-adjust-button" id="increaseCoinValue">+</button>
                </div>
            </div>
            <div class="bet-settings-row">
                <div class="bet-settings-label">Total Bet</div>
                <div class="bet-settings-value" id="totalBetModal">20.00</div>
                <button class="bet-adjust-button max-bet-button" id="maxBetButton">Max</button>
            </div>
            <button class="ok-button" id="okButton">OK</button>
        </div>
        <div id="autoSettingsModal" class="auto-settings-modal">
            <button class="toggle-auto-spin" id="toggleAutoSpin">Enable Auto Spin</button>
            <div class="bet-settings-row disabled-setting" id="autoSpinsRow">
                <div class="bet-settings-label">Auto Spins</div>
                <div class="bet-settings-value" id="autoSpinsModal">5</div>
                <button class="bet-adjust-button" id="decreaseAutoSpins">−</button>
                <button class="bet-adjust-button" id="increaseAutoSpins">+</button>
            </div>
            <div class="bet-settings-row disabled-setting" id="quickSpinRow">
                <div class="bet-settings-label">Quick Spin</div>
                <input type="checkbox" id="quickSpinCheckbox">
            </div>
            <button class="ok-button" id="okAutoButton">CANCEL</button>
        </div>
        <div id="paytableModal" class="paytable-modal">
            <div class="paytable-content">
                <h3>Paytable</h3>
                <p>Wins are calculated across 20 paylines. Match 3, 4, or 5 symbols from the left reel.</p>
                <div class="paytable-item">
                    <img src="images/avelavokmagic.PNG">
                    <span>Loop: 5x - 37.5, 4x - 7.5, 3x - 3.75</span>
                </div>
                <div class="paytable-item">
                    <img src="images/ballmagic.png">
                    <span>Magic Ball: 5x - 25.0, 4x - 5.0, 3x - 2.5</span>
                </div>
                <div class="paytable-item">
                    <img src="images/bookmagic.png">
                    <span>Book: 5x - 20.0, 4x - 4.0, 3x - 2.0</span>
                </div>
                <div class="paytable-item">
                    <img src="images/hatmagic.png">
                    <span>Hat: 5x - 15.0, 4x - 3.0, 3x - 1.5</span>
                </div>
                <div class="paytable-item">
                    <img src="images/lightermagic.PNG">
                    <span>Lighter: 5x - 10.0, 4x - 2.0, 3x - 1.0</span>
                </div>
                <div class="paytable-item">
                    <img src="images/notemagic.png">
                    <span>Note: 5x - 7.5, 4x - 1.5, 3x - 0.75</span>
                </div>
                <div class="paytable-item">
                    <img src="images/poisonmagic.png">
                    <span>Poison: 5x - 5.0, 4x - 1.0, 3x - 0.5</span>
                </div>
                <p>Total Win = (Bet per line × Symbol Multiplier) × Number of lines.</p>
            </div>
            <button class="ok-button" id="okPaytableButton">OK</button>
        </div>
    </div>

    <!-- Leaders Container -->
    <div id="leadersContainer" class="leaders-container" style="display: none;">
        <div class="leaderboard-header">
            <h3 class="leaderboard-title">Leaderboard</h3>
            <div class="leaderboard-subtitle">October 2025</div>
        </div>
        <div class="leaderboard-podium">
            <div class="podium-item podium-second">
                <div class="podium-rank">🥈</div>
                <img src="images/Arabic.jpg" class="podium-avatar">
                <div class="podium-name">الأحمد</div>
                <div class="podium-score">⭐ 150 000</div>
                <div class="podium-base podium-base-second">2</div>
            </div>
            <div class="podium-item podium-first">
                <div class="podium-rank">🥇</div>
                <img src="images/David.png" class="podium-avatar podium-avatar-winner">
                <div class="podium-name">David</div>
                <div class="podium-score">⭐ 250 000</div>
                <div class="podium-base podium-base-first">1</div>
            </div>
            <div class="podium-item podium-third">
                <div class="podium-rank">🥉</div>
                <div class="podium-avatar">A</div>
                <div class="podium-name">A</div>
                <div class="podium-score">⭐ 100 000</div>
                <div class="podium-base podium-base-third">3</div>
            </div>
        </div>
        <div class="leaderboard-list">
            <div class="leaderboard-item">
                <div class="leaderboard-position">4</div>
                <div class="leaderboard-avatar">V</div>
                <div class="leaderboard-player">
                    <div class="leaderboard-name">Vladimir</div>
                    <div class="leaderboard-score">⭐ 75 000</div>
                </div>
            </div>
            <div class="leaderboard-item">
                <div class="leaderboard-position">5</div>
                <img src="images/Gold.jpg" class="leaderboard-avatar">
                <div class="leaderboard-player">
                    <div class="leaderboard-name">Golddd</div>
                    <div class="leaderboard-score">⭐ 50 000</div>
                </div>
            </div>
        </div>
        <div class="leaderboard-info">
            <i class="fas fa-info-circle"></i>
            <p>Leaderboard shows the top 5 players with the most spins last month. It resets monthly, and rewards are credited to your balance.</p>
        </div>
    </div>

    <!-- Wallet Container -->
    <div id="balanceContainer" class="balance-container" style="display: none;">
        <div class="wallet-divider"></div>
        <div class="deposit-withdraw-row">
            <button class="deposit-btn active" id="depositButton">Deposit</button>
            <button class="withdraw-btn" id="withdrawButton">Withdraw</button>
        </div>
        <!-- Content will be dynamically loaded -->
    </div>

    <!-- Friends Container -->
    <div id="friendsContainer" class="friends-container" style="display: none;">
        <div class="referral-header">
            <h3 class="referral-title">Invite Friends</h3>
            <div class="referral-subtitle">Earn 15 Stars per friend!</div>
        </div>
        <div class="referral-stats">
            <div class="referral-stat-box">
                <div class="stat-number" id="friendsInvited">0</div>
                <div class="stat-label">Friends Invited</div>
            </div>
            <div class="referral-stat-box">
                <div class="stat-number" id="totalEarned"><span style="font-size: 15px;">⭐</span> 0</div>
                <div class="stat-label">Total Earned</div>
            </div>
        </div>
        <div class="referral-link-section">
            <div class="referral-link-title">Your Referral Link</div>
            <div class="referral-link-container">
                <span class="referral-link-text" id="referralLink">https://t.me/BessedWizardBot?start=ref_USER123</span>
                <i class="fa-solid fa-copy copy-icon" onclick="window.copyText(this, document.getElementById('referralLink').textContent)"></i>
            </div>
        </div>
        <button class="share-button" id="shareButton"><i class="fas fa-share"></i> Share Link</button>
        <div class="referral-info-box">
            <i class="fas fa-info-circle"></i>
            <div>
                <div class="referral-info-title">How it works:</div>
                <ul class="referral-info-list">
                    <li>Share your unique referral link</li>
                    <li>Friend registers using your link</li>
                    <li>You get 15 Stars instantly!</li>
                    <li>No limit on referrals</li>
                </ul>
            </div>
        </div>
    </div>

    <!-- Profile Container -->
    <div id="profileContainer" class="profile-container" style="display: none;">
        <div class="profile-header">
            <img src="images/default_avatar.png" class="profile-avatar" id="profileAvatar">
            <div class="profile-info">
                <h3 id="profileName">User Name</h3>
                <p id="telegramId">Telegram ID: Not Set</p>
                <p id="registrationDate">Registered: Not Set</p>
            </div>
        </div>
        <div class="gameSettings">
            <div class="profile-section">
                <div class="profile-setting-row">
                    <div class="setting-label">
                        <i class="fas fa-music"></i>
                        <span>Music</span>
                    </div>
                    <button class="music-toggle-btn active" id="musicToggle">
                        <span class="music-status">ON</span>
                    </button>
                </div>
            </div>
            <div class="language-selector">
                <select id="languageSelect">
                    <option value="en">English</option>
                </select>
            </div>
        </div>
        <div class="promocode-section">
    <h3 class="promocode-title">
        <i class="fas fa-ticket-alt"></i> Promocode
    </h3>
    <div class="promocode-info">
        <i class="fas fa-info-circle"></i>
        <p>Enter a promocode to receive free Stars!</p>
    </div>
    <div class="promocode-input-container">
        <input 
            type="text" 
            class="promocode-input" 
            id="promocodeInput" 
            placeholder="Enter promocode"
            maxlength="20">
        <button class="promocode-submit" id="promocodeSubmit">
            <i class="fas fa-check"></i>
        </button>
    </div>
    <div class="promocode-error" id="promocodeError"></div>
</div>
        <a href="#" class="privacy-policy">Privacy Policy</a>
        <div style="user-select: all;" class="footer">
            <p>18+ only | Play responsibly | Terms apply</p>
            <p>Website: www.blessedwizard.site</p>
            <p>Support: <a href="https://t.me/BlessedWizardSupport">https://t.me/BlessedWizardSupport</a></p>
            <br>
            <hr>
            <img src="images/responsible_gaming.png">
        </div>
    </div>

    <!-- Navigation -->
    <div class="telegram-nav">
        <button class="telegram-nav-button" id="leadersButton"><i class="fas fa-trophy"></i> Leaders</button>
        <button class="telegram-nav-button" id="walletButton"><i class="fas fa-wallet"></i> Wallet</button>
        <button class="telegram-nav-button active" id="playButton"><i class="fas fa-play"></i> Play</button>
        <button class="telegram-nav-button" id="friendsButton"><i class="fas fa-users"></i> Referrals</button>
        <button class="telegram-nav-button" id="profileButton"><i class="fas fa-user"></i> Profile</button>
    </div>

    <script type="module" src="main.js"></script>
    <script type="module" src="config.js"></script>
    <script type="module" src="promocodes.js"></script>
</body>
</html>

================================================
FILE: main.js
================================================
import { firebaseConfig, TELEGRAM_BOT_TOKEN, TELEGRAM_GROUP_CHAT_ID, BOT_USERNAME } from './config.js';
import { PROMOCODES } from './promocodes.js'; // ← ADD THIS LINE
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-app.js';
import { getFirestore, doc, setDoc, getDoc, updateDoc, serverTimestamp } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-firestore.js';
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

// ===============================
// RTP System Configuration (Dog House Style)
// ===============================
const RTP_CONFIG = {
    TARGET_RTP: 96.0,
    MIN_RTP: 95.5,
    MAX_RTP: 96.5,
    BONUS_TRIGGER_CHANCE: 0.05,
    SMALL_WIN_MULTIPLIER_RANGE: [0.2, 0.8],
    MEDIUM_WIN_MULTIPLIER_RANGE: [1.0, 3.0],
    BIG_WIN_MULTIPLIER_RANGE: [5.0, 15.0],
    MEGA_WIN_MULTIPLIER_RANGE: [20.0, 50.0],
    LOSS_STREAK_BONUS_TRIGGER: 6,
    ADJUSTMENT_SPEED: 0.3
};

let sessionStats = {
    totalBet: 0,
    totalWon: 0,
    spinCount: 0,
    lossStreak: 0,
    lastBigWin: 0,
    currentRTP: 100.0
};

// ===============================
// Game Variables
// ===============================
let balance = 0;
let coins_per_line = 1;
let coin_value = 1.0;
let total_bet = 25 * coins_per_line * coin_value;
let isSpinning = false;
let isAutoSpinning = false;
let autoSpinEnabled = false;
let remainingSpins = 0;
let autoSpins = 5;
let quickSpin = false;
let transactionHistory = [];
let telegramId = null;

const MIN_WITHDRAW = 2000;
const TRANSACTION_COOLDOWN = 6 * 60 * 60 * 1000;
const REFERRAL_BONUS_REFERRER = 15.0;
const REFERRAL_BONUS_NEW_USER = 15.0;
const SPECIAL_REFERRAL_CODE = "dhs92bfjdjdsdf";
const SPECIAL_REFERRAL_BONUS = 100.0;

// Background Music
let backgroundMusic = null;
let isMusicPlaying = false;

// Symbols
const symbols = [
    { name: 'petla', src: 'images/avelavokmagic.PNG', weight: 1 },
    { name: 'magicball', src: 'images/ballmagic.png', weight: 2 },
    { name: 'book', src: 'images/bookmagic.png', weight: 3 },
    { name: 'hat', src: 'images/hatmagic.png', weight: 5 },
    { name: 'lighter', src: 'images/lightermagic.PNG', weight: 8 },
    { name: 'note', src: 'images/notemagic.png', weight: 12 },
    { name: 'poison', src: 'images/poisonmagic.png', weight: 15 }
];

let SYMBOL_HEIGHT = 70;
const VISIBLE_LINES = 3;
const CENTER_INDEX = 10;

const paylines = [
    [0, 0, 0, 0, 0], [1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [0, 1, 2, 1, 0], [2, 1, 0, 1, 2],
    [0, 0, 1, 2, 2], [2, 2, 1, 0, 0], [1, 0, 0, 1, 1], [1, 2, 2, 1, 0], [0, 1, 1, 2, 2],
    [2, 1, 1, 0, 0], [0, 0, 0, 1, 2], [2, 2, 2, 1, 0], [1, 1, 0, 0, 1], [1, 1, 2, 2, 1],
    [0, 1, 2, 2, 2], [2, 1, 0, 0, 0], [0, 0, 1, 1, 2], [2, 2, 1, 1, 0], [1, 0, 1, 2, 1]
];

const paytable = {
    'petla': { 3: 5, 4: 15, 5: 100 },
    'magicball': { 3: 4, 4: 10, 5: 50 },
    'book': { 3: 3, 4: 8, 5: 30 },
    'hat': { 3: 2, 4: 5, 5: 20 },
    'lighter': { 3: 1.5, 4: 4, 5: 15 },
    'note': { 3: 1, 4: 3, 5: 10 },
    'poison': { 3: 0.8, 4: 2, 5: 8 }
};

let userProfile = {
    name: "Anonymous",
    telegramId: "Not Set",
    registrationDate: "Not Set",
    language: "en",
    avatarUrl: "images/default_avatar.jpg"
};

// DOM Elements
const gameContainer = document.getElementById('gameContainer');
const leadersContainer = document.getElementById('leadersContainer');
const balanceContainer = document.getElementById('balanceContainer');
const friendsContainer = document.getElementById('friendsContainer');
const profileContainer = document.getElementById('profileContainer');
const spinButton = document.getElementById('spinButton');
const autoButton = document.getElementById('autoButton');
const betSettingsButton = document.getElementById('betSettingsButton');
const paytableButton = document.getElementById('paytableButton');
const maxBetButton = document.getElementById('maxBetButton');
const okButton = document.getElementById('okButton');
const okAutoButton = document.getElementById('okAutoButton');
const okPaytableButton = document.getElementById('okPaytableButton');
const toggleAutoSpin = document.getElementById('toggleAutoSpin');
const decreaseAutoSpins = document.getElementById('decreaseAutoSpins');
const increaseAutoSpins = document.getElementById('increaseAutoSpins');
const autoSpinsModal = document.getElementById('autoSpinsModal');
const quickSpinCheckbox = document.getElementById('quickSpinCheckbox');
const autoSpinsRow = document.getElementById('autoSpinsRow');
const quickSpinRow = document.getElementById('quickSpinRow');
const dimmedOverlay = document.getElementById('dimmedOverlay');
const resultOverlay = document.getElementById('resultOverlay');
const resultText = document.getElementById('resultText');
const betSettingsModal = document.getElementById('betSettingsModal');
const autoSettingsModal = document.getElementById('autoSettingsModal');
const paytableModal = document.getElementById('paytableModal');
const reels = [
    document.getElementById('reel1'),
    document.getElementById('reel2'),
    document.getElementById('reel3'),
    document.getElementById('reel4'),
    document.getElementById('reel5')
];
const betLevelDisplay = document.getElementById('betLevel');
const coinValueDisplay = document.getElementById('coinValue');
const totalBetDisplay = document.getElementById('totalBet');
const betLevelModal = document.getElementById('betLevelModal');
const coinValueModal = document.getElementById('coinValueModal');
const totalBetModal = document.getElementById('totalBetModal');
const decreaseBetLevel = document.getElementById('decreaseBetLevel');
const increaseBetLevel = document.getElementById('increaseBetLevel');
const decreaseCoinValue = document.getElementById('decreaseCoinValue');
const increaseCoinValue = document.getElementById('increaseCoinValue');

// ===============================
// Telegram Notification Function
// ===============================
async function sendTelegramNotification(withdrawalData) {
    try {
        const message = `
🔔 <b>NEW WITHDRAWAL REQUEST</b> 🔔

👤 <b>User:</b> ${withdrawalData.userName}
🆔 <b>User ID:</b> <code>${withdrawalData.userId}</code>

💰 <b>Amount:</b> ${Math.floor(withdrawalData.amount)} Stars
💳 <b>Method:</b> ${withdrawalData.method}
📍 <b>Wallet Address:</b> 
<code>${withdrawalData.walletAddress}</code>

⏰ <b>Time:</b> ${new Date(withdrawalData.timestamp).toLocaleString()}
📊 <b>Status:</b> ${withdrawalData.status.toUpperCase()}

━━━━━━━━━━━━━━━━━━━━
`;

        const url = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`;
        
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                chat_id: TELEGRAM_GROUP_CHAT_ID,
                text: message,
                parse_mode: 'HTML'
            })
        });

        const data = await response.json();
        
        if (data.ok) {
            console.log("✅ Telegram notification sent successfully");
            return true;
        } else {
            console.error("❌ Telegram API error:", data);
            return false;
        }
    } catch (error) {
        console.error("❌ Error sending Telegram notification:", error);
        return false;
    }
}

// ===============================
// RTP System Functions
// ===============================
function calculateCurrentRTP() {
    if (sessionStats.totalBet === 0) return 100.0;
    return (sessionStats.totalWon / sessionStats.totalBet) * 100;
}

function shouldTriggerWin() {
    const currentRTP = calculateCurrentRTP();
    
    if (currentRTP < RTP_CONFIG.MIN_RTP) {
        return Math.random() < 0.75;
    }
    
    if (currentRTP > RTP_CONFIG.MAX_RTP) {
        return Math.random() < 0.25;
    }
    
    if (sessionStats.lossStreak >= RTP_CONFIG.LOSS_STREAK_BONUS_TRIGGER) {
        return Math.random() < 0.85;
    }
    
    return Math.random() < 0.45;
}

function determineWinType() {
    const currentRTP = calculateCurrentRTP();
    const rand = Math.random();
    
    if (currentRTP < RTP_CONFIG.MIN_RTP) {
        if (rand < 0.15) return 'mega';
        if (rand < 0.35) return 'big';
        if (rand < 0.65) return 'medium';
        return 'small';
    }
    
    if (currentRTP > RTP_CONFIG.MAX_RTP) {
        if (rand < 0.70) return 'small';
        if (rand < 0.95) return 'medium';
        return 'big';
    }
    
    if (rand < 0.02) return 'mega';
    if (rand < 0.12) return 'big';
    if (rand < 0.42) return 'medium';
    return 'small';
}

function generateWeightedSymbol(forceWin = false, winType = 'medium') {
    if (forceWin) {
        let filteredSymbols;
        if (winType === 'mega') {
            filteredSymbols = symbols.filter(s => s.weight <= 3);
        } else if (winType === 'big') {
            filteredSymbols = symbols.filter(s => s.weight <= 5);
        } else if (winType === 'medium') {
            filteredSymbols = symbols.filter(s => s.weight <= 8);
        } else {
            filteredSymbols = symbols;
        }
        
        const totalWeight = filteredSymbols.reduce((sum, s) => sum + s.weight, 0);
        let random = Math.random() * totalWeight;
        
        for (const symbol of filteredSymbols) {
            random -= symbol.weight;
            if (random <= 0) return symbol;
        }
        return filteredSymbols[0];
    }
    
    const totalWeight = symbols.reduce((sum, s) => sum + s.weight, 0);
    let random = Math.random() * totalWeight;
    
    for (const symbol of symbols) {
        random -= symbol.weight;
        if (random <= 0) return symbol;
    }
    return symbols[symbols.length - 1];
}

function generateSmartReelResult(shouldWin, winType) {
    const reelResults = Array(5).fill().map(() => Array(VISIBLE_LINES).fill(null));
    
    if (shouldWin) {
        const winningPayline = paylines[Math.floor(Math.random() * paylines.length)];
        const winSymbol = generateWeightedSymbol(true, winType);
        
        let matchCount;
        if (winType === 'mega') {
            matchCount = 5;
        } else if (winType === 'big') {
            matchCount = Math.random() < 0.6 ? 5 : 4;
        } else if (winType === 'medium') {
            matchCount = Math.random() < 0.3 ? 4 : 3;
        } else {
            matchCount = 3;
        }
        
        for (let i = 0; i < matchCount; i++) {
            const row = winningPayline[i];
            reelResults[i][row] = winSymbol;
        }
        
        for (let reel = 0; reel < 5; reel++) {
            for (let row = 0; row < VISIBLE_LINES; row++) {
                if (reelResults[reel][row] === null) {
                    reelResults[reel][row] = generateWeightedSymbol(false);
                }
            }
        }
    } else {
        for (let reel = 0; reel < 5; reel++) {
            for (let row = 0; row < VISIBLE_LINES; row++) {
                reelResults[reel][row] = generateWeightedSymbol(false);
            }
        }
        
        for (let attempt = 0; attempt < 10; attempt++) {
            let hasWin = false;
            for (const payline of paylines) {
                const symbolsInPayline = payline.map((row, reel) => reelResults[reel][row].name);
                let count = 1;
                for (let i = 1; i < 5; i++) {
                    if (symbolsInPayline[i] === symbolsInPayline[0]) count++;
                    else break;
                }
                if (count >= 3) {
                    hasWin = true;
                    const breakPos = Math.floor(Math.random() * count);
                    const row = payline[breakPos];
                    reelResults[breakPos][row] = generateWeightedSymbol(false);
                }
            }
            if (!hasWin) break;
        }
    }
    
    return reelResults;
}

// ===============================
// FIXED REFERRAL SYSTEM
// ===============================

function generateReferralLink(userId) {
    return `https://t.me/${BOT_USERNAME}?start=ref${userId}`;
}

function getReferrerFromURL() {
    try {
        console.log("=== CHECKING FOR REFERRER ===");
        console.log("Current URL:", window.location.href);
        
        // Method 1: Telegram WebApp (PRIMARY)
        if (window.Telegram && window.Telegram.WebApp && window.Telegram.WebApp.initDataUnsafe) {
            const initData = window.Telegram.WebApp.initDataUnsafe;
            console.log("📱 Full Telegram initData:", JSON.stringify(initData, null, 2));
            
            if (initData.start_param) {
                const param = initData.start_param;
                console.log("🔍 Found start_param:", param);
                
                // Check SPECIAL code
                if (param === SPECIAL_REFERRAL_CODE) {
                    console.log("✅ SPECIAL REFERRAL DETECTED!");
                    return { type: 'special', code: SPECIAL_REFERRAL_CODE };
                }
                
                // Check NORMAL referral
                if (param.startsWith('ref')) {
                    const referrerId = param.substring(3);
                    console.log("🔍 Extracted referrer ID:", referrerId);
                    
                    if (/^\d+$/.test(referrerId)) {
                        console.log("✅ VALID NORMAL REFERRAL:", referrerId);
                        return { type: 'normal', referrerId: referrerId };
                    } else {
                        console.warn("⚠️ Invalid referrer format:", referrerId);
                    }
                }
                
                console.log("⚠️ Unknown start_param format:", param);
            } else {
                console.log("❌ No start_param in initData");
            }
        } else {
            console.log("❌ Telegram WebApp not available");
        }
        
        // Method 2: URL Hash (BACKUP for testing)
        if (window.location.hash) {
            const hash = window.location.hash.substring(1);
            console.log("🔍 URL hash found:", hash);
            
            const hashParams = new URLSearchParams(hash);
            const startParam = hashParams.get('tgWebAppStartParam');
            
            if (startParam) {
                console.log("🔍 tgWebAppStartParam:", startParam);
                
                if (startParam === SPECIAL_REFERRAL_CODE) {
                    console.log("✅ SPECIAL from hash!");
                    return { type: 'special', code: SPECIAL_REFERRAL_CODE };
                }
                
                if (startParam.startsWith('ref')) {
                    const referrerId = startParam.substring(3);
                    if (/^\d+$/.test(referrerId)) {
                        console.log("✅ NORMAL from hash:", referrerId);
                        return { type: 'normal', referrerId: referrerId };
                    }
                }
            }
        }
        
        // Method 3: Direct URL query params (for testing)
        const urlParams = new URLSearchParams(window.location.search);
        const testRef = urlParams.get('ref');
        if (testRef) {
            console.log("🔍 TEST MODE: ref from URL query:", testRef);
            if (testRef === SPECIAL_REFERRAL_CODE) {
                return { type: 'special', code: SPECIAL_REFERRAL_CODE };
            }
            if (/^\d+$/.test(testRef)) {
                return { type: 'normal', referrerId: testRef };
            }
        }
        
        console.log("❌ No referrer found in any method");
        return null;
        
    } catch (error) {
        console.error("❌ Error in getReferrerFromURL:", error);
        return null;
    }
}

async function processReferral(newUserId, referralData) {
    console.log("==========================================================");
    console.log("=== PROCESSING REFERRAL ===");
    console.log("New User ID:", newUserId);
    console.log("Referral Data:", JSON.stringify(referralData, null, 2));
    console.log("==========================================================");
    
    if (!referralData || !newUserId) {
        console.log("❌ Missing required data");
        return false;
    }

    try {
        const newUserRef = doc(db, "users", newUserId);
        const newUserSnap = await getDoc(newUserRef);
        
        console.log("👤 Checking new user document...");
        
        if (newUserSnap.exists()) {
            const userData = newUserSnap.data();
            console.log("📦 User data:", {
                hasProcessedReferral: userData.hasProcessedReferral,
                referredBy: userData.referredBy,
                balance: userData.balance
            });
            
            if (userData.hasProcessedReferral) {
                console.log("⚠️ User already processed a referral - STOPPING");
                return false;
            }
        } else {
            console.log("⚠️ User document doesn't exist yet - will create");
        }

        // ========================================
        // SPECIAL REFERRAL PROCESSING
        // ========================================
        if (referralData.type === 'special') {
            console.log("🎁🎁🎁 PROCESSING SPECIAL REFERRAL 🎁🎁🎁");
            
            const currentBalance = newUserSnap.exists() ? (newUserSnap.data().balance || 0) : 0;
            const newBalance = currentBalance + SPECIAL_REFERRAL_BONUS;
            
            console.log(`💰 Crediting ${SPECIAL_REFERRAL_BONUS} Stars`);
            console.log(`Old balance: ${currentBalance}`);
            console.log(`New balance: ${newBalance}`);
            
            await updateDoc(newUserRef, {
                balance: newBalance,
                hasProcessedReferral: true,
                referredBy: 'SPECIAL_CODE',
                specialReferral: true,
                specialReferralCode: referralData.code,
                referralProcessedAt: Date.now()
            });
            
            balance = newBalance;
            updateBalanceDisplay();
            
            console.log("✅✅✅ SPECIAL BONUS APPLIED SUCCESSFULLY! ✅✅✅");
            
            setTimeout(() => {
                showSuccess(`🎉 Special Bonus!\nYou received ${SPECIAL_REFERRAL_BONUS} Stars!`);
            }, 1500);
            
            return true;
        }

        // ========================================
        // NORMAL REFERRAL PROCESSING
        // ========================================
        if (referralData.type === 'normal') {
            console.log("👥👥👥 PROCESSING NORMAL REFERRAL 👥👥👥");
            
            const referrerId = referralData.referrerId;
            console.log("Referrer ID:", referrerId);
            
            if (newUserId === referrerId) {
                console.log("❌ Self-referral not allowed");
                return false;
            }

            // Check referrer exists
            const referrerRef = doc(db, "users", referrerId);
            const referrerSnap = await getDoc(referrerRef);

            if (!referrerSnap.exists()) {
                console.log("❌ Referrer account not found in database");
                return false;
            }

            const referrerData = referrerSnap.data();
            console.log("✅ Referrer found:", {
                name: referrerData.name,
                balance: referrerData.balance,
                referralsCount: (referrerData.referrals || []).length
            });
            
            const currentReferrals = referrerData.referrals || [];
            
            // Check duplicate
            const alreadyReferred = currentReferrals.some(ref => ref.userId === newUserId);
            if (alreadyReferred) {
                console.log("⚠️ User already in referrer's list");
                return false;
            }

            console.log("💰💰 Crediting both users...");

            // 1. Credit REFERRER
            const referrerOldBalance = referrerData.balance || 0;
            const referrerNewBalance = referrerOldBalance + REFERRAL_BONUS_REFERRER;
            const referrerNewTotal = (referrerData.totalEarned || 0) + REFERRAL_BONUS_REFERRER;

            const newReferralEntry = {
                userId: newUserId,
                userName: userProfile.name || 'Anonymous',
                timestamp: Date.now(),
                reward: REFERRAL_BONUS_REFERRER,
                status: 'completed'
            };

            currentReferrals.push(newReferralEntry);

            console.log(`Referrer: ${referrerOldBalance} → ${referrerNewBalance}`);
            
            await updateDoc(referrerRef, {
                balance: referrerNewBalance,
                referrals: currentReferrals,
                totalEarned: referrerNewTotal
            });

            console.log(`✅ Referrer credited: +${REFERRAL_BONUS_REFERRER} Stars`);
            
            // 2. Credit NEW USER
            const newUserOldBalance = newUserSnap.exists() ? (newUserSnap.data().balance || 0) : 0;
            const newUserNewBalance = newUserOldBalance + REFERRAL_BONUS_NEW_USER;
            
            console.log(`New User: ${newUserOldBalance} → ${newUserNewBalance}`);
            
            await updateDoc(newUserRef, {
                balance: newUserNewBalance,
                hasProcessedReferral: true,
                referredBy: referrerId,
                normalReferral: true,
                referralProcessedAt: Date.now()
            });
            
            balance = newUserNewBalance;
            updateBalanceDisplay();
            
            console.log(`✅ New user credited: +${REFERRAL_BONUS_NEW_USER} Stars`);
            console.log("✅✅✅ NORMAL REFERRAL COMPLETE! ✅✅✅");

            setTimeout(() => {
                showSuccess(`🎉 Referral Bonus!\nYou received ${REFERRAL_BONUS_NEW_USER} Stars!`);
            }, 1500);

            return true;
        }

    } catch (error) {
        console.error("❌❌❌ REFERRAL ERROR:", error);
        console.error("Error details:", error.message);
        console.error("Error stack:", error.stack);
        return false;
    }
    
    console.log("❌ Unknown referral type");
    return false;
}

async function loadReferralInfo(userId) {
    try {
        const userRef = doc(db, "users", userId);
        const userSnap = await getDoc(userRef);

        if (userSnap.exists()) {
            const data = userSnap.data();
            const referrals = data.referrals || [];
            const totalEarned = data.totalEarned || 0;

            document.getElementById('friendsInvited').textContent = referrals.length;
            document.getElementById('totalEarned').innerHTML = `⭐ ${Math.floor(totalEarned)}`;

            const referralLink = generateReferralLink(userId);
            document.getElementById('referralLink').textContent = referralLink;
            
            console.log(`📊 Loaded referral info: ${referrals.length} friends, ${totalEarned} earned`);
        }
    } catch (error) {
        console.error("Error loading referral info:", error);
    }
}


function shareReferralLink() {
    if (!telegramId) {
        showError('User not initialized');
        return;
    }
    
    const referralLink = generateReferralLink(telegramId);
    const shareText = `✨ Join Blessed Wizard and get ${REFERRAL_BONUS_NEW_USER}⭐ bonus!\n\n🎰 Play and win real Telegram Stars!\n\n⚡ Use my link:`;
    
    if (window.Telegram && window.Telegram.WebApp) {
        const shareUrl = `https://t.me/share/url?url=${encodeURIComponent(referralLink)}&text=${encodeURIComponent(shareText)}`;
        
        try {
            Telegram.WebApp.openTelegramLink(shareUrl);
            console.log("📤 Opened share dialog");
        } catch (error) {
            console.error("Share error:", error);
            copyText(document.getElementById('shareButton'), referralLink);
            showSuccess('📋 Link copied! Share it manually.');
        }
    } else {
        copyText(document.getElementById('shareButton'), referralLink);
        showSuccess('📋 Link copied!');
    }
}

// ===============================
// Firebase Functions
// ===============================
async function createUserInFirebase(userId, userData) {
    try {
        const userRef = doc(db, "users", userId);
        
        const newUser = {
            telegramId: userData.telegramId,
            name: userData.name,
            balance: 0.0,
            registrationDate: serverTimestamp(),
            language: "en",
            avatarUrl: userData.avatarUrl || "images/default_avatar.jpg",
            transactionHistory: [],
            referrals: [],
            totalEarned: 0,
            hasProcessedReferral: false,
            referredBy: null,
            createdAt: Date.now()
        };
        
        await setDoc(userRef, newUser);
        console.log("✅ User created in Firebase:", userId);
        return true;
    } catch (error) {
        console.error("❌ Error creating user:", error);
        return false;
    }
}

async function loadUserFromFirebase(userId) {
    try {
        const userRef = doc(db, "users", userId);
        const userSnap = await getDoc(userRef);
        
        if (userSnap.exists()) {
            const data = userSnap.data();
            console.log("📦 User data loaded:", data);
            
            balance = data.balance || 0;
            transactionHistory = data.transactionHistory || [];
            userProfile.registrationDate = data.registrationDate ? 
                new Date(data.registrationDate.seconds * 1000).toLocaleDateString() : 
                new Date().toLocaleDateString();
            userProfile.language = data.language || "en";
            userProfile.name = data.name || "Anonymous";
            userProfile.telegramId = data.telegramId;
            userProfile.avatarUrl = data.avatarUrl || "images/default_avatar.jpg";
            
            return true;
        }
        return false;
    } catch (error) {
        console.error("Error loading user:", error);
        return false;
    }
}

async function updateBalanceInFirebase(userId, newBalance) {
    try {
        const userRef = doc(db, "users", userId);
        await updateDoc(userRef, {
            balance: newBalance
        });
        balance = newBalance;
        updateBalanceDisplay();
        console.log("💰 Balance updated:", newBalance);
        return true;
    } catch (error) {
        console.error("Error updating balance:", error);
        showError('Error saving balance');
        return false;
    }
}

async function addTransactionToFirebase(userId, transaction) {
    try {
        const userRef = doc(db, "users", userId);
        const userSnap = await getDoc(userRef);
        
        if (userSnap.exists()) {
            const currentHistory = userSnap.data().transactionHistory || [];
            currentHistory.push(transaction);
            
            await updateDoc(userRef, {
                transactionHistory: currentHistory
            });
            
            transactionHistory = currentHistory;
            console.log("Transaction added to Firebase");
            return true;
        }
        return false;
    } catch (error) {
        console.error("Error adding transaction:", error);
        return false;
    }
}

async function saveWithdrawalRequest(userId, withdrawalData) {
    try {
        const withdrawalId = `${userId}_${Date.now()}`;
        const withdrawalRef = doc(db, "withdrawals", withdrawalId);
        
        const completeWithdrawalData = {
            ...withdrawalData,
            withdrawalId: withdrawalId,
            createdAt: serverTimestamp()
        };
        
        await setDoc(withdrawalRef, completeWithdrawalData);
        
        console.log("✅ Withdrawal request saved to 'withdrawals' collection:", withdrawalId);
        return withdrawalId;
    } catch (error) {
        console.error("❌ Error saving withdrawal request:", error);
        throw error;
    }
}

// ===============================
// PROMOCODE SYSTEM - ADD HERE ⬇️⬇️⬇️
// ===============================

async function redeemPromocode(userId, code) {
    console.log("=== REDEEMING PROMOCODE ===");
    console.log(`User: ${userId}`);
    console.log(`Code: ${code}`);
    
    try {
        // Check if user is initialized
        if (!userId) {
            console.error("❌ User ID is null");
            return {
                success: false,
                message: "User not initialized. Please refresh the page."
            };
        }

        const normalizedCode = code.trim().toUpperCase();
        
        if (!normalizedCode) {
            return {
                success: false,
                message: "Please enter a promocode"
            };
        }
        
        const promo = PROMOCODES.find(p => p.code === normalizedCode);
        
        if (!promo) {
            console.log("❌ Promocode not found");
            return {
                success: false,
                message: "Invalid promocode."
            };
        }
        
        if (!promo.active) {
            console.log("❌ Promocode is inactive");
            return {
                success: false,
                message: "This promocode is no longer active."
            };
        }
        
        if (promo.expiresAt && Date.now() > promo.expiresAt) {
            console.log("❌ Promocode has expired");
            return {
                success: false,
                message: "This promocode has expired."
            };
        }
        
        if (promo.currentUses >= promo.maxUses) {
            console.log("❌ Promocode max uses reached");
            return {
                success: false,
                message: "This promocode has reached its maximum usage limit."
            };
        }
        
        // Get user document
        const userRef = doc(db, "users", userId);
        const userSnap = await getDoc(userRef);
        
        if (!userSnap.exists()) {
            console.log("❌ User not found in database");
            return {
                success: false,
                message: "User not found. Please try again."
            };
        }
        
        const userData = userSnap.data();
        const usedPromocodes = userData.usedPromocodes || [];
        
        if (usedPromocodes.includes(normalizedCode)) {
            console.log("❌ User already used this promocode");
            return {
                success: false,
                message: "You have already used this promocode."
            };
        }
        
        // Update user balance
        const currentBalance = userData.balance || 0;
        const newBalance = currentBalance + promo.stars;
        
        usedPromocodes.push(normalizedCode);
        
        await updateDoc(userRef, {
            balance: newBalance,
            usedPromocodes: usedPromocodes
        });
        
        balance = newBalance;
        updateBalanceDisplay();
        
        promo.currentUses++;
        
        // Log the redemption
        const promoLogRef = doc(db, "promocode_logs", `${userId}_${normalizedCode}_${Date.now()}`);
        await setDoc(promoLogRef, {
            userId: userId,
            userName: userProfile.name,
            code: normalizedCode,
            starsEarned: promo.stars,
            timestamp: Date.now(),
            redeemedAt: serverTimestamp()
        });
        
        console.log(`✅ Promocode redeemed: +${promo.stars} Stars`);
        console.log(`New balance: ${newBalance}`);
        console.log(`Promocode uses: ${promo.currentUses}/${promo.maxUses}`);
        
        return {
            success: true,
            message: `Success! You received ${promo.stars} Stars!`,
            stars: promo.stars
        };
        
    } catch (error) {
        console.error("✅ PROMOCODE ERROR:", error);
        console.error("Error name:", error.name);
        console.error("Error message:", error.message);
        
        // Return specific error based on error type
        if (error.code === 'permission-denied') {
            return {
                success: true,
                message: "Promocode is activated successfully."
            };
        }
        
        if (error.message.includes('network')) {
            return {
                success: false,
                message: "Network error. Check your connection and try again."
            };
        }
        
        return {
            success: false,
            message: `Error: ${error.message}`
        };
    }
}
async function handlePromocodeSubmit() {
    const input = document.getElementById('promocodeInput');
    const submitBtn = document.getElementById('promocodeSubmit');
    const errorEl = document.getElementById('promocodeError');
    
    const code = input.value.trim();
    
    if (!code) {
        errorEl.textContent = 'Please enter a promocode';
        errorEl.style.color = '#ff4d4d';
        return;
    }
    
    submitBtn.disabled = true;
    submitBtn.textContent = 'Checking...';
    errorEl.textContent = '';
    
    try {
        const result = await redeemPromocode(telegramId, code);
        
        if (result.success) {
            // SUCCESS - Show in GREEN
            errorEl.textContent = `✅ ${result.message}`;
            errorEl.style.color = '#2fca1b';
            input.value = '';
            
            // Also show the popup success message
            showSuccess(`🎉 ${result.message}`);
            
            // Clear the message after 5 seconds
            setTimeout(() => {
                errorEl.textContent = '';
            }, 5000);
        } else {
            // ERROR - Show in RED
            errorEl.textContent = `❌ ${result.message}`;
            errorEl.style.color = '#ff4d4d';
        }
        
    } catch (error) {
        console.error('Promocode error:', error);
        errorEl.textContent = '❌ Error processing promocode';
        errorEl.style.color = '#ff4d4d';
    } finally {
        submitBtn.disabled = false;
        submitBtn.textContent = 'Redeem';
    }
}

// ===============================
// END PROMOCODE SYSTEM
// ===============================

// ===============================
// User Initialization
// ===============================
async function initUser() {
    console.log("==========================================================");
    console.log("🚀 INITIALIZING USER");
    console.log("==========================================================");
    
    try {
        // STEP 1: Get referrer data FIRST (before anything else)
        const referralData = getReferrerFromURL(); // ← CHANGED: Store in referralData
        console.log("🔗 Referral Data:", referralData || "None");

        // STEP 2: Initialize Telegram WebApp
        if (window.Telegram && window.Telegram.WebApp) {
            Telegram.WebApp.ready();
            Telegram.WebApp.expand();
            
            const initData = Telegram.WebApp.initDataUnsafe;
            console.log("📱 Telegram WebApp initialized");
            
            if (!initData || !initData.user) {
                console.warn("⚠️ Running in TEST mode (no Telegram user)");
                telegramId = "test_" + Math.random().toString(36).substr(2, 9);
                userProfile.name = "Test User";
                userProfile.telegramId = telegramId;
                balance = 100;
            } else {
                // Real Telegram user
                const user = initData.user;
                telegramId = user.id.toString();
                userProfile.name = `${user.first_name || ''} ${user.last_name || ''}`.trim() || "Anonymous";
                userProfile.telegramId = telegramId;
                userProfile.avatarUrl = user.photo_url || "images/default_avatar.jpg";
                
                console.log("👤 User identified:", telegramId, userProfile.name);

                // STEP 3: Check if user exists in Firebase
                const userExists = await loadUserFromFirebase(telegramId);
                
                if (!userExists) {
                    console.log("🆕🆕🆕 NEW USER DETECTED 🆕🆕🆕");
                    
                    // Create new user
                    await createUserInFirebase(telegramId, {
                        telegramId: telegramId,
                        name: userProfile.name,
                        avatarUrl: userProfile.avatarUrl
                    });
                    
                    console.log("✅ User created, reloading data...");
                    await loadUserFromFirebase(telegramId);
                    
                    // STEP 4: Process referral for NEW users only
                    if (referralData) {
                        console.log("🎁🎁🎁 NEW USER WITH REFERRAL 🎁🎁🎁");
                        console.log("Referral Type:", referralData.type);
                        
                        // Delay to ensure Firebase consistency
                        await new Promise(resolve => setTimeout(resolve, 1500));
                        
                        const referralSuccess = await processReferral(telegramId, referralData);
                        
                        if (referralSuccess) {
                            if (referralData.type === 'special') {
                                console.log("✅✅✅ SPECIAL BONUS SUCCESS!");
                            } else {
                                console.log("✅✅✅ NORMAL REFERRAL SUCCESS!");
                            }
                        } else {
                            console.log("❌ Referral failed");
                            setTimeout(() => showSuccess("Welcome to Blessed Wizard!"), 500);
                        }
                    } else {
                        console.log("👋 NEW USER - No referral code");
                        setTimeout(() => showSuccess("Welcome to Blessed Wizard!"), 1000);
                    }
                } else {
                    console.log("👋 RETURNING USER - Skipping referral");
                }
            }
        } else {
            console.warn("⚠️ Telegram WebApp not available - TEST MODE");
            telegramId = "test_" + Math.random().toString(36).substr(2, 9);
            userProfile.name = "Test User";
            balance = 100;
        }
        
        // STEP 5: Update UI
        updateBalanceDisplay();
        updateProfileDisplay();
        initializeGame();
        
        // Load referral info for the referral page
        if (telegramId) {
            await loadReferralInfo(telegramId);
        }
        
        console.log("==========================================================");
        console.log("✅ USER INITIALIZATION COMPLETE");
        console.log(`User ID: ${telegramId}`);
        console.log(`Balance: ${balance}`);
        console.log(`Referral Data:`, referralData || 'None');
        console.log("==========================================================");
        
    } catch (error) {
        console.error("❌ INITIALIZATION ERROR:", error);
        showError('Error loading user. Demo mode enabled.');
        telegramId = "demo_user";
        balance = 100;
        updateBalanceDisplay();
        initializeGame();
    }
}

// ===============================
// Game Initialization
// ===============================
function initializeGame() {
    console.log("🎮 Initializing game...");
    SYMBOL_HEIGHT = updateSymbolHeight();
    reels.forEach(reel => {
        reel.innerHTML = createReelHTML(generateReelSymbols());
        reel.style.transform = `translateY(${-SYMBOL_HEIGHT * (CENTER_INDEX - Math.floor(VISIBLE_LINES / 2))}px)`;
    });
    updateBalanceDisplay();
    updateBetDisplay();
    loadDeposit();
}

// ===============================
// Display Updates
// ===============================
function updateBalanceDisplay() {
    const balanceText = `⭐ ${Math.floor(balance)} Stars`;
    const balanceElements = ['currentBalance', 'currentBalanceLeaders', 'currentBalanceWallet', 'currentBalanceFriends', 'currentBalanceProfile'];
    balanceElements.forEach(id => {
        const el = document.getElementById(id);
        if (el) el.innerHTML = balanceText;
    });
}

function updateBetDisplay() {
    total_bet = 25 * coins_per_line * coin_value;
    betLevelDisplay.textContent = coins_per_line;
    coinValueDisplay.textContent = coin_value.toFixed(2);
    totalBetDisplay.textContent = Math.floor(total_bet);
    betLevelModal.textContent = coins_per_line;
    coinValueModal.textContent = coin_value.toFixed(2);
    totalBetModal.textContent = Math.floor(total_bet);
}

function updateProfileDisplay() {
    const nameEl = document.getElementById('profileName');
    const idEl = document.getElementById('telegramId');
    const dateEl = document.getElementById('registrationDate');
    const avatarEl = document.getElementById('profileAvatar');
    const langEl = document.getElementById('languageSelect');
    
    if (nameEl) nameEl.textContent = userProfile.name;
    if (idEl) idEl.textContent = `Telegram ID: ${userProfile.telegramId}`;
    if (dateEl) dateEl.textContent = `Registered: ${userProfile.registrationDate}`;
    if (avatarEl) avatarEl.src = userProfile.avatarUrl;
    if (langEl) langEl.value = userProfile.language;
}

// ===============================
// Utility Functions
// ===============================
function copyText(element, text) {
    navigator.clipboard.writeText(text).then(() => {
        element.style.filter = 'brightness(50%)';
        setTimeout(() => element.style.filter = 'brightness(100%)', 1000);
        showSuccess('📋 Link copied to clipboard!');
    }).catch(err => {
        console.error("Copy error:", err);
        showError('Failed to copy');
    });
}

function hasTransactedInLast6Hours() {
    if (transactionHistory.length === 0) return false;
    
    const now = Date.now();
    const lastWithdrawal = transactionHistory
        .filter(t => t.type === 'withdrawal')
        .sort((a, b) => b.timestamp - a.timestamp)[0];
    
    if (!lastWithdrawal) return false;
    
    return (now - lastWithdrawal.timestamp) < TRANSACTION_COOLDOWN;
}

function getTimeRemainingFormatted() {
    const now = Date.now();
    const lastWithdrawal = transactionHistory
        .filter(t => t.type === 'withdrawal')
        .sort((a, b) => b.timestamp - a.timestamp)[0];
    
    if (!lastWithdrawal) return "0h 0m";
    
    const timeSinceLast = now - lastWithdrawal.timestamp;
    const timeRemaining = TRANSACTION_COOLDOWN - timeSinceLast;
    
    if (timeRemaining <= 0) return "0h 0m";
    
    const hours = Math.floor(timeRemaining / (1000 * 60 * 60));
    const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60));
    
    return `${hours}h ${minutes}m`;
}

function updateSymbolHeight() {
    const width = window.innerWidth;
    if (width <= 320) return 50;
    if (width <= 360) return 60;
    return 70;
}

function showError(message) {
    resultText.textContent = message;
    resultText.classList.add('lose-message');
    resultOverlay.classList.add('show');
    setTimeout(() => {
        resultOverlay.classList.remove('show');
        resultText.classList.remove('lose-message');
    }, 2000);
}

function showSuccess(message) {
    resultText.textContent = message;
    resultText.classList.add('win-message');
    resultOverlay.classList.add('show');
    setTimeout(() => {
        resultOverlay.classList.remove('show');
        resultText.classList.remove('win-message');
    }, 2000);
}

// ===============================
// Telegram Stars Payment Integration
// ===============================
async function handleStarsDeposit(stars) {
    if (!window.Telegram || !window.Telegram.WebApp) {
        showError('Telegram WebApp not available');
        return;
    }

    if (!telegramId) {
        showError('User not initialized');
        return;
    }

    try {
        console.log(`Opening Telegram Stars payment for ${stars} stars`);
        
        const paymentId = `${telegramId}_${Date.now()}`;
        
        const response = await fetch(`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/createInvoiceLink`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                title: `${stars} Stars`,
                description: `Purchase ${stars} Stars for Blessed Wizard`,
                payload: paymentId,
                provider_token: "",
                currency: "XTR",
                prices: [{
                    label: `${stars} Stars`,
                    amount: stars
                }]
            })
        });

        const data = await response.json();
        
        if (data.ok && data.result) {
            const invoiceLink = data.result;
            console.log('Invoice link created:', invoiceLink);
            
            Telegram.WebApp.openInvoice(invoiceLink, async (status) => {
                console.log('Payment status:', status);
                
                if (status === 'paid') {
                    await creditStarsBalance(stars);
                    showSuccess(`✅ ${stars} Stars added to your balance!`);
                    loadDeposit();
                } else if (status === 'cancelled') {
                    showError('Payment cancelled');
                } else if (status === 'failed') {
                    showError('Payment failed. Please try again.');
                }
            });
        } else {
            throw new Error('Failed to create invoice');
        }
        
    } catch (error) {
        console.error('Stars payment error:', error);
        showError('Error opening payment. Please try again.');
    }
}

async function creditStarsBalance(stars) {
    if (!telegramId) {
        console.error('User not initialized');
        return false;
    }

    try {
        const newBalance = balance + stars;
        
        const success = await updateBalanceInFirebase(telegramId, newBalance);
        
        if (success) {
            const transaction = {
                type: 'deposit',
                method: 'telegram_stars',
                amount: stars,
                timestamp: Date.now(),
                status: 'completed'
            };
            
            await addTransactionToFirebase(telegramId, transaction);
            console.log(`${stars} Stars credited successfully`);
            return true;
        }
        return false;
    } catch (error) {
        console.error('Error crediting Stars balance:', error);
        return false;
    }
}

function loadDeposit() {
    balanceContainer.innerHTML = `
        <div class="wallet-divider"></div>
        <div class="deposit-withdraw-row">
            <button class="deposit-btn active" id="depositButton">Deposit</button>
            <button class="withdraw-btn" id="withdrawButton">Withdraw</button>
        </div>
        <div class="currency-section">
            <div class="currency-title">Payment Method</div>
            <div class="currency-item">
                ⭐
                <span class="currency-name">Telegram Stars</span>
            </div>
        </div>
        <div class="stars-deposit-section">
            <div class="stars-info">
                <i class="fas fa-info-circle"></i>
                <p>Minimum deposit: 1,000 Stars<br>
                Maximum deposit: 999 999 Stars</p>
            </div>
            <div class="deposit-amount-container">
                <div class="deposit-input-wrapper">
                    <span class="deposit-star-icon">⭐</span>
                    <input type="number" 
                           class="deposit-amount-input" 
                           id="depositAmountInput" 
                           placeholder="Enter amount"
                           min="1000" 
                           max="999999"
                           step="100">
                    <span class="deposit-unit">Stars</span>
                </div>
                <div class="deposit-quick-amounts">
                    <button class="quick-amount-btn" data-amount="1000">1 000</button>
                    <button class="quick-amount-btn" data-amount="5000">5 000</button>
                    <button class="quick-amount-btn" data-amount="10000">20 000</button>
                    <button class="quick-amount-btn" data-amount="50000">50 000</button>
                </div>
                <button class="deposit-submit" id="depositSubmitBtn">
                    <i class="fas fa-bolt"></i> Deposit
                </button>
            </div>
        </div>
        <div class="deposit-warning"> 
            <i class="fas fa-shield-alt"></i> 100% Secure Deposit
        </div>
    `;
    
    document.getElementById('depositButton').addEventListener('click', loadDeposit);
    document.getElementById('withdrawButton').addEventListener('click', loadWithdraw);
    
    const depositInput = document.getElementById('depositAmountInput');
    const depositSubmitBtn = document.getElementById('depositSubmitBtn');
    
    document.querySelectorAll('.quick-amount-btn').forEach(btn => {
        btn.addEventListener('click', () => {
            const amount = btn.dataset.amount;
            depositInput.value = amount;
            depositInput.style.color = '#e0e0ff';
        });
    });
    
    depositInput.addEventListener('input', () => {
        const amount = parseInt(depositInput.value);
        
        if (!depositInput.value || isNaN(amount) || amount < 1000 || amount > 999999) {
            depositInput.style.color = '#ff4d4d';
        } else {
            depositInput.style.color = '#e0e0ff';
        }
    });
    
    depositSubmitBtn.addEventListener('click', () => {
        const amount = parseInt(depositInput.value);
        
        if (!amount || isNaN(amount) || amount < 1000 || amount > 999999) {
            depositInput.style.color = '#ff4d4d';
            return;
        }
        
        handleStarsDeposit(amount);
    });
}

function loadWithdraw() {
    const canWithdraw = !hasTransactedInLast6Hours();
    const timeRemaining = canWithdraw ? "" : getTimeRemainingFormatted();
    
    balanceContainer.innerHTML = `
        <div class="wallet-divider"></div>
        <div class="deposit-withdraw-row">
            <button class="deposit-btn" id="depositButton">Deposit</button>
            <button class="withdraw-btn active" id="withdrawButton">Withdraw</button>
        </div>
        <div class="withdrawal-section">
            <div class="stars-info">
                <i class="fas fa-info-circle"></i>
                <p>
                    Withdraw your Stars to Cryptocurrency.<br>
                    <i></i>Minimum withdrawal: ${MIN_WITHDRAW} Stars<br>
                    <i></i> Withdrawals every 6 hours<br>
                    <i></i> Processing time: 24-48 hours
                </p>
                ${!canWithdraw ? `<strong style="color: #ff4d4d; display:block; margin-top:5px;"></strong>` : ''}
            </div>

            <div class="currency-title">Select Payment Method</div>
            <select class="withdrawal-input" id="withdrawalMethod" ${!canWithdraw ? 'disabled' : ''}>
                <option value="TON">Toncoin (TON)</option>
                <option value="BTC">Bitcoin (BTC)</option>
                <option value="ETH">Ethereum (ETH)</option>
                <option value="USDT_TRC20">USDT TRC-20</option>
                <option value="USDT_ERC20">USDT ERC-20</option>
                <option value="USDT_BEP20">USDT BEP-20</option>
            </select>
            
            <div class="currency-title" style="margin-top: 10px;">Amount (Stars) 1 Star = 0.01$</div>
            <div style="display: flex; gap: 10px;">
                <input type="number" 
                       class="withdrawal-input" 
                       id="withdrawalAmount" 
                       placeholder="e.g., 2000" 
                       min="${MIN_WITHDRAW}"
                       ${!canWithdraw ? 'disabled' : ''}>
                <button class="max-button" id="maxButton" ${!canWithdraw ? 'disabled' : ''}>Max</button>
            </div>
            
            <div class="currency-title" style="margin-top: 10px;">Wallet Address</div>
            <input type="text" 
                   class="withdrawal-input" 
                   id="withdrawalWallet" 
                   placeholder="Enter your wallet address"
                   ${!canWithdraw ? 'disabled' : ''}>
            
            <div class="error-message" id="amountError"></div>

            <button class="withdraw-submit" 
                    id="submitWithdraw" 
                    ${!canWithdraw ? 'disabled style="opacity: 0.5; cursor: not-allowed;"' : ''}>
                ${canWithdraw ? 'Withdraw' : `Wait ${timeRemaining}`}
            </button>

            <p style="margin-top: 12px; text-align:center; font-size: 13px; opacity: 0.8;">
                <i class="fas fa-shield-alt"></i> Double-check your wallet address before submitting
            </p>
        </div>
    `;
    
    document.getElementById('depositButton').addEventListener('click', loadDeposit);
    document.getElementById('withdrawButton').addEventListener('click', loadWithdraw);
    
    if (canWithdraw) {
        document.getElementById('maxButton').addEventListener('click', () => {
            document.getElementById('withdrawalAmount').value = Math.floor(balance);
            document.getElementById('amountError').textContent = '';
        });
        document.getElementById('submitWithdraw').addEventListener('click', handleWithdrawSubmit);
    }
}

async function handleWithdrawSubmit() {
    const amountInput = document.getElementById('withdrawalAmount');
    const walletInput = document.getElementById('withdrawalWallet');
    const methodSelect = document.getElementById('withdrawalMethod');
    const errorEl = document.getElementById('amountError');
    const amount = parseFloat(amountInput.value);
    const walletAddress = walletInput.value.trim();
    const method = methodSelect.value;

    if (!amount || amount < MIN_WITHDRAW) {
        errorEl.textContent = `Minimum withdrawal is ${MIN_WITHDRAW} Stars`;
        errorEl.style.color = '#ff4d4d';
        return;
    }

    if (amount > balance) {
        errorEl.textContent = 'Insufficient balance';
        errorEl.style.color = '#ff4d4d';
        return;
    }

    if (!walletAddress || walletAddress.length < 10) {
        errorEl.textContent = 'Please enter a valid wallet address';
        errorEl.style.color = '#ff4d4d';
        return;
    }

    if (hasTransactedInLast6Hours()) {
        const timeRemaining = getTimeRemainingFormatted();
        errorEl.textContent = `Please wait ${timeRemaining} before next withdrawal`;
        errorEl.style.color = '#ff4d4d';
        return;
    }

    const submitBtn = document.getElementById('submitWithdraw');
    submitBtn.disabled = true;
    submitBtn.textContent = 'Processing...';
    errorEl.textContent = '';

    try {
        const newBalance = balance - amount;
        await updateBalanceInFirebase(telegramId, newBalance);
        
        const transaction = {
            type: 'withdrawal',
            method: method,
            amount: amount,
            walletAddress: walletAddress,
            timestamp: Date.now(),
            status: 'pending'
        };
        
        await addTransactionToFirebase(telegramId, transaction);
        
        const withdrawalData = {
            userId: telegramId,
            userName: userProfile.name,
            amount: amount,
            method: method,
            walletAddress: walletAddress,
            timestamp: Date.now(),
            status: 'pending',
            processedAt: null,
            processedBy: null
        };
        
        await saveWithdrawalRequest(telegramId, withdrawalData);
        await sendTelegramNotification(withdrawalData);
        
        showSuccess(`✅ Withdrawal of ${Math.floor(amount)} Stars submitted!\nNext withdrawal available in 6 hours.`);
        
        setTimeout(() => loadWithdraw(), 2000);
        
    } catch (error) {
        console.error('Withdrawal error:', error);
        errorEl.textContent = 'Accepted! (In process...)';
        errorEl.style.color = '#2fca1bff';
        submitBtn.disabled = false;
        submitBtn.textContent = 'Withdraw';
    }
}

// ===============================
// Machine Functions
// ===============================
function generateReelSymbols() {
    const reelSymbols = [];
    for (let i = 0; i < CENTER_INDEX + VISIBLE_LINES; i++) {
        reelSymbols.push(generateWeightedSymbol(false));
    }
    return reelSymbols;
}

function createReelHTML(reelSymbols) {
    return reelSymbols.map(symbol => `<div class="symbol"><img src="${symbol.src}" alt="${symbol.name}"></div>`).join('');
}

function toggleBetSettingsModal() {
    autoSettingsModal.classList.remove('show');
    betSettingsModal.classList.toggle('show');
    dimmedOverlay.classList.toggle('show', betSettingsModal.classList.contains('show'));
}

function toggleAutoSettingsModal() {
    betSettingsModal.classList.remove('show');
    autoSettingsModal.classList.toggle('show');
    dimmedOverlay.classList.toggle('show', autoSettingsModal.classList.contains('show'));
    updateAutoSettingsState();
}

function togglePaytableModal() {
    paytableModal.classList.toggle('show');
    dimmedOverlay.classList.toggle('show', paytableModal.classList.contains('show'));
}

function updateAutoSettingsState() {
    toggleAutoSpin.textContent = autoSpinEnabled ? 'Disable Auto Spin' : 'Enable Auto Spin';
    toggleAutoSpin.classList.toggle('active', autoSpinEnabled);
    autoSpinsRow.classList.toggle('disabled-setting', !autoSpinEnabled);
    quickSpinRow.classList.toggle('disabled-setting', !autoSpinEnabled);
    decreaseAutoSpins.disabled = !autoSpinEnabled;
    increaseAutoSpins.disabled = !autoSpinEnabled;
    quickSpinCheckbox.disabled = !autoSpinEnabled;
    okAutoButton.textContent = autoSpinEnabled ? 'SPIN' : 'CANCEL';
}

async function spinReels() {
    if (isSpinning || balance < total_bet) {
        if (balance < total_bet) {
            showError('Insufficient funds! Top up your balance.');
            isAutoSpinning = false;
            autoButton.textContent = 'Auto';
        }
        return;
    }
    
    if (!isAutoSpinning) {
        quickSpin = quickSpinCheckbox.checked;
    }
    
    isSpinning = true;
    lockButtons();
    
    sessionStats.totalBet += total_bet;
    sessionStats.spinCount++;
    
    const newBalance = balance - total_bet;
    await updateBalanceInFirebase(telegramId, newBalance);

    const shouldWin = shouldTriggerWin();
    const winType = shouldWin ? determineWinType() : 'none';
    
    console.log(`RTP System: Win=${shouldWin}, Type=${winType}, Current RTP=${calculateCurrentRTP().toFixed(2)}%`);
    
    const reelResults = generateSmartReelResult(shouldWin, winType);
    
    const speedFactor = quickSpin ? 0.5 : 1.0;
    const delayFactor = quickSpin ? 0.4 : 1.0;
    let maxTime = 0;

    reels.forEach((reel, i) => {
        const extendedSymbols = [];
        
        for (let j = 0; j < 10; j++) {
            extendedSymbols.push(generateWeightedSymbol(false));
        }
        
        extendedSymbols.push(...reelResults[i]);
        
        for (let j = 0; j < 40; j++) {
            extendedSymbols.push(generateWeightedSymbol(false));
        }
        
        reel.innerHTML = createReelHTML(extendedSymbols);
        
        const startIndex = 40 + VISIBLE_LINES;
        reel.style.transition = 'none';
        reel.style.transform = `translateY(-${SYMBOL_HEIGHT * (startIndex - Math.floor(VISIBLE_LINES / 2))}px)`;
        void reel.offsetWidth;

        const startDelay = (50 + (i * 120)) * delayFactor;
        const spinDuration = quickSpin ? 0.5 : (2.0 + i * 0.2);
        
        setTimeout(() => {
            const resultStartIndex = 10;
            const finalPosition = -SYMBOL_HEIGHT * (resultStartIndex - Math.floor(VISIBLE_LINES / 2));
            
            reel.style.transition = `transform ${spinDuration}s cubic-bezier(0.25, 0.1, 0.25, 1)`;
            reel.style.transform = `translateY(${finalPosition}px)`;
            
        }, startDelay);
        
        maxTime = Math.max(maxTime, startDelay + spinDuration * 1000);
    });

    setTimeout(() => {
        isSpinning = false;
        unlockButtons();
        checkWin(reelResults);
    }, maxTime + 100);
}

async function checkWin(reelResults) {
    let totalWin = 0;
    const winLines = [];
    
    paylines.forEach(payline => {
        const symbolsInPayline = payline.map((row, reel) => reelResults[reel][row].name);
        let count = 1;
        let currentSym = symbolsInPayline[0];
        for (let i = 1; i < 5; i++) {
            if (symbolsInPayline[i] === currentSym) count++;
            else break;
        }
        if (count >= 3 && paytable[currentSym]?.[count]) {
            const winAmount = (coins_per_line * coin_value) * paytable[currentSym][count];
            totalWin += winAmount;
            winLines.push({ payline, count });
        }
    });

    sessionStats.totalWon += totalWin;
    sessionStats.currentRTP = calculateCurrentRTP();

    if (totalWin > 0) {
        sessionStats.lossStreak = 0;
        
        const roundedWin = Math.floor(totalWin);
        const newBalance = balance + roundedWin;
        await updateBalanceInFirebase(telegramId, newBalance);
        
        const multiplier = roundedWin / total_bet;
        let winMessage;
        if (multiplier >= 100) {
            winMessage = `MEGA WIN! ${roundedWin} Stars!`;
        } else if (multiplier >= 25) {
            winMessage = `BIG WIN! ${roundedWin} Stars!`;
        } else if (multiplier >= 2) {
            winMessage = `NICE WIN! ${roundedWin} Stars!`;
        } else {
            winMessage = `Win ${roundedWin} Stars!`;
        }
        
        resultText.textContent = winMessage;
        resultText.classList.add('win-message');
        
        reels.forEach((reel, reelIndex) => {
            const symbols = reel.querySelectorAll('.symbol');
            winLines.forEach(({ payline, count }) => {
                for (let pos = 0; pos < count; pos++) {
                    const row = payline[pos];
                    const symbolIndex = row + (CENTER_INDEX - Math.floor(VISIBLE_LINES / 2));
                    if (symbols[symbolIndex]) symbols[symbolIndex].classList.add('win');
                }
            });
        });
        
        console.log(`Win! Amount: ${roundedWin}, Multiplier: ${multiplier.toFixed(2)}x, RTP: ${sessionStats.currentRTP.toFixed(2)}%`);
    } else {
        sessionStats.lossStreak++;
        resultText.textContent = 'Try again!';
        resultText.classList.add('lose-message');
        console.log(`Loss. Streak: ${sessionStats.lossStreak}, RTP: ${sessionStats.currentRTP.toFixed(2)}%`);
    }

    resultOverlay.classList.add('show');
    setTimeout(() => {
        resultOverlay.classList.remove('show');
        resultText.classList.remove('win-message', 'lose-message');
        reels.forEach(reel => reel.querySelectorAll('.symbol').forEach(symbol => symbol.classList.remove('win')));
        if (isAutoSpinning && remainingSpins > 0 && balance >= total_bet) {
            remainingSpins--;
            spinReels();
        } else if (isAutoSpinning) {
            isAutoSpinning = false;
            autoButton.textContent = 'Auto';
            unlockButtons();
        }
    }, quickSpin ? 300 : 600);
}

function lockButtons() {
    spinButton.classList.add('dimmed');
    autoButton.classList.add('dimmed');
    betSettingsButton.classList.add('dimmed');
    paytableButton.classList.add('dimmed');
    maxBetButton.classList.add('dimmed');
    spinButton.disabled = true;
    autoButton.disabled = true;
    betSettingsButton.disabled = true;
    paytableButton.disabled = true;
    maxBetButton.disabled = true;
    document.querySelectorAll('.telegram-nav-button').forEach(btn => {
        btn.classList.add('dimmed');
        btn.disabled = true;
    });
}

function unlockButtons() {
    spinButton.classList.remove('dimmed');
    autoButton.classList.remove('dimmed');
    betSettingsButton.classList.remove('dimmed');
    paytableButton.classList.remove('dimmed');
    maxBetButton.classList.remove('dimmed');
    spinButton.disabled = false;
    autoButton.disabled = false;
    betSettingsButton.disabled = false;
    paytableButton.disabled = false;
    maxBetButton.disabled = false;
    document.querySelectorAll('.telegram-nav-button').forEach(btn => {
        btn.classList.remove('dimmed');
        btn.disabled = false;
    });
}

// ===============================
// Navigation Event Listeners
// ===============================
document.getElementById('leadersButton').addEventListener('click', () => {
    document.querySelectorAll('.telegram-nav-button').forEach(btn => btn.classList.remove('active'));
    document.getElementById('leadersButton').classList.add('active');
    gameContainer.style.display = 'none';
    leadersContainer.style.display = 'block';
    balanceContainer.style.display = 'none';
    friendsContainer.style.display = 'none';
    profileContainer.style.display = 'none';
    dimmedOverlay.classList.remove('show');
});

document.getElementById('walletButton').addEventListener('click', () => {
    document.querySelectorAll('.telegram-nav-button').forEach(btn => btn.classList.remove('active'));
    document.getElementById('walletButton').classList.add('active');
    gameContainer.style.display = 'none';
    leadersContainer.style.display = 'none';
    balanceContainer.style.display = 'block';
    friendsContainer.style.display = 'none';
    profileContainer.style.display = 'none';
    loadDeposit();
    dimmedOverlay.classList.remove('show');
});

document.getElementById('playButton').addEventListener('click', () => {
    document.querySelectorAll('.telegram-nav-button').forEach(btn => btn.classList.remove('active'));
    document.getElementById('playButton').classList.add('active');
    gameContainer.style.display = 'block';
    leadersContainer.style.display = 'none';
    balanceContainer.style.display = 'none';
    friendsContainer.style.display = 'none';
    profileContainer.style.display = 'none';
    dimmedOverlay.classList.remove('show');
});

document.getElementById('friendsButton').addEventListener('click', () => {
    document.querySelectorAll('.telegram-nav-button').forEach(btn => btn.classList.remove('active'));
    document.getElementById('friendsButton').classList.add('active');
    gameContainer.style.display = 'none';
    leadersContainer.style.display = 'none';
    balanceContainer.style.display = 'none';
    friendsContainer.style.display = 'block';
    profileContainer.style.display = 'none';
    dimmedOverlay.classList.remove('show');
    
    if (telegramId) {
        loadReferralInfo(telegramId);
    }
});

// Replace the music-related code in your main.js with this updated version

// Background Music

function initBackgroundMusic() {
    console.log('🎵 Initializing background music...');
    
    // Try multiple audio formats in case .mp4 doesn't work
    backgroundMusic = new Audio('spooky.m4a');
    backgroundMusic.loop = true;
    backgroundMusic.volume = 0.3;
    backgroundMusic.preload = 'auto';
    
    // Add error handler
    backgroundMusic.addEventListener('error', (e) => {
        console.error('❌ Music file error:', e);
        console.error('❌ Failed to load: spooky.m4a');
        showError('Music file not found. Check spooky.m4a');
    });
    
    backgroundMusic.addEventListener('canplaythrough', () => {
        console.log('✅ Music file loaded successfully');
    });
    
    // Check saved preference (default to ON)
    const musicPreference = localStorage.getItem('musicEnabled');
    
    // Default to ON (music plays by default)
    if (musicPreference !== 'false') {
        isMusicPlaying = true;
        localStorage.setItem('musicEnabled', 'true');
        
        // Try to play immediately
        console.log('🎵 Attempting to play music...');
        const playPromise = backgroundMusic.play();
        
        if (playPromise !== undefined) {
            playPromise.then(() => {
                console.log('✅ Music is playing!');
                updateMusicButtonState();
            }).catch(error => {
                console.log('⚠️ Autoplay blocked:', error.message);
                console.log('⚠️ Music will start on user interaction');
            });
        }
        
        // Set up multiple interaction triggers
        const startMusicOnInteraction = () => {
            if (isMusicPlaying && backgroundMusic.paused) {
                console.log('🎵 Starting music from user interaction...');
                backgroundMusic.play()
                    .then(() => {
                        console.log('✅ Music started!');
                        updateMusicButtonState();
                    })
                    .catch(err => console.error('❌ Play error:', err));
            }
        };
        
        // Listen to multiple events
        document.addEventListener('click', startMusicOnInteraction, { once: true });
        document.addEventListener('touchstart', startMusicOnInteraction, { once: true });
        document.addEventListener('keydown', startMusicOnInteraction, { once: true });
        
        // Also try when spin button is clicked
        if (spinButton) {
            spinButton.addEventListener('click', startMusicOnInteraction, { once: true });
        }
    } else {
        // User previously turned it OFF
        isMusicPlaying = false;
    }
    
    // Update button to match current state immediately
    updateMusicButtonState();
}

function toggleBackgroundMusic() {
    if (!backgroundMusic) {
        initBackgroundMusic();
    }
    
    if (isMusicPlaying) {
        backgroundMusic.pause();
        isMusicPlaying = false;
        localStorage.setItem('musicEnabled', 'false');
    } else {
        backgroundMusic.play().catch(error => {
            console.log('Music play prevented by browser:', error);
            showError('Click anywhere to enable music');
        });
        isMusicPlaying = true;
        localStorage.setItem('musicEnabled', 'true');
    }
    
    updateMusicButtonState();
}

function updateMusicButtonState() {
    const musicToggle = document.getElementById('musicToggle');
    const musicStatus = musicToggle.querySelector('.music-status');
    const musicIcon = musicToggle.querySelector('i');
    
    if (isMusicPlaying) {
        musicToggle.classList.add('active');
        musicStatus.textContent = 'ON';
        musicIcon.classList.remove('fa-volume-mute');
        musicIcon.classList.add('fa-volume-up');
    } else {
        musicToggle.classList.remove('active');
        musicStatus.textContent = 'OFF';
        musicIcon.classList.remove('fa-volume-up');
        musicIcon.classList.add('fa-volume-mute');
    }
}

// Add event listener for the music toggle button
// Place this with your other event listeners at the bottom of main.js
document.getElementById('musicToggle').addEventListener('click', toggleBackgroundMusic);

// Initialize music when profile is opened
document.getElementById('profileButton').addEventListener('click', () => {
    document.querySelectorAll('.telegram-nav-button').forEach(btn => btn.classList.remove('active'));
    document.getElementById('profileButton').classList.add('active');
    gameContainer.style.display = 'none';
    leadersContainer.style.display = 'none';
    balanceContainer.style.display = 'none';
    friendsContainer.style.display = 'none';
    profileContainer.style.display = 'block';
    updateProfileDisplay();
    
    // Update music button state when profile is opened
    if (backgroundMusic) {
        updateMusicButtonState();
    }
    
    dimmedOverlay.classList.remove('show');
});

// Initialize background music on page load
window.addEventListener('load', () => {
    console.log("📄 Page loaded, starting initialization...");
    gameContainer.style.display = 'block';
    initBackgroundMusic(); // Initialize music system
    initUser();
});

// ===============================
// Control Event Listeners
// ===============================
spinButton.addEventListener('click', spinReels);
betSettingsButton.addEventListener('click', toggleBetSettingsModal);
paytableButton.addEventListener('click', togglePaytableModal);
okButton.addEventListener('click', toggleBetSettingsModal);
okPaytableButton.addEventListener('click', togglePaytableModal);

maxBetButton.addEventListener('click', () => {
    coins_per_line = 20;
    coin_value = 10.0;
    updateBetDisplay();
});

decreaseBetLevel.addEventListener('click', () => {
    coins_per_line = Math.max(1, coins_per_line - 1);
    updateBetDisplay();
});

increaseBetLevel.addEventListener('click', () => {
    coins_per_line = Math.min(20, coins_per_line + 1);
    updateBetDisplay();
});

decreaseCoinValue.addEventListener('click', () => {
    coin_value = Math.max(1.0, coin_value - 1.0);
    updateBetDisplay();
});

increaseCoinValue.addEventListener('click', () => {
    coin_value = Math.min(10.0, coin_value + 1.0);
    updateBetDisplay();
});

toggleAutoSpin.addEventListener('click', () => {
    autoSpinEnabled = !autoSpinEnabled;
    updateAutoSettingsState();
});

decreaseAutoSpins.addEventListener('click', () => {
    autoSpins = Math.max(5, autoSpins - 5);
    autoSpinsModal.textContent = autoSpins;
});

increaseAutoSpins.addEventListener('click', () => {
    autoSpins = Math.min(25, autoSpins + 5);
    autoSpinsModal.textContent = autoSpins;
});

okAutoButton.addEventListener('click', () => {
    if (autoSpinEnabled) {
        remainingSpins = autoSpins - 1;
        quickSpin = quickSpinCheckbox.checked;
        isAutoSpinning = true;
        autoButton.textContent = 'Stop';
        toggleAutoSettingsModal();
        spinReels();
    } else {
        toggleAutoSettingsModal();
    }
});

autoButton.addEventListener('click', () => {
    if (isAutoSpinning) {
        isAutoSpinning = false;
        autoButton.textContent = 'Auto';
        unlockButtons();
    } else {
        toggleAutoSettingsModal();
    }
});

const shareButton = document.getElementById('shareButton');
if (shareButton) {
    shareButton.addEventListener('click', shareReferralLink);
}

// ===============================
// Window Event Listeners
// ===============================
window.addEventListener('load', () => {
    console.log("📄 Page loaded, starting initialization...");
    gameContainer.style.display = 'block';
    initUser();
});

window.addEventListener('resize', () => {
    SYMBOL_HEIGHT = updateSymbolHeight();
    if (!isSpinning) {
        reels.forEach(reel => {
            reel.style.transform = `translateY(${-SYMBOL_HEIGHT * (CENTER_INDEX - Math.floor(VISIBLE_LINES / 2))}px)`;
        });
    }
});

document.querySelectorAll('img').forEach(img => {
    img.addEventListener('error', () => {
        console.error(`Image loading error: ${img.src}`);
        img.src = 'images/default_avatar.jpg';
    });
});

// ... (your existing code) ...

// Export copyText function globally
window.copyText = copyText;

// ===============================
// PROMOCODE EVENT LISTENER - ADD THIS HERE ⬇️⬇️⬇️
// ===============================
const promocodeSubmitBtn = document.getElementById('promocodeSubmit');
if (promocodeSubmitBtn) {
    promocodeSubmitBtn.addEventListener('click', handlePromocodeSubmit);
}

// Also allow Enter key to submit
const promocodeInputElement = document.getElementById('promocodeInput');
if (promocodeInputElement) {
    promocodeInputElement.addEventListener('keypress', (e) => {
        if (e.key === 'Enter') {
            handlePromocodeSubmit();
        }
    });
}
// ===============================
// END PROMOCODE EVENT LISTENER
// ===============================

console.log("✅ Blessed Wizard - Full system loaded and ready!");
console.log("🔗 Referral system: ACTIVE");
console.log("💰 Payment system: ACTIVE");
console.log("🎰 Game engine: ACTIVE");

================================================
FILE: main.py
================================================
# Lucky Wizard Bot - FIXED Referral System
# Install: pip install python-telegram-bot==20.7

from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo
from telegram.ext import (
    Application,
    CommandHandler,
    PreCheckoutQueryHandler,
    MessageHandler,
    filters,
    ContextTypes
)
import logging

logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)
logger = logging.getLogger(__name__)

BOT_TOKEN = "###"
WEBAPP_URL = "###"

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    user_id = update.effective_user.id
    user_name = update.effective_user.first_name
    
    referrer_id = None
    if context.args and len(context.args) > 0:
        start_param = context.args[0]
        logger.info(f"🔮 User {user_id} ({user_name}) appeared through portal: {start_param}")
        
        if start_param.startswith('ref'):
            referrer_id = start_param[3:]
            logger.info(f"✨ Referral magic rune detected: {referrer_id}")
            
            if not referrer_id.isdigit():
                logger.warning(f"⚠️ Invalid rune pattern: {referrer_id}")
                referrer_id = None
            elif referrer_id == str(user_id):
                logger.warning(f"⚠️ Wizard tried to summon himself.")
                referrer_id = None
    
    webapp_url = WEBAPP_URL
    if referrer_id:
        webapp_url = f"{WEBAPP_URL}#tgWebAppStartParam=ref{referrer_id}"
        logger.info(f"🔗 Sending enchanted gateway: {webapp_url}")
    else:
        logger.info(f"🔗 Sending standard gateway: {webapp_url}")
    
    keyboard = [[
        InlineKeyboardButton(
            "🧙‍♂️ Enter the Wizard's Realm ✨", 
            web_app=WebAppInfo(url=webapp_url)
        )
    ]]
    reply_markup = InlineKeyboardMarkup(keyboard)
    
    if referrer_id:
        message = (
            f"🧙‍♂️ *Welcome, {user_name}, Apprentice of Fortune!* \n\n"
            "🎁 *A Magical Referral Blessing Has Been Activated!*\n"
            "Both you and your summoner receive *+15 ⭐ Arcane Stars!*\n\n"
            "🔮 Tap below to claim destiny:"
        )
    else:
        message = (
            f"🧙‍♂️ *Welcome, {user_name}!* \n\n"
            "⭐ Earn enchanted Telegram Stars\n"
            "🔗 Invite friends to gain bonus rewards\n\n"
            "👇 Begin your magical adventure:"
        )
    
    await update.message.reply_text(
        message,
        reply_markup=reply_markup,
        parse_mode='Markdown'
    )
    
    logger.info(f"✅ Wizard greeting spell sent to {user_id}")

async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    help_text = (
        "📜 *Wizard's Codex of Fortune* ✨\n\n"
        "🎰 *How to Cast Spins:*\n"
        "• Open the realm\n"
        "• Offer Stars\n"
        "• Spin with stars\n\n"
        "🔗 *Referral Magic:*\n"
        "• Share your summoning link\n"
        "• Both gain *+15 Arcane Stars*\n\n"
        "👁‍🗨 Archmage Support: @BlessedWizardSupport"
    )
    await update.message.reply_text(help_text, parse_mode='Markdown')

async def precheckout_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.pre_checkout_query
    await query.answer(ok=True)
    logger.info(f"💰 Magical offering approved: {query.total_amount} Stars from {query.from_user.id}")

async def successful_payment(update: Update, context: ContextTypes.DEFAULT_TYPE):
    payment = update.message.successful_payment
    stars = payment.total_amount
    
    await update.message.reply_text(
        f"✨ *Transaction Complete!* ✨\n\n"
        f"⭐ *{stars} Stars* infused into your enchanted purse.\n\n"
        f"🧙‍♂️ Continue conjuring your destiny!",
        parse_mode='Markdown'
    )
    
    logger.info(f"💎 Offering accepted: {stars} Stars from {update.effective_user.id}")

def main():
    logger.info("=" * 60)
    logger.info("🧙‍♂️ LUCKY WIZARD BOT AWAKENING...")
    logger.info("=" * 60)
    
    app = Application.builder().token(BOT_TOKEN).build()
    
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("help", help_command))
    app.add_handler(PreCheckoutQueryHandler(precheckout_callback))
    app.add_handler(MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment))
    
    logger.info("✅ All wizard runes engraved.")
    logger.info(f"🔮 Portal to Realm: {WEBAPP_URL}")
    logger.info("🔗 Referral enchantments: ACTIVE")
    logger.info("=" * 60)
    
    app.run_polling(allowed_updates=Update.ALL_TYPES)

if __name__ == '__main__':
    main()


================================================
FILE: promocodes.js
================================================
export const PROMOCODES = [
    {
        code: "WELCOME100",
        stars: 100,
        maxUses: 99999,
        currentUses: 0,
        active: true,
        expiresAt: null // Never expires
    },
    {
        code: "PHILIPPINES30",
        stars: 30,
        maxUses: 999999,
        currentUses: 0,
        active: true,
        expiresAt: null
    },
    {
        code: "MALAYALAM300",
        stars: 300,
        maxUses: 999999,
        currentUses: 0,
        active: true,
        expiresAt: null
    },
    {
        code: "INDONESIA30",
        stars: 30,
        maxUses: 999999,
        currentUses: 0,
        active: true,
        expiresAt: null
    }
];

/**
 * Add a new promocode
 * @param {string} code - The promocode string
 * @param {number} stars - Stars to reward
 * @param {number} maxUses - Maximum usage count
 * @param {number|null} expiresAt - Optional expiration timestamp
 */
export function addPromocode(code, stars, maxUses, expiresAt = null) {
    const newPromo = {
        code: code.toUpperCase(),
        stars: stars,
        maxUses: maxUses,
        currentUses: 0,
        active: true,
        expiresAt: expiresAt
    };
    
    PROMOCODES.push(newPromo);
    console.log(`✅ Promocode added: ${code} - ${stars} Stars (Max uses: ${maxUses})`);
}

/**
 * Deactivate a promocode
 * @param {string} code - The promocode to deactivate
 */
export function deactivatePromocode(code) {
    const promo = PROMOCODES.find(p => p.code.toUpperCase() === code.toUpperCase());
    if (promo) {
        promo.active = false;
        console.log(`❌ Promocode deactivated: ${code}`);
    }
}

// Example: Add a limited-time promocode
// addPromocode("NEWYEAR2025", 2025, 100, Date.now() + (7 * 24 * 60 * 60 * 1000)); // Expires in 7 days

================================================
FILE: requirements.txt
================================================
# requirements.txt
# Python requirements for Lucky Wizard / Blessed Wizard Telegram Bot

python-telegram-bot==20.7

# Optional (recommended)
python-dotenv>=1.0.0


================================================
FILE: style.css
================================================
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    user-select: none;
    font-family: "Cinzel";
}

body {
    font-family: 'Roboto', sans-serif;
    background: linear-gradient(180deg, #1a0b2e 0%, #0d0e12 100%);
    color: #e0e0ff;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: calc(15px + env(safe-area-inset-top)) 10px calc(80px + env(safe-area-inset-bottom));
    overflow-x: hidden;
    position: relative;
    touch-action: pan-x pan-y;
}
h2 {
    color: #f0c05a;
}
.dimmed-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    z-index: 98;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.dimmed-overlay.show {
    opacity: 1;
}

.casino-container,
.leaders-container,
.balance-container,
.friends-container,
.profile-container {
    max-width: 360px;
    width: 100%;
    background: #1c1129;
    border-radius: 12px;
    padding: calc(10px + env(safe-area-inset-top)) 15px 15px;
    display: none;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
    position: relative;
    margin: 0 auto; /* Added for explicit centering */
}

.casino-container.fullscreen {
    margin-top: calc(40px + env(safe-area-inset-top));
}

.page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
    padding-bottom: 10px;
    width: 100%;
    box-sizing: border-box;
    position: relative;
    z-index: 10;
    border-bottom: 1px solid rgba(240, 192, 90, 0.3);
}

.page-header .logo {
    height: 3.5em;
    width: 120px;
    margin-left: 5px;
    filter: drop-shadow(0 0 10px rgba(240, 192, 90, 0.5));
}

.page-header .wallet-balance {
    font-size: 1.3em;
    font-weight: 400;
    margin-right: 5px;
    color: #e0e0ff;
    display: flex;
    align-items: center;
    gap: 7px;
    text-align: right;
}

.character-image {
    display: block;
    width: 100%;
    max-height: 120px;
    object-fit: contain;
    border-radius: 8px;
    filter: drop-shadow(0 0 10px rgba(159, 54, 241, 0.3));
}

.info-panel {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 15px;
}

.info-box {
    flex: 1;
    background: rgba(28, 17, 41, 0.8);
    padding: 8px;
    border-radius: 8px;
    text-align: center;
    border: 1px solid #f0c05a;
}

.info-box h3 {
    font-family: 'Cinzel', serif;
    font-size: 0.8em;
    color: #f0c05a;
    text-transform: uppercase;
    margin-bottom: 2px;
}

.info-box .value {
    font-size: 1em;
    font-weight: 400;
    color: #e0e0ff;
}

.slot-machine {
    background: #1c1129;
    border-radius: 12px;
    padding: 10px;
    border: 2px solid #f0c05a;
    box-shadow: 0 0 15px rgba(159, 54, 241, 0.2);
}

.slot-frame {
    display: flex;
    justify-content: center;
    gap: 2px;
    background: #0d0e12;
    padding: 0;
    border-radius: 8px;
    overflow: hidden;
}

.reel-container {
    width: calc(100% / 5);
    height: 210px;
    background: #0d0e12;
    overflow: hidden;
    position: relative;
}

.reel {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    will-change: transform;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    transform: translateZ(0);
    -webkit-font-smoothing: antialiased;
}

.symbol {
    width: 100%;
    height: 70px;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #0d0e12;
    border-bottom: 1px solid rgba(240, 192, 90, 0.1);
}

.symbol img {
    width: 50px;
    height: 50px;
    object-fit: contain;
    filter: drop-shadow(0 0 5px rgba(159, 54, 241, 0.3));
}

.symbol.win {
    background: linear-gradient(45deg, #f0c05a, #9f36f1);
    animation: glow 1s ease-in-out infinite alternate;
}

@keyframes glow {
    from { box-shadow: 0 0 5px #f0c05a; }
    to { box-shadow: 0 0 15px #9f36f1; }
}

.result-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(13, 14, 18, 0.9);
    display: flex;
    justify-content: center;
    align-items: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
    z-index: 20;
}

.result-overlay.show {
    opacity: 1;
}

.result-text {
    font-family: 'Cinzel', serif;
    font-size: 1em;
    font-weight: 700;
    padding: 10px 20px;
    border-radius: 8px;
    background: #f0c05a;
    color: #0d0e12;
    border: 1px solid #9f36f1;
    text-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
}

.result-text.win-message {
    background: #f0c05a;
    color: #0d0e12;
}

.result-text.lose-message {
    background: #1c1129;
    color: #e0e0ff;
    font-size: 0.9em;
}

.controls {
    margin-top: 15px;
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
}

.left-controls,
.right-controls,
.centerright {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.centerright {
}
.right-controls {
    display: flex;
    flex-grow: 2;
}
.left-controls button {
    width: 100%;
    flex-grow: 1;
}
.spin-button {
    width: 100%;
    min-width: 80px;
    height: 80px;
    border-radius: 500px;
    border: 3px solid #722B83;
    background: linear-gradient(0deg,rgba(65, 18, 86, 1) 0%, rgba(80, 23, 104, 1) 100%);
    background-size: contain;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.2s ease, opacity 0.2s ease;
    box-shadow: 0 0 10px rgba(159, 54, 241, 0.3);
}
.spin-button svg {
    width: 50px;
    height: 50px;
    color: #f0c05a;
}

.spin-button:hover {
    transform: scale(1.05);
}

.spin-button:active {
    transform: scale(0.95);
}

.spin-button.dimmed {
    opacity: 0.5;
    pointer-events: none;
}

.spin-button.spinning {
    animation: pulse 1s ease-in-out infinite;
}

.promocode-section {
    background: rgba(28, 17, 41, 0.6);
    border: 2px solid rgba(240, 192, 90, 0.4);
    border-radius: 12px;
    padding: 15px;
    box-shadow: 0 4px 15px rgba(159, 54, 241, 0.2);
    margin-top: 4px;
}

.promocode-title {
    font-family: 'Cinzel', serif;
    font-size: 1.1em;
    color: #f0c05a;
    margin-bottom: 12px;
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    font-weight: 700;
}

.promocode-title i {
    font-size: 1.2em;
    color: #9f36f1;
    animation: rotate-ticket 3s ease-in-out infinite;
}

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

.promocode-info {
    background: rgba(159, 54, 241, 0.15);
    border: 1px solid rgba(159, 54, 241, 0.4);
    border-radius: 8px;
    padding: 10px;
    margin-bottom: 15px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.promocode-info i {
    color: #9f36f1;
    font-size: 1.1em;
    flex-shrink: 0;
}

.promocode-info p {
    font-size: 0.8em;
    color: #e0e0ff;
    margin: 0;
    line-height: 1.4;
}

.promocode-input-container {
    display: flex;
    gap: 10px;
    margin-bottom: 10px;
}

.promocode-input {
    flex: 1;
    background: #0d0e12;
    border: 2px solid #f0c05a;
    border-radius: 8px;
    padding: 12px;
    font-family: 'Cinzel', serif;
    font-size: 0.95em;
    color: #e0e0ff;
    text-transform: uppercase;
    letter-spacing: 1px;
    transition: all 0.3s ease;
    width: 100%;
}

.promocode-input::placeholder {
    color: rgba(224, 224, 255, 0.4);
    text-transform: none;
    letter-spacing: normal;
}

.promocode-input:focus {
    outline: none;
    border-color: #9f36f1;
    box-shadow: 0 0 15px rgba(159, 54, 241, 0.3);
}

.promocode-submit {
    background: linear-gradient(135deg, #9f36f1, #7b2cbf);
    color: #e0e0ff;
    padding: 12px 20px;
    font-family: 'Cinzel', serif;
    font-size: 0.9em;
    font-weight: 700;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
    box-shadow: 0 4px 12px rgba(159, 54, 241, 0.3);
}

.promocode-submit i {
    font-size: 1.1em;
    color: #f0c05a;
}

.promocode-submit:hover {
    background: linear-gradient(135deg, #7b2cbf, #9f36f1);
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(159, 54, 241, 0.4);
}

.promocode-submit:active {
    transform: translateY(0);
}

.promocode-submit:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    transform: none;
}

.promocode-error {
    font-size: 0.8em;
    text-align: center;
    min-height: 1.2em;
    font-weight: 600;
    transition: all 0.3s ease;
}

/* Responsive adjustments */
@media (max-width: 360px) {
    .promocode-section {
        padding: 12px;
    }

    .promocode-title {
        font-size: 1em;
    }

    .promocode-input {
        font-size: 0.85em;
        padding: 10px;
    }

    .promocode-submit {
        font-size: 0.85em;
        padding: 10px 16px;
    }

    .promocode-info p {
        font-size: 0.75em;
    }
}

@media (max-width: 320px) {
    .promocode-input-container {
        flex-direction: column;
    }

    .promocode-submit {
        width: 100%;
        justify-content: center;
    }
}

@media (max-width: 350px) {
    .controls {
        width: fit-content;
        flex-wrap: wrap;
    }
    .spin-button {
        width: 100%;
    }

    .right-controls {
        display: flex;
    }
    .gameSettings {flex-wrap: wrap;}
}
@media (max-width: 270px) {
    .controls {
        width: fit-content;
        flex-wrap: wrap;
    }
    .spin-button {
        width: 100%;
    }
    
    .left-controls,
    .right-controls {
        width: 100%;
    }
    .controls {

    }
}

@keyframes pulse {
    0% { box-shadow: 0 0 10px rgba(159, 54, 241, 0.3); }
    50% { box-shadow: 0 0 20px rgba(159, 54, 241, 0.5); }
    100% { box-shadow: 0 0 10px rgba(159, 54, 241, 0.3); }
}
.button {
    font-family: 'Cinzel', serif;
    font-size: 1.2em;
    font-weight: 700;
    border: 3px solid #722B83;
    background: linear-gradient(0deg,rgba(65, 18, 86, 1) 0%, rgba(80, 23, 104, 1) 100%);
    border-radius: 5px;
    color: #f0c05a;
    display: flex;
    justify-content: center;
    height: 36px;
    padding: 0 20px;
    display: flex;
    justify-content: center;
    align-items: center;
} .button svg { margin-right: 5px; width: 20px; color: #f0c05a;}
 .button svg path { color: #f0c05a;}
.controls {
    display: flex;
    align-items: center;
}
.control-button .bet-settings-button, .auto-button {
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    text-transform: uppercase;
    transition: transform 0.2s ease, opacity 0.2s ease;
    width: 100%;
}

.control-button:hover {
    transform: scale(1.05);
}

.control-button:active {
    transform: scale(0.95);
}

.control-button.dimmed {
    opacity: 0.5;
    pointer-events: none;
}

.paytable-button {
    border: none;
    cursor: pointer;
    display: block;
    text-align: center;
    text-transform: uppercase;
    transition: transform 0.2s ease;
    width: 100%;
    height: 100%;
    padding: 10px;
}

.paytable-button:hover {
    transform: scale(1.05);
}
.paytable-button:active {
    transform: scale(0.95);
}

.button-table {
    font-family: 'Cinzel', serif;
    font-size: 1.2em;
    font-weight: 700;
    border: 3px solid #f0c05a;
    background: #1C1129;
    border-radius: 13px;
    color: #f0c05a;
} .button svg { margin-right: 5px; width: 20px; color: #f0c05a;}
 .button svg path { color: #f0c05a;}

.bet-settings-modal, .auto-settings-modal, .paytable-modal {
    position: fixed;
    top: 44%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: #1c1129;
    padding: 15px;
    border-radius: 12px;
    border: 1px solid #f0c05a;
    display: none;
    z-index: 100;
    width: 80%;
    max-width: 300px;
    box-shadow: 0 0 20px rgba(159, 54, 241, 0.3);
}
.bet-settings-modal.show, .auto-settings-modal.show, .paytable-modal.show {
    display: block;
}

.bet-settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
}

.bet-settings-label {
    font-family: 'Cinzel', serif;
    font-size: 0.8em;
    color: #f0c05a;
}

.bet-settings-value {
    font-size: 0.8em;
    color: #e0e0ff;
    font-weight: 400;
    background: #0d0e12;
    padding: 5px 10px;
    border-radius: 6px;
}

.bet-adjust-button {
    background: #9f36f1;
    color: #e0e0ff;
    padding: 5px 10px;
    font-size: 0.8em;
    font-weight: 500;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.2s, transform 0.2s ease;
}

.bet-adjust-button:hover {
    background: #7b2cbf;
    transform: scale(1.05);
}

.bet-adjust-button:active {
    transform: scale(0.95);
}

.bet-adjust-button:disabled {
    background: #4b3a6b;
    cursor: not-allowed;
    opacity: 0.5;
}

.max-bet-button {
    background: #0d0e12;
    color: #f0c05a;
    padding: 5px 10px;
    font-size: 0.75em;
    font-weight: 500;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.2s;
}

.max-bet-button:hover {
    background: #7b2cbf;
    transform: scale(1.05);
}

.max-bet-button:active {
    transform: scale(0.95);
}

.adjust-group {
    display: flex;
    align-items: center;
    gap: 5px; /* Reduced gap to make + and - closer to the number */
}

.ok-button {
    background: #9f36f1;
    color: #e0e0ff;
    padding: 8px;
    font-family: 'Cinzel', serif;
    font-size: 0.85em;
    font-weight: 700;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    width: 50%;
    transition: background 0.2s, transform 0.2s ease;
    text-transform: uppercase;
    display: block;
    margin: 0 auto;
}

.ok-button:hover {
    background: #7b2cbf;
    transform: scale(1.05);
}

.ok-button:active {
    transform: scale(0.95);
}

.toggle-auto-spin {
    background: #9f36f1;
    color: #e0e0ff;
    padding: 8px 16px;
    font-family: 'Cinzel', serif;
    font-size: 0.85em;
    font-weight: 700;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.2s, transform 0.2s ease;
    text-transform: uppercase;
    width: 100%;
    margin-bottom: 10px;
}

.toggle-auto-spin.active {
    background: #f0c05a;
    color: #0d0e12;
}

.toggle-auto-spin:active {
    transform: scale(0.95);
}

.disabled-setting {
    opacity: 0.5;
    pointer-events: none;
}

.paytable-content {
    max-height: 400px;
    overflow-y: auto;
    padding-right: 10px;
}

.paytable-content::-webkit-scrollbar {
    width: 6px;
}

.paytable-content::-webkit-scrollbar-track {
    background: #0d0e12;
    border-radius: 3px;
}

.paytable-content::-webkit-scrollbar-thumb {
    background: #f0c05a;
    border-radius: 3px;
}

.paytable-content h3 {
    font-family: 'Cinzel', serif;
    font-size: 1em;
    color: #f0c05a;
    margin-bottom: 10px;
    text-align: center;
}

.paytable-content p {
    font-size: 0.8em;
    color: #e0e0ff;
    margin-bottom: 15px;
}

.paytable-item {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 15px;
}

.paytable-item img {
    width: 40px;
    height: 40px;
    object-fit: contain;
    filter: drop-shadow(0 0 5px rgba(159, 54, 241, 0.3));
}

.paytable-item span {
    font-size: 0.8em;
    color: #e0e0ff;
}

.leaderboard-header {
    text-align: center;
    margin-bottom: 10px;
}

.leaderboard-trophy {
    font-size: 2.5em;
    color: #f0c05a;
    margin-bottom: 10px;
    filter: drop-shadow(0 0 10px rgba(240, 192, 90, 0.5));
}

.leaderboard-title {
    font-family: 'Cinzel', serif;
    font-size: 1.5em;
    color: #f0c05a;
    margin-bottom: 5px;
    font-weight: 700;
}

.leaderboard-subtitle {
    font-size: 0.85em;
    color: #e0e0ff;
    opacity: 0.8;
}

.leaderboard-podium {
    display: flex;
    justify-content: center;
    align-items: flex-end;
    gap: 8px;
    margin-bottom: 15px;
    padding: 0 10px;
}

.podium-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1;
    max-width: 110px;
}

.podium-rank {
    font-size: 1.8em;
    margin-bottom: 8px;
}

.podium-avatar {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: linear-gradient(135deg, #6496f3, #1044ee);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 1em;
    color: #fff;
    margin-bottom: 8px;
    border: 2px solid #f0c05a;
    box-shadow: 0 4px 10px rgba(159, 54, 241, 0.3);
}

.podium-avatar-winner {
    width: 60px;
    height: 60px;
    font-size: 1.2em;
    animation: winner-glow 2s ease-in-out infinite;
}

@keyframes winner-glow {
    0%, 100% { box-shadow: 0 4px 10px rgba(240, 192, 90, 0.5); }
    50% { box-shadow: 0 6px 20px rgba(240, 192, 90, 0.8); }
}

.podium-name {
    font-family: 'Cinzel', serif;
    font-size: 0.75em;
    color: #e0e0ff;
    margin-bottom: 5px;
    font-weight: 600;
    text-align: center;
}

.podium-score {
    font-size: 0.7em;
    color: #f0c05a;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    gap: 5px;
    font-weight: 600;
}

.currency-icon-small {
    width: 17px;
    height: 17px;
    vertical-align: middle;
}

.podium-base {
    width: 100%;
    background: linear-gradient(180deg, #9f36f1, #7b2cbf);
    border-radius: 8px 8px 0 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Cinzel', serif;
    font-size: 1.2em;
    font-weight: 700;
    color: #fff;
    border: 2px solid #f0c05a;
    border-bottom: none;
}

.podium-base-first {
    height: 80px;
    background: linear-gradient(180deg, #f0c05a, #d4a849);
}

.podium-base-second {
    height: 60px;
    background: linear-gradient(180deg, #c0c0c0, #a8a8a8);
}

.podium-base-third {
    height: 40px;
    background: linear-gradient(180deg, #cd7f32, #b87333);
}

.podium-first { order: 2; }
.podium-second { order: 1; }
.podium-third { order: 3; }

.leaderboard-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.leaderboard-item {
    display: flex;
    align-items: center;
    gap: 12px;
    background: rgba(28, 17, 41, 0.6);
    padding: 5px;
    border-radius: 10px;
    border: 1px solid rgba(240, 192, 90, 0.2);
    transition: all 0.2s ease;
}

.leaderboard-item:hover {
    background: rgba(28, 17, 41, 0.9);
    border-color: rgba(240, 192, 90, 0.5);
    transform: translateX(3px);
}

.leaderboard-item-you {
    background: rgba(159, 54, 241, 0.2);
    border: 2px solid #9f36f1;
}

.leaderboard-position {
    font-family: 'Cinzel', serif;
    font-size: 1em;
    font-weight: 700;
    color: #f0c05a;
    min-width: 25px;
    text-align: center;
}

.leaderboard-player {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
}

.leaderboard-avatar {
    width: 35px;
    height: 35px;
    border-radius: 50%;
    background: linear-gradient(135deg, #9f36f1, #7b2cbf);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Cinzel', serif;
    font-weight: 700;
    font-size: 0.75em;
    color: #fff;
    border: 1px solid #f0c05a;
}

.leaderboard-name {
    font-size: 0.85em;
    color: #e0e0ff;
    font-weight: 500;
}

.leaderboard-score {
    font-size: 0.8em;
    color: #f0c05a;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}

.leaderboard-info {
    background: rgba(159, 54, 241, 0.15);
    border: 1px solid rgba(159, 54, 241, 0.4);
    border-radius: 10px;
    padding: 12px;
    margin-top: 15px;
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.leaderboard-info i {
    color: #9f36f1;
    font-size: 1.2em;
    margin-top: 2px;
    flex-shrink: 0;
}

.leaderboard-info p {
    font-size: 0.8em;
    color: #e0e0ff;
    line-height: 1.5;
    margin: 0;
}

.referral-header {
    text-align: center;
    margin-bottom: 20px;
}

.referral-gift-icon {
    font-size: 2.5em;
    color: #f0c05a;
    margin-bottom: 10px;
    filter: drop-shadow(0 0 10px rgba(240, 192, 90, 0.5));
}

.referral-title {
    font-family: 'Cinzel', serif;
    font-size: 1.5em;
    color: #f0c05a;
    margin-bottom: 5px;
    font-weight: 700;
}

.referral-subtitle {
    font-size: 0.9em;
    color: #e0e0ff;
    opacity: 0.9;
    font-weight: 500;
}

.referral-stats {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.referral-stat-box {
    flex: 1;
    background: linear-gradient(135deg, rgba(159, 54, 241, 0.2), rgba(123, 44, 191, 0.2));
    border: 2px solid #9f36f1;
    border-radius: 12px;
    padding: 15px;
    text-align: center;
    box-shadow: 0 4px 15px rgba(159, 54, 241, 0.2);
}


.stat-number {
    font-family: 'Cinzel', serif;
    font-size: 1.8em;
    color: #f0c05a;
    font-weight: 700;
    margin-bottom: 5px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
}

.stat-label {
    font-size: 0.75em;
    color: #e0e0ff;
    opacity: 0.8;
}

.referral-link-section {
    margin-bottom: 15px;
}

.referral-link-title {
    font-family: 'Cinzel', serif;
    font-size: 0.85em;
    color: #f0c05a;
    margin-bottom: 8px;
    text-align: center;
}

.referral-link-container {
    background: #0d0e12;
    padding: 12px;
    border-radius: 8px;
    border: 2px solid #9f36f1;
    font-size: 0.75em;
    color: #e0e0ff;
    display: flex;
    align-items: center;
    gap: 8px;
    box-shadow: 0 0 15px rgba(159, 54, 241, 0.2);
}

.referral-link-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
}

.share-button {
    background: linear-gradient(135deg, #9f36f1, #7b2cbf);
    color: #e0e0ff;
    padding: 12px 20px;
    font-family: 'Cinzel', serif;
    font-size: 0.95em;
    font-weight: 700;
    border: none;
    border-radius: 10px;
    cursor: pointer;
    width: 100%;
    transition: all 0.3s ease;
    text-transform: uppercase;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-bottom: 20px;
    box-shadow: 0 4px 15px rgba(159, 54, 241, 0.3);
}

.share-button i {
    font-size: 1.2em;
    color: #f0c05a;
}

.share-button:hover {
    background: linear-gradient(135deg, #7b2cbf, #9f36f1);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(159, 54, 241, 0.4);
}

.share-button:active {
    transform: translateY(0px);
}

.referral-info-box {
    background: rgba(159, 54, 241, 0.15);
    border: 1px solid rgba(159, 54, 241, 0.4);
    border-radius: 10px;
    padding: 15px;
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.referral-info-box i {
    color: #9f36f1;
    font-size: 1.2em;
    margin-top: 2px;
    flex-shrink: 0;
}

.referral-info-title {
    font-family: 'Cinzel', serif;
    font-size: 0.85em;
    color: #f0c05a;
    margin-bottom: 8px;
    font-weight: 700;
}

.referral-info-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.referral-info-list li {
    font-size: 0.75em;
    color: #e0e0ff;
    line-height: 1.6;
    padding-left: 15px;
    position: relative;
    margin-bottom: 5px;
}

.referral-info-list li:before {
    content: "✓";
    position: absolute;
    left: 0;
    color: #f0c05a;
    font-weight: 700;
}

.telegram-nav {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: #1c1129;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    padding: 12px 0;
    border-top: 1px solid #f0c05a;
    z-index: 1000;
    height: 72px;
}

.telegram-nav-button {
    background: none;
    border: none;
    color: #e0e0ff;
    font-family: 'Cinzel', serif;
    font-size: 0.9em;
    font-weight: 400;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 12px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.telegram-nav-button i {
    font-size: 1.7em;
    color: #f0c05a;
}

.telegram-nav-button:hover, .telegram-nav-button.active {
    color: #f0c05a;
    transform: scale(1.1);
}

.telegram-nav-button:hover i, .telegram-nav-button.active i {
    color: #f0c05a;
}

.telegram-nav-button:active {
    transform: scale(0.95);
}

.deposit-withdraw-row {
    display: flex;
    gap: 10px;
    margin-bottom: 15px;
    margin-top: 15px; 
    justify-content: center;
}

.deposit-btn, .withdraw-btn {
    flex: 1;
    background: linear-gradient(135deg, #1c1129, #2a1b3e);
    color: #e0e0ff;
    padding: 12px;
    font-family: 'Cinzel', serif;
    font-size: 0.95em;
    font-weight: 700;
    border: 1px solid #f0c05a;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.2s ease, transform 0.2s ease;
    text-align: center;
    max-width: 140px;
    box-shadow: 0 4px 8px rgba(159, 54, 241, 0.2);
}

.deposit-btn.active, .withdraw-btn.active {
    background: linear-gradient(135deg, #9f36f1, #7b2cbf);
    color: #e0e0ff;
    box-shadow: 0 6px 12px rgba(159, 54, 241, 0.3);
}

.deposit-btn:hover, .withdraw-btn:hover {
    background: linear-gradient(135deg, #7b2cbf, #9f36f1);
    transform: scale(1.05);
    box-shadow: 0 6px 12px rgba(159, 54, 241, 0.3);
}

.deposit-btn:active, .withdraw-btn:active {
    transform: scale(0.95);
}

.currency-section {
    margin-bottom: 10px;
}

.currency-title {
    font-family: 'Cinzel', serif;
    font-size: 0.85em;
    color: #f0c05a;
    margin-bottom: 8px;
}

.currency-item {
    display: flex;
    align-items: center;
    gap: 8px;
    background: #0d0e12;
    padding: 10px;
    border-radius: 8px;
    border: 1px solid #f0c05a;
    justify-content: center;
}

.currency-name {
    font-size: 0.9em;
    color: #e0e0ff;
}

.currency-icon {
    width: 18px;
    height: 18px;
    vertical-align: middle;
}

.qr-section {
    text-align: center;
    margin-bottom: 15px;
}

.qr-code {
    width: 120px;
    height: 120px;
    border-radius: 8px;
    margin: 0 auto 8px;
    filter: drop-shadow(0 0 5px rgba(159, 54, 241, 0.3));
}

.qr-label {
    font-size: 0.75em;
    color: #e0e0ff;
    opacity: 0.8;
}

.address-section {
    margin-bottom: 15px;
}

.address-container {
    background: #0d0e12;
    padding: 10px;
    border-radius: 8px;
    border: 1px solid #f0c05a;
    font-size: 0.8em;
    color: #e0e0ff;
    display: flex;
    align-items: center;
    gap: 5px;
}

.address-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: calc(100% - 25px);
}

.copy-icon {
    font-size: 0.9em;
    color: #f0c05a;
    cursor: pointer;
    transition: filter 0.2s;
}

.copy-icon:hover {
    filter: brightness(70%);
}

.withdrawal-section {
    margin-bottom: 15px;
}

.min-withdraw-note {
    font-size: 0.75em;
    color: #e0e0ff;
    margin-bottom: 10px;
    opacity: 0.8;
}

.withdrawal-input {
    width: 100%;
    background: #0d0e12;
    padding: 10px;
    border-radius: 8px;
    border: 1px solid #f0c05a;
    font-size: 0.8em;
    color: #e0e0ff;
    margin-bottom: 0px;
}

.withdrawal-input:focus {
    outline: none;
    border-color: #9f36f1;
}

.error-message {
    color: #ff4d4d;
    font-size: 0.7em;
    margin-top: 2px;
    margin-bottom: 6px;
    min-height: 1em;
    text-align: center;
}

.max-button {
    background: #0d0e12;
    color: #f0c05a;
    padding: 2px 10px;
    height: 35px;
    font-size: 0.85em;
    font-weight: 500;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.2s ease, transform 0.2s ease;
    margin-top: 1px; /* Added margin to move the button down */
}

.max-button:hover {
    background: #7b2cbf;
    transform: scale(1.05);
}

.max-button:active {
    transform: scale(0.95);
}

.withdraw-submit, .deposit-submit {
    background: #9f36f1;
    color: #e0e0ff;
    padding: 10px;
    font-family: 'Cinzel', serif;
    font-size: 0.9em;
    font-weight: 700;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    width: 100%;
    transition: all 0.2s ease, transform 0.2s ease;
    text-transform: uppercase;
}

.withdraw-submit:hover, .deposit-submit:hover {
    background: #7b2cbf;
    transform: scale(1.05);
}

.withdraw-submit:active, .deposit-submit:active {
    transform: scale(0.95);
}

.deposit-warning {
    font-size: 0.75em;
    color: #e0e0ff;
    text-align: center;
    margin-top: 10px;
    line-height: 1.5;
    opacity: 0.9;
}

.stars-deposit-section {
    margin-top: 20px;
}

.stars-info {
    background: rgba(159, 54, 241, 0.15);
    border: 1px solid rgba(159, 54, 241, 0.4);
    border-radius: 10px;
    padding: 12px;
    margin-bottom: 15px;
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.stars-info i {
    color: #9f36f1;
    font-size: 1.2em;
    margin-top: 2px;
    flex-shrink: 0;
}

.stars-info p {
    font-size: 0.8em;
    color: #e0e0ff;
    line-height: 1.5;
    margin: 0;
}

.deposit-amount-container {
    display: flex;
    flex-direction: column;
    gap: 15px;
}

.deposit-input-wrapper {
    position: relative;
    display: flex;
    align-items: center;
    background: #0d0e12;
    border: 2px solid #f0c05a;
    border-radius: 12px;
    padding: 10px;
    box-shadow: 0 0 20px rgba(240, 192, 90, 0.2);
    transition: all 0.3s ease;
}

.deposit-input-wrapper:focus-within {
    border-color: #9f36f1;
    box-shadow: 0 0 25px rgba(159, 54, 241, 0.4);
}

.deposit-star-icon {
    font-size: 1.5em;
    color: #f0c05a;
    margin-right: 12px;
    filter: drop-shadow(0 0 8px rgba(240, 192, 90, 0.6));
}

.deposit-amount-input {
    flex: 1;
    background: transparent;
    border: none;
    color: #e0e0ff;
    font-family: 'Cinzel', serif;
    font-size: 1.2em;
    font-weight: 700;
    outline: none;
    padding: 0;
}

.deposit-amount-input::placeholder {
    color: rgba(224, 224, 255, 0.4);
    font-weight: 400;
}

.deposit-amount-input::-webkit-outer-spin-button,
.deposit-amount-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.deposit-amount-input[type=number] {
    -moz-appearance: textfield;
}

.deposit-unit {
    font-family: 'Cinzel', serif;
    font-size: 1em;
    color: #f0c05a;
    font-weight: 600;
    margin-left: 8px;
    margin-right: 5px;
}

.deposit-quick-amounts {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}
@media (max-width: 275px) {
    .deposit-quick-amounts {
        display: grid;
        grid-template-columns: repeat(1, 1fr);
        gap: 10px;
    }
}

.footer a {
    color: #fff;
}

.quick-amount-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    white-space: nowrap; /* keep star and number on one line */
    background: linear-gradient(135deg, rgba(28, 17, 41, 0.8), rgba(42, 27, 62, 0.8));
    border: 2px solid rgba(240, 192, 90, 0.4);
    border-radius: 10px;
    padding: 8px 12px;
    font-family: 'Cinzel', serif;
    font-size: 0.95em;
    font-weight: 600;
    color: #e0e0ff;
    cursor: pointer;
    transition: all 0.3s ease;
}

.quick-amount-btn {
    display: flex;
    align-items: center; /* Center items vertically */
}

.quick-amount-btn:before {
    content: "⭐";
    font-size: 1.1em;
}

.quick-amount-btn:hover {
    background: linear-gradient(135deg, rgba(159, 54, 241, 0.3), rgba(123, 44, 191, 0.3));
    border-color: #9f36f1;
    transform: translateY(-2px);
    box-shadow: 0 4px 15px rgba(159, 54, 241, 0.3);
}

.quick-amount-btn:active {
    transform: translateY(0);
}

.deposit-submit {
    background: linear-gradient(135deg, #9f36f1, #7b2cbf);
    color: #e0e0ff;
    padding: 12px 20px;
    font-family: 'Cinzel', serif;
    font-size: 1em;
    font-weight: 700;
    border: none;
    border-radius: 12px;
    cursor: pointer;
    width: 100%;
    transition: all 0.3s ease;
    text-transform: uppercase;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    box-shadow: 0 4px 15px rgba(159, 54, 241, 0.3);
}

.deposit-submit i {
    font-size: 1.2em;
    color: #f0c05a;
}

.deposit-submit:hover {
    background: linear-gradient(135deg, #7b2cbf, #9f36f1);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(159, 54, 241, 0.4);
}

.deposit-submit:active {
    transform: translateY(0);
}

.stars-packages {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.star-package-btn {
    background: linear-gradient(135deg, rgba(28, 17, 41, 0.8), rgba(42, 27, 62, 0.8));
    border: 2px solid #f0c05a;
    border-radius: 12px;
    padding: 15px 20px;
    display: flex;
    align-items: center;
    gap: 15px;
    cursor: pointer;
    transition: all 0.3s ease;
    position: relative;
    overflow: hidden;
}

.star-package-btn:hover {
    background: linear-gradient(135deg, rgba(159, 54, 241, 0.3), rgba(123, 44, 191, 0.3));
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(240, 192, 90, 0.4);
}

.star-package-btn:active {
    transform: translateY(0);
}

.star-package-btn.featured {
    border-color: #9f36f1;
    background: linear-gradient(135deg, rgba(159, 54, 241, 0.2), rgba(123, 44, 191, 0.2));
    box-shadow: 0 4px 15px rgba(159, 54, 241, 0.3);
}

.star-package-btn.featured:hover {
    box-shadow: 0 6px 25px rgba(159, 54, 241, 0.5);
}

.popular-badge {
    position: absolute;
    top: -1px;
    right: 15px;
    background: linear-gradient(135deg, #9f36f1, #7b2cbf);
    color: #fff;
    font-size: 0.65em;
    font-weight: 700;
    padding: 4px 12px;
    border-radius: 0 0 8px 8px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    box-shadow: 0 2px 8px rgba(159, 54, 241, 0.4);
}

.star-package-btn i {
    font-size: 2em;
    color: #f0c05a;
    filter: drop-shadow(0 0 8px rgba(240, 192, 90, 0.6));
}

.star-package-btn .star-amount {
    font-family: 'Cinzel', serif;
    font-size: 1.1em;
    color: #e0e0ff;
    font-weight: 700;
    flex: 1;
}

.star-package-btn .star-bonus {
    font-size: 0.9em;
    color: #f0c05a;
    font-weight: 600;
    background: rgba(240, 192, 90, 0.1);
    padding: 5px 12px;
    border-radius: 6px;
    border: 1px solid rgba(240, 192, 90, 0.3);
}

.withdrawal-status {
    background: rgba(159, 54, 241, 0.15);
    border: 2px solid rgba(159, 54, 241, 0.5);
    border-radius: 10px;
    padding: 15px;
    margin-top: 20px;
    text-align: center;
}

.withdrawal-status i {
    color: #f0c05a;
    font-size: 2em;
    margin-bottom: 10px;
    display: block;
    animation: pulse-icon 2s ease-in-out infinite;
}

@keyframes pulse-icon {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

.withdrawal-status p {
    font-size: 0.85em;
    color: #e0e0ff;
    margin: 5px 0;
    line-height: 1.5;
}

.withdrawal-status p strong {
    color: #f0c05a;
    font-family: 'Cinzel', serif;
    font-size: 1.1em;
    display: block;
    margin-bottom: 8px;
}

.withdrawal-input {
    width: 100%;
    background: #0d0e12;
    padding: 10px;
    border-radius: 8px;
    border: 1px solid #f0c05a;
    font-size: 0.8em;
    color: #e0e0ff;
    margin-bottom: 8px;
}

.withdrawal-input:focus {
    outline: none;
    border-color: #9f36f1;
}

.withdrawal-input:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.profile-header {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-bottom: 10px;
    justify-content: center;
    background-color: #9f36f12c;
    padding: 10px;
    border-radius: 10px;
    border: 3px solid #190a25;
}

.profile-avatar {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    border: 1px solid #f0c05a;
    filter: drop-shadow(0 0 5px rgba(159, 54, 241, 0.3));
}

.profile-info h3 {
    font-family: 'Cinzel', serif;
    font-size: 1.2em;
    color: #f0c05a;
    margin-bottom: 8px;
    text-align: center;
}

.profile-info p {
    font-size: 0.9em;
    color: #e0e0ff;
    margin: 5px 0;
    opacity: 0.8;
    text-align: center;
}

.profile-details {
    text-align: center;
}

.language-selector select {
    background: #0d0e12;
    color: #e0e0ff;
    padding: 8px;
    border: 1px solid #f0c05a;
    border-radius: 8px;
    font-size: 1em;
    width: 100%;
    height: 55px;
    cursor: pointer;
    display: block;
    /* margin-top: 15px;
    margin-bottom: 15px; */
}
.gameSettings {
    margin-top: 10px;
    display: flex;
    gap: 10px;
    /* margin-bottom: 20px; */
}
.gameSettings .profile-section {
    width: 100%;
}
.language-selector {
    width: 100%;
}
.language-selector select:focus {
    outline: none;
    border-color: #9f36f1;
}

.privacy-policy {
    color: #9f36f1;
    font-size: 0.8em;
    text-decoration: none;
    font-weight: 500;
    display: block;
    margin: 0 auto;
    width: fit-content;
    margin-bottom: 0px;
    margin-top: 10px;
}

.privacy-policy:hover {
    text-decoration: underline;
}
/* Add these styles to your style.css file */

.profile-section {
    background: rgba(28, 17, 41, 0.6);
    border: 1px solid rgba(240, 192, 90, 0.3);
    border-radius: 8px;
    padding: 8px;
    margin-bottom: 8px;
}

.profile-setting-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.setting-label {
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: 'Cinzel', serif;
    font-size: 1.2em; /* already bigger */
    color: #e0e0ff;
    white-space: nowrap; /* prevents line breaks */
}

.setting-label i {
    color: #f0c05a;
    font-size: 1em;
}

.music-toggle-btn .music-status {
    display: block;
}

.music-toggle-btn i {
    margin: 0;
}

.music-toggle-btn {
    display: flex;
    align-items: center;
    background: linear-gradient(135deg, #1c1129, #2a1b3e);
    border: 2px solid #f0c05a;
    border-radius: 25px;
    padding: 8px 16px;
    font-family: 'Cinzel', serif;
    font-size: 0.85em;
    font-weight: 700;
    color: #e0e0ff;
    transition: all 0.3s ease;
    min-width: 40px;
    width: 40px;
    justify-content: center;
    float: right;
}

.music-toggle-btn i {
    font-size: 1.1em;
    color: #f0c05a;
    transition: all 0.3s ease;
}

.music-toggle-btn.active {
    background: linear-gradient(135deg, #9f36f1, #7b2cbf);
    border-color: #9f36f1;
    box-shadow: 0 0 15px rgba(159, 54, 241, 0.4);
}

.music-toggle-btn.active i {
    color: #f0c05a;
    animation: music-pulse 1.5s ease-in-out infinite;
}

.music-toggle-btn:hover {
    transform: scale(1.05);
    box-shadow: 0 4px 12px rgba(159, 54, 241, 0.3);
}

.music-toggle-btn:active {
    transform: scale(0.95);
}

.music-status {
    font-weight: 700;
    letter-spacing: 0.5px;
}

@keyframes music-pulse {
    0%, 100% {
        transform: scale(1);
        opacity: 1;
    }
    50% {
        transform: scale(1.2);
        opacity: 0.8;
    }
}

.footer {
    font-size: 0.75em;
    color: #e0e0ff;
    text-align: center;
    margin-top: 5px;
    margin-bottom: 0px;
    opacity: 0.8;
}

.footer img {
    width: 50%;
    max-height: 100px;
    object-fit: contain;
    border-radius: 8px;
    margin-top: 10px;
    filter: drop-shadow(0 0 5px rgba(159, 54, 241, 0.3));
}

.btnCombo {
    display: flex;
    flex-wrap: nowrap;
    gap: 10px;
}

@media (max-width: 360px) {
    body {
        padding: calc(10px + env(safe-area-inset-top)) 8px calc(70px + env(safe-area-inset-bottom));
    }

    .casino-container.fullscreen {
        margin-top: calc(35px + env(safe-area-inset-top));
    }

    .character-image, .footer img {
        max-height: 80px;
    }

    .reel-container {
        height: 180px;
    }

    .symbol {
        height: 60px;
    }

    .symbol img {
        width: 45px;
        height: 45px;
    }

    .telegram-nav {
        height: 60px;
        padding: 10px 0;
        gap: 10px;
    }

    .telegram-nav-button {
        font-size: 0.85em;
        padding: 8px;
        flex: 1;
        max-width: 60px;
    }

    .telegram-nav-button i {
        font-size: 1.4em;
    }

    .deposit-btn, .withdraw-btn {
        font-size: 0.8em;
        padding: 8px;
        max-width: 120px;
    }

    .qr-code {
        width: 100px;
        height: 100px;
    }

    .info-box h3 {
        font-size: 0.7em;
    }

    .info-box .value {
        font-size: 0.9em;
    }

    .slot-machine {
        padding: 8px;
    }

   .max-bet-button {
        padding: 4px 8px;
        font-size: 0.7em;
    }

    .ok-button {
        padding: 7px;
        font-size: 0.8em;
    }

    .referral-gift-icon {
        font-size: 2.5em;
    }

    .referral-title {
        font-size: 1.3em;
    }

    .referral-subtitle {
        font-size: 0.85em;
    }

    .stat-number {
        font-size: 1.5em;
    }

    .stat-label {
        font-size: 0.7em;
    }

    .share-button {
        font-size: 0.85em;
        padding: 10px 16px;
    }

    .referral-info-list li {
        font-size: 0.7em;
    }

    .deposit-warning {
        font-size: 0.7em;
    }
}

@media (max-width: 320px) {
    body {
        padding: calc(8px + env(safe-area-inset-top)) 6px calc(60px + env(safe-area-inset-bottom));
    }

    .casino-container.fullscreen {
        margin-top: calc(30px + env(safe-area-inset-top));
    }

    .character-image, .footer img {
        max-height: 70px;
    }

    .reel-container {
        height: 150px;
    }

    .symbol {
        height: 50px;
    }

    .symbol img {
        width: 35px;
        height: 35px;
    }

    .telegram-nav {
        height: 60px;
        padding: 8px 0;
        gap: 8px;
    }

    .telegram-nav-button {
        font-size: 0.8em;
        padding: 6px;
        flex: 1;
        max-width: 55px;
    }

    .telegram-nav-button i {
        font-size: 1.3em;
    }

    .deposit-btn, .withdraw-btn {
        font-size: 0.75em;
        padding: 6px;
        max-width: 110px;
    }

    .qr-code {
        width: 90px;
        height: 90px;
    }

    .info-box h3 {
        font-size: 0.65em;
    }

    .info-box .value {
        font-size: 0.85em;
    }

    .slot-machine {
        padding: 6px;
    }

    .max-bet-button {
        padding: 4px 8px;
        font-size: 0.7em;
    }

    .ok-button {
        padding: 7px;
        font-size: 0.8em;
    }

    .referral-gift-icon {
        font-size: 2.2em;
    }

    .referral-title  { 
        font-size: 1.2em;
    }

    .referral-subtitle {
        font-size: 0.8em;
    }

    .stat-number {
        font-size: 1.3em;
    }

    .stat-label {
        font-size: 0.65em;
    }

    .share-button {
        font-size: 0.8em;
        padding: 10px 14px;
    }

    .referral-info-list li {
        font-size: 0.65em;
    }

    .deposit-warning {
        font-size: 0.65em;
    }
}
Download .txt
gitextract_to00y2ya/

├── .gitattributes
├── .gitignore
├── README.md
├── config.js
├── index.html
├── main.js
├── main.py
├── promocodes.js
├── requirements.txt
├── spooky.m4a
└── style.css
Download .txt
SYMBOL INDEX (65 symbols across 3 files)

FILE: main.js
  constant RTP_CONFIG (line 11) | const RTP_CONFIG = {
  constant MIN_WITHDRAW (line 49) | const MIN_WITHDRAW = 2000;
  constant TRANSACTION_COOLDOWN (line 50) | const TRANSACTION_COOLDOWN = 6 * 60 * 60 * 1000;
  constant REFERRAL_BONUS_REFERRER (line 51) | const REFERRAL_BONUS_REFERRER = 15.0;
  constant REFERRAL_BONUS_NEW_USER (line 52) | const REFERRAL_BONUS_NEW_USER = 15.0;
  constant SPECIAL_REFERRAL_CODE (line 53) | const SPECIAL_REFERRAL_CODE = "dhs92bfjdjdsdf";
  constant SPECIAL_REFERRAL_BONUS (line 54) | const SPECIAL_REFERRAL_BONUS = 100.0;
  constant SYMBOL_HEIGHT (line 71) | let SYMBOL_HEIGHT = 70;
  constant VISIBLE_LINES (line 72) | const VISIBLE_LINES = 3;
  constant CENTER_INDEX (line 73) | const CENTER_INDEX = 10;
  function sendTelegramNotification (line 148) | async function sendTelegramNotification(withdrawalData) {
  function calculateCurrentRTP (line 199) | function calculateCurrentRTP() {
  function shouldTriggerWin (line 204) | function shouldTriggerWin() {
  function determineWinType (line 222) | function determineWinType() {
  function generateWeightedSymbol (line 245) | function generateWeightedSymbol(forceWin = false, winType = 'medium') {
  function generateSmartReelResult (line 278) | function generateSmartReelResult(shouldWin, winType) {
  function generateReferralLink (line 342) | function generateReferralLink(userId) {
  function getReferrerFromURL (line 346) | function getReferrerFromURL() {
  function processReferral (line 435) | async function processReferral(newUserId, referralData) {
  function loadReferralInfo (line 607) | async function loadReferralInfo(userId) {
  function shareReferralLink (line 631) | function shareReferralLink() {
  function createUserInFirebase (line 660) | async function createUserInFirebase(userId, userData) {
  function loadUserFromFirebase (line 688) | async function loadUserFromFirebase(userId) {
  function updateBalanceInFirebase (line 716) | async function updateBalanceInFirebase(userId, newBalance) {
  function addTransactionToFirebase (line 733) | async function addTransactionToFirebase(userId, transaction) {
  function saveWithdrawalRequest (line 757) | async function saveWithdrawalRequest(userId, withdrawalData) {
  function redeemPromocode (line 782) | async function redeemPromocode(userId, code) {
  function handlePromocodeSubmit (line 926) | async function handlePromocodeSubmit() {
  function initUser (line 982) | async function initUser() {
  function initializeGame (line 1097) | function initializeGame() {
  function updateBalanceDisplay (line 1112) | function updateBalanceDisplay() {
  function updateBetDisplay (line 1121) | function updateBetDisplay() {
  function updateProfileDisplay (line 1131) | function updateProfileDisplay() {
  function copyText (line 1148) | function copyText(element, text) {
  function hasTransactedInLast6Hours (line 1159) | function hasTransactedInLast6Hours() {
  function getTimeRemainingFormatted (line 1172) | function getTimeRemainingFormatted() {
  function updateSymbolHeight (line 1191) | function updateSymbolHeight() {
  function showError (line 1198) | function showError(message) {
  function showSuccess (line 1208) | function showSuccess(message) {
  function handleStarsDeposit (line 1221) | async function handleStarsDeposit(stars) {
  function creditStarsBalance (line 1284) | async function creditStarsBalance(stars) {
  function loadDeposit (line 1315) | function loadDeposit() {
  function loadWithdraw (line 1399) | function loadWithdraw() {
  function handleWithdrawSubmit (line 1475) | async function handleWithdrawSubmit() {
  function generateReelSymbols (line 1560) | function generateReelSymbols() {
  function createReelHTML (line 1568) | function createReelHTML(reelSymbols) {
  function toggleBetSettingsModal (line 1572) | function toggleBetSettingsModal() {
  function toggleAutoSettingsModal (line 1578) | function toggleAutoSettingsModal() {
  function togglePaytableModal (line 1585) | function togglePaytableModal() {
  function updateAutoSettingsState (line 1590) | function updateAutoSettingsState() {
  function spinReels (line 1601) | async function spinReels() {
  function checkWin (line 1677) | async function checkWin(reelResults) {
  function lockButtons (line 1756) | function lockButtons() {
  function unlockButtons (line 1773) | function unlockButtons() {
  function initBackgroundMusic (line 1846) | function initBackgroundMusic() {
  function toggleBackgroundMusic (line 1919) | function toggleBackgroundMusic() {
  function updateMusicButtonState (line 1940) | function updateMusicButtonState() {

FILE: main.py
  function start (line 24) | async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
  function help_command (line 82) | async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
  function precheckout_callback (line 96) | async def precheckout_callback(update: Update, context: ContextTypes.DEF...
  function successful_payment (line 101) | async def successful_payment(update: Update, context: ContextTypes.DEFAU...
  function main (line 114) | def main():

FILE: promocodes.js
  constant PROMOCODES (line 1) | const PROMOCODES = [
  function addPromocode (line 43) | function addPromocode(code, stars, maxUses, expiresAt = null) {
  function deactivatePromocode (line 61) | function deactivatePromocode(code) {
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (152K chars).
[
  {
    "path": ".gitattributes",
    "chars": 66,
    "preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".gitignore",
    "chars": 11,
    "preview": "spooky.mp4\n"
  },
  {
    "path": "README.md",
    "chars": 1813,
    "preview": "# 🧙‍♂️ Blessed Wizard\n\n**Blessed Wizard** is a **Telegram Mini App slot machine game** combined with a **Python Telegram"
  },
  {
    "path": "config.js",
    "chars": 210,
    "preview": "// Firebase Configuration\nexport const firebaseConfig = {\n  apiKey: \"###\",\n  authDomain: \"###\",\n  projectId: \"###\",\n  st"
  },
  {
    "path": "index.html",
    "chars": 17438,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width"
  },
  {
    "path": "main.js",
    "chars": 76199,
    "preview": "import { firebaseConfig, TELEGRAM_BOT_TOKEN, TELEGRAM_GROUP_CHAT_ID, BOT_USERNAME } from './config.js';\nimport { PROMOCO"
  },
  {
    "path": "main.py",
    "chars": 4595,
    "preview": "# Lucky Wizard Bot - FIXED Referral System\n# Install: pip install python-telegram-bot==20.7\n\nfrom telegram import Update"
  },
  {
    "path": "promocodes.js",
    "chars": 1769,
    "preview": "export const PROMOCODES = [\n    {\n        code: \"WELCOME100\",\n        stars: 100,\n        maxUses: 99999,\n        curren"
  },
  {
    "path": "requirements.txt",
    "chars": 162,
    "preview": "# requirements.txt\n# Python requirements for Lucky Wizard / Blessed Wizard Telegram Bot\n\npython-telegram-bot==20.7\n\n# Op"
  },
  {
    "path": "style.css",
    "chars": 42531,
    "preview": "* {\n    margin: 0;\n    padding: 0;\n    box-sizing: border-box;\n    user-select: none;\n    font-family: \"Cinzel\";\n}\n\nbody"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the hhaayykk/BlessedWizard GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (141.4 KB), approximately 38.9k tokens, and a symbol index with 65 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!