Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', function() { | |
| initHeader(); | |
| initCasinoCards(); | |
| initAnimations(); | |
| initSearch(); | |
| initSmoothScroll(); | |
| initScrollEffects(); | |
| }); | |
| document.addEventListener('click', e => { | |
| const a = e.target.closest('a[href="#"]'); | |
| if (a) { | |
| e.preventDefault(); | |
| } | |
| }); | |
| const casinos = [ | |
| { | |
| id: 1, | |
| name: '7K CASINO', | |
| url: 'https://match-sevenkpartnerstraffic.com/l/6974c388bffefb2c5f06d6f2', | |
| logo: '⭐', | |
| rating: 4.8, | |
| reviews: 3120, | |
| bonus: '100% до 150 000 ₽', | |
| freeSpins: 500, | |
| minDeposit: '100 ₽', | |
| payoutSpeed: '30 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto', 'mobile'], | |
| features: ['5000+ игр', 'Live казино', 'Мобильное приложение'], | |
| badge: 'Популярное', | |
| badgeColor: 'primary' | |
| }, | |
| { | |
| id: 2, | |
| name: 'BEEF CASINO', | |
| url: 'https://beef-way-three.com/c39e458e3', | |
| logo: '🪙', | |
| rating: 4.9, | |
| reviews: 2780, | |
| bonus: '100% до 200 000 ₽', | |
| freeSpins: 180, | |
| minDeposit: '1000 ₽', | |
| payoutSpeed: '10 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'crypto'], | |
| features: ['Криптовалюта', 'Мгновенные выплаты', 'VIP программа'], | |
| badge: 'Лучший выбор', | |
| badgeColor: 'primary' | |
| }, | |
| { | |
| id: 3, | |
| name: 'MARTIN CASINO', | |
| url: 'https://martin-route-six.com/c73a1ed3a', | |
| logo: '⚡', | |
| rating: 4.8, | |
| reviews: 980, | |
| bonus: '100% до 100 000 ₽', | |
| freeSpins: 150, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '5 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Самые быстрые выплаты', 'Без комиссии', 'High rollers'], | |
| badge: 'Хит', | |
| badgeColor: 'secondary' | |
| }, | |
| { | |
| id: 4, | |
| name: 'FLAGMAN CASINO', | |
| url: 'https://flagman-way-four.com/c587a2df9', | |
| logo: '☀️', | |
| rating: 4.5, | |
| reviews: 210, | |
| bonus: '100% до 200 000 ₽', | |
| freeSpins: 200, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '20 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['crypto'], | |
| features: ['Solana сеть', 'Low fees', 'NFT коллекции'], | |
| badge: 'NEW', | |
| badgeColor: 'success' | |
| }, | |
| { | |
| id: 5, | |
| name: 'AZINO777', | |
| url: 'https://l9p.bhf5727b0f.com/promo/click/68e911fe6b4fb', | |
| logo: '🎲', | |
| rating: 4.8, | |
| reviews: 1560, | |
| bonus: '100% до 200 000 ₽', | |
| freeSpins: 250, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '25 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Эксклюзивные игры', 'Быстрая верификация', '24/7 поддержка'], | |
| badge: 'Рекомендуем', | |
| badgeColor: 'secondary' | |
| }, | |
| { | |
| id: 6, | |
| name: 'PLAYFORTUNA', | |
| url: 'https://fortuna-promo1.net/alt/playfortuna/registration?c85a63b593552902626a0fccfd1b8a5c', | |
| logo: '🎰', | |
| rating: 4.9, | |
| reviews: 2450, | |
| bonus: '100% до 100 000 ₽', | |
| freeSpins: 200, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '15 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Мгновенные выплаты', 'Бонус на депозит', 'VIP программа'], | |
| badge: 'Топ', | |
| badgeColor: 'secondary' | |
| }, | |
| { | |
| id: 7, | |
| name: 'VAVADA CASINO', | |
| url: 'https://gate707.com/?promo=86859097-b30c-4ce6-931b-42f64c40b82e&target=register', | |
| logo: '💎', | |
| rating: 4.7, | |
| reviews: 1890, | |
| bonus: '100% до 100 000 ₽', | |
| freeSpins: 100, | |
| minDeposit: '300 ₽', | |
| payoutSpeed: '20 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Турниры', 'Кэшбэк 10%', 'Без верификации'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 8, | |
| name: 'RIOBET CASINO', | |
| url: 'https://tracker.referilink.com/link?btag=103028746_478044', | |
| logo: '🌴', | |
| rating: 4.6, | |
| reviews: 2100, | |
| bonus: '100% до 150 000 ₽', | |
| freeSpins: 200, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '30 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Турниры', 'VIP программа', 'Live чат'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 9, | |
| name: 'JOYCASINO', | |
| url: 'https://52199.call2me.pro/en/registration?partner=p52199p3326563pe729', | |
| logo: '😊', | |
| rating: 4.7, | |
| reviews: 3200, | |
| bonus: '200% до 100 000 ₽', | |
| freeSpins: 100, | |
| minDeposit: '100 ₽', | |
| payoutSpeed: '20 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Большой выбор слотов', 'Быстрые выплаты', 'Мобильная версия'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 10, | |
| name: 'IRWIN CASINO', | |
| url: 'https://irwinroute1.com/c40749c93', | |
| logo: '🎯', | |
| rating: 4.8, | |
| reviews: 890, | |
| bonus: '100% до 500 000 ₽', | |
| freeSpins: 400, | |
| minDeposit: '1000 ₽', | |
| payoutSpeed: '10 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'crypto'], | |
| features: ['Provably fair', 'Sports betting', 'Live streaming'], | |
| badge: 'HOT', | |
| badgeColor: 'warning' | |
| }, | |
| { | |
| id: 11, | |
| name: 'GIZBO CASINO', | |
| url: 'https://gzb-blcp10.com/c9e65f538', | |
| logo: '🎮', | |
| rating: 4.5, | |
| reviews: 1500, | |
| bonus: '100% до 150 000 ₽', | |
| freeSpins: 150, | |
| minDeposit: '300 ₽', | |
| payoutSpeed: '15 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Современный дизайн', 'Быстрая регистрация', 'Кэшбэк'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 12, | |
| name: 'LEX CASINO', | |
| url: 'https://lex-blcp10.com/c548a516d', | |
| logo: '🏛️', | |
| rating: 4.4, | |
| reviews: 1200, | |
| bonus: '100% до 100 000 ₽', | |
| freeSpins: 100, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '25 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Классические игры', 'Надежность', 'Поддержка 24/7'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 13, | |
| name: '1GO CASINO', | |
| url: 'https://1go-blcp10.com/cc4a4605e', | |
| logo: '🚀', | |
| rating: 4.6, | |
| reviews: 1800, | |
| bonus: '100% до 200 000 ₽', | |
| freeSpins: 200, | |
| minDeposit: '200 ₽', | |
| payoutSpeed: '10 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto', 'mobile'], | |
| features: ['Быстрые выплаты', 'Мобильная оптимизация', 'Турниры'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 14, | |
| name: 'MONRO CASINO', | |
| url: 'https://monroway1.com/cbbcc7331', | |
| logo: '💰', | |
| rating: 4.5, | |
| reviews: 1600, | |
| bonus: '100% до 150 000 ₽', | |
| freeSpins: 150, | |
| minDeposit: '300 ₽', | |
| payoutSpeed: '20 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Кэшбэк', 'VIP программа', 'Большой выбор игр'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 15, | |
| name: 'DRIP CASINO', | |
| url: 'https://drp-blcp10.com/caa284b8f', | |
| logo: '💧', | |
| rating: 4.3, | |
| reviews: 900, | |
| bonus: '100% до 100 000 ₽', | |
| freeSpins: 100, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '30 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Стильный дизайн', 'Бонусы', 'Удобный интерфейс'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 16, | |
| name: 'STARDA CASINO', | |
| url: 'https://strd-blcp21.com/cb4b05d78', | |
| logo: '⭐', | |
| rating: 4.4, | |
| reviews: 1300, | |
| bonus: '100% до 150 000 ₽', | |
| freeSpins: 150, | |
| minDeposit: '300 ₽', | |
| payoutSpeed: '25 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Космическая тематика', 'Турниры', 'Кэшбэк'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 17, | |
| name: 'LEGZO CASINO', | |
| url: 'https://gzo-blcp10.com/c402e3152', | |
| logo: '🎰', | |
| rating: 4.5, | |
| reviews: 1400, | |
| bonus: '100% до 200 000 ₽', | |
| freeSpins: 200, | |
| minDeposit: '200 ₽', | |
| payoutSpeed: '15 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Быстрые выплаты', 'Большой выбор слотов', 'VIP программа'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 18, | |
| name: 'VOLNA CASINO', | |
| url: 'https://vln-blcp10.com/c561979ce', | |
| logo: '🌊', | |
| rating: 4.6, | |
| reviews: 1700, | |
| bonus: '100% до 150 000 ₽', | |
| freeSpins: 150, | |
| minDeposit: '300 ₽', | |
| payoutSpeed: '20 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Морская тематика', 'Турниры', 'Кэшбэк'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 19, | |
| name: 'JET CASINO', | |
| url: 'https://jtb-emufrap.com/cdde45a17', | |
| logo: '✈️', | |
| rating: 4.7, | |
| reviews: 2000, | |
| bonus: '100% до 200 000 ₽', | |
| freeSpins: 200, | |
| minDeposit: '200 ₽', | |
| payoutSpeed: '10 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto', 'mobile'], | |
| features: ['Быстрые выплаты', 'Мобильная оптимизация', 'Турниры'], | |
| badge: null, | |
| badgeColor: null | |
| }, | |
| { | |
| id: 20, | |
| name: 'IZZI CASINO', | |
| url: 'https://izzi-bal03.com/c40ac99d4', | |
| logo: '🎨', | |
| rating: 4.4, | |
| reviews: 1100, | |
| bonus: '100% до 100 000 ₽', | |
| freeSpins: 100, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '25 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto'], | |
| features: ['Творческий подход', 'Бонусы', 'Удобный интерфейс'], | |
| badge: null, | |
| badgeColor: null | |
| } | |
| ]; | |
| const newCasinos = [ | |
| { | |
| id: 21, | |
| name: 'Beef', | |
| url: 'https://beef-way-three.com/c39e458e3', | |
| logo: '🔮', | |
| rating: 4.6, | |
| reviews: 320, | |
| bonus: '200% до 300 000 ₽', | |
| freeSpins: 350, | |
| minDeposit: '200 ₽', | |
| payoutSpeed: '10 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['crypto'], | |
| features: ['Только крипта', 'Анонимность', 'NFT бонусы'], | |
| badge: 'NEW', | |
| badgeColor: 'success' | |
| }, | |
| { | |
| id: 22, | |
| name: 'Martin', | |
| url: 'https://martin-route-six.com/c7ca1c5b1', | |
| logo: '🚀', | |
| rating: 4.7, | |
| reviews: 450, | |
| bonus: '150% до 250 000 ₽', | |
| freeSpins: 300, | |
| minDeposit: '300 ₽', | |
| payoutSpeed: '15 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'wallet', 'crypto', 'mobile'], | |
| features: ['VR казино', 'Social gaming', 'Гонки слотов'], | |
| badge: 'NEW', | |
| badgeColor: 'success' | |
| }, | |
| { | |
| id: 23, | |
| name: 'Flagman', | |
| url: 'https://flagman-way-four.com/c587a2df9', | |
| logo: '☀️', | |
| rating: 4.5, | |
| reviews: 210, | |
| bonus: '100% до 200 000 ₽', | |
| freeSpins: 200, | |
| minDeposit: '500 ₽', | |
| payoutSpeed: '20 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['crypto'], | |
| features: ['Solana сеть', 'Low fees', 'NFT коллекции'], | |
| badge: 'NEW', | |
| badgeColor: 'success' | |
| }, | |
| { | |
| id: 24, | |
| name: 'Irwin', | |
| url: 'https://irwinroute1.com/ce0e89171', | |
| logo: '🎯', | |
| rating: 4.8, | |
| reviews: 890, | |
| bonus: '100% до 500 000 ₽', | |
| freeSpins: 400, | |
| minDeposit: '1000 ₽', | |
| payoutSpeed: '10 мин', | |
| license: 'Curacao', | |
| paymentMethods: ['card', 'crypto'], | |
| features: ['Provably fair', 'Sports betting', 'Live streaming'], | |
| badge: 'HOT', | |
| badgeColor: 'warning' | |
| } | |
| ]; | |
| function initHeader() { | |
| const header = document.querySelector('header'); | |
| let lastScroll = 0; | |
| window.addEventListener('scroll', () => { | |
| const currentScroll = window.pageYOffset; | |
| if (currentScroll > 100) { | |
| header.classList.add('bg-gray-950/95', 'backdrop-blur-lg', 'shadow-lg'); | |
| } else { | |
| header.classList.remove('bg-gray-950/95', 'backdrop-blur-lg', 'shadow-lg'); | |
| } | |
| lastScroll = currentScroll; | |
| }); | |
| } | |
| function initCasinoCards() { | |
| renderCasinoCards(casinos, 'casinos-grid'); | |
| renderCasinoCards(newCasinos, 'new-casinos-grid'); | |
| } | |
| function renderCasinoCards(casinosList, containerId) { | |
| const container = document.getElementById(containerId); | |
| if (!container) return; | |
| container.innerHTML = casinosList.map((casino, index) => ` | |
| <div class="casino-card card-hover animate-fade-in-up" style="animation-delay: ${index * 0.1}s"> | |
| ${casino.badge ? ` | |
| <div class="absolute top-3 right-3 z-10"> | |
| <span class="badge badge-${casino.badgeColor} animate-pulse"> | |
| ${casino.badge} | |
| </span> | |
| </div> | |
| ` : ''} | |
| <div class="p-6"> | |
| <div class="flex items-start space-x-4 mb-4"> | |
| <div class="w-16 h-16 rounded-xl bg-gradient-to-br from-gray-800 to-gray-900 flex items-center justify-center text-3xl shadow-lg"> | |
| ${casino.logo} | |
| </div> | |
| <div class="flex-1"> | |
| <h3 class="font-display font-bold text-lg text-white mb-1">${casino.name}</h3> | |
| <div class="flex items-center space-x-2"> | |
| <div class="flex items-center"> | |
| ${generateStars(casino.rating)} | |
| </div> | |
| <span class="text-sm text-gray-400">${casino.rating}</span> | |
| <span class="text-xs text-gray-500">(${casino.reviews.toLocaleString()} отз.)</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gray-800/50 rounded-xl p-4 mb-4"> | |
| <div class="text-center mb-3"> | |
| <span class="text-gray-400 text-sm">Бонус</span> | |
| <div class="text-xl font-bold text-secondary-400">${casino.bonus}</div> | |
| <div class="text-sm text-primary-400">+${casino.freeSpins} фриспинов</div> | |
| </div> | |
| <div class="grid grid-cols-2 gap-3 text-center"> | |
| <div> | |
| <span class="text-gray-500 text-xs">Депозит от</span> | |
| <div class="text-white font-semibold">${casino.minDeposit}</div> | |
| </div> | |
| <div> | |
| <span class="text-gray-500 text-xs">Вывод до</span> | |
| <div class="text-white font-semibold">${casino.payoutSpeed}</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex flex-wrap gap-2 mb-4"> | |
| ${casino.features.slice(0, 3).map(feature => ` | |
| <span class="text-xs bg-gray-800 text-gray-300 px-2 py-1 rounded-lg"> | |
| ${feature} | |
| </span> | |
| `).join('')} | |
| </div> | |
| <div class="flex items-center space-x-2 mb-4"> | |
| ${casino.paymentMethods.map(method => ` | |
| <span class="text-xs text-gray-500 bg-gray-800 px-2 py-1 rounded"> | |
| ${getPaymentIcon(method)} | |
| </span> | |
| `).join('')} | |
| <span class="text-xs text-gray-500 ml-auto">${casino.license}</span> | |
| </div> | |
| <a href="${casino.url}" target="_blank" rel="noopener noreferrer" class="w-full inline-flex items-center justify-center space-x-2 bg-gradient-to-r from-primary-600 to-primary-500 hover:from-primary-500 hover:to-primary-400 text-white py-3 rounded-xl font-semibold transition-all shadow-lg shadow-primary-500/25 group"> | |
| <span>Играть</span> | |
| <i data-feather="arrow-right" class="w-4 h-4 group-hover:translate-x-1 transition-transform"></i> | |
| </a> | |
| </div> | |
| </div> | |
| `).join(''); | |
| if (typeof feather !== 'undefined') { | |
| feather.replace(); | |
| } | |
| } | |
| function generateStars(rating) { | |
| let stars = ''; | |
| for (let i = 1; i <= 5; i++) { | |
| if (i <= Math.floor(rating)) { | |
| stars += '<i data-feather="star" class="w-4 h-4 text-secondary-500 fill-secondary-500"></i>'; | |
| } else if (i - 0.5 <= rating) { | |
| stars += '<i data-feather="star" class="w-4 h-4 text-secondary-500 fill-secondary-500" style="fill: url(#half-star)"></i>'; | |
| } else { | |
| stars += '<i data-feather="star" class="w-4 h-4 text-gray-600"></i>'; | |
| } | |
| } | |
| return stars; | |
| } | |
| function getPaymentIcon(method) { | |
| const icons = { | |
| 'card': '💳', | |
| 'wallet': '👛', | |
| 'crypto': '₿', | |
| 'mobile': '📱' | |
| }; | |
| return icons[method] || '💰'; | |
| } | |
| function initAnimations() { | |
| const observerOptions = { | |
| threshold: 0.1, | |
| rootMargin: '0px 0px -50px 0px' | |
| }; | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| entry.target.classList.add('animate-fade-in-up'); | |
| observer.unobserve(entry.target); | |
| } | |
| }); | |
| }, observerOptions); | |
| document.querySelectorAll('.casino-card, article, .bg-gray-900\\/50').forEach(el => { | |
| el.style.opacity = '0'; | |
| observer.observe(el); | |
| }); | |
| } | |
| function initSearch() { | |
| const searchInput = document.querySelector('input[placeholder="Найти казино..."]'); | |
| if (!searchInput) return; | |
| let debounceTimer; | |
| searchInput.addEventListener('input', (e) => { | |
| clearTimeout(debounceTimer); | |
| debounceTimer = setTimeout(() => { | |
| const query = e.target.value.toLowerCase(); | |
| filterCasinos(query); | |
| }, 300); | |
| }); | |
| } | |
| function filterCasinos(query) { | |
| const allCasinos = [...casinos, ...newCasinos]; | |
| const filtered = allCasinos.filter(casino => | |
| casino.name.toLowerCase().includes(query) || | |
| casino.features.some(f => f.toLowerCase().includes(query)) | |
| ); | |
| const topGrid = document.getElementById('casinos-grid'); | |
| const newGrid = document.getElementById('new-casinos-grid'); | |
| if (topGrid) { | |
| const topFiltered = filtered.filter(c => casinos.includes(c)); | |
| renderCasinoCards(topFiltered, 'casinos-grid'); | |
| } | |
| if (newGrid) { | |
| const newFiltered = filtered.filter(c => newCasinos.includes(c)); | |
| renderCasinoCards(newFiltered, 'new-casinos-grid'); | |
| } | |
| } | |
| function initSmoothScroll() { | |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
| anchor.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| const target = document.querySelector(this.getAttribute('href')); | |
| if (target) { | |
| target.scrollIntoView({ | |
| behavior: 'smooth', | |
| block: 'start' | |
| }); | |
| } | |
| }); | |
| }); | |
| } | |
| function initScrollEffects() { | |
| const sections = document.querySelectorAll('section'); | |
| const sectionObserver = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| entry.target.classList.add('active-section'); | |
| } | |
| }); | |
| }, { threshold: 0.2 }); | |
| sections.forEach(section => { | |
| sectionObserver.observe(section); | |
| }); | |
| } | |
| document.querySelectorAll('.casino-card').forEach((card, index) => { | |
| card.style.animationDelay = `${index * 0.1}s`; | |
| }); | |
| function animateCounter(element, target, duration = 2000) { | |
| let start = 0; | |
| const increment = target / (duration / 16); | |
| const timer = setInterval(() => { | |
| start += increment; | |
| if (start >= target) { | |
| element.textContent = target.toLocaleString(); | |
| clearInterval(timer); | |
| } else { | |
| element.textContent = Math.floor(start).toLocaleString(); | |
| } | |
| }, 16); | |
| } | |
| const statsObserver = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| const counters = entry.target.querySelectorAll('.stat-number'); | |
| counters.forEach(counter => { | |
| const value = counter.textContent.replace(/[^0-9]/g, ''); | |
| if (value && !counter.classList.contains('animated')) { | |
| counter.classList.add('animated'); | |
| } | |
| }); | |
| statsObserver.unobserve(entry.target); | |
| } | |
| }); | |
| }, { threshold: 0.5 }); | |
| document.querySelectorAll('.grid > div').forEach(stat => { | |
| statsObserver.observe(stat); | |
| }); |