<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>PlayPapa</title>
<script>
(() => {
window.__preloaderStart = performance.now();
try {
const requestedTheme = new URLSearchParams(window.location.search).get("theme");
const savedTheme = localStorage.getItem("playpapa-theme");
const theme = requestedTheme || savedTheme;
document.documentElement.dataset.theme = theme === "dark" ? "dark" : "light";
} catch {
document.documentElement.dataset.theme = "light";
}
try {
if ("scrollRestoration" in history) history.scrollRestoration = "manual";
if (!window.location.hash || window.location.hash === "#") {
window.addEventListener("load", () => requestAnimationFrame(() => window.scrollTo(0, 0)), { once: true });
}
} catch {}
})();
</script>
<script>
window.playpapaCatalog = {{ catalog_payload_json|default('{"products":[],"total":0}')|raw }};
</script>
<script>
tailwind = {
config: {
theme: {
extend: {
colors: {
papa: "#268bf3",
ink: "#202838",
soft: "#f2f4f8",
},
},
},
},
};
</script>
<script src="https://cdn.tailwindcss.com" defer></script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600;700;800;900&display=swap" rel="stylesheet" />
<link rel="icon" type="image/svg+xml" href="./assets/blogger-playpapa-logo.svg" />
<link rel="stylesheet" href="./frame.css" />
<link rel="stylesheet" href="./styles.css" />
<link rel="stylesheet" href="/auth-local.css" />
</head>
<body class="preloader-active">
<div class="page-preloader" id="pagePreloader" role="status" aria-label="Загрузка">
<div class="preloader-inner">
<div class="preloader-dots" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</div>
<div class="preloader-text">Загрузка...</div>
</div>
</div>
<header class="site-header">
<div class="shell header-inner">
<a class="logo-link" href="/">
<img src="./assets/logo.svg" alt="PlayPapa" />
</a>
<div class="theme-switch" aria-label="Переключение темы">
<button class="theme-btn is-active" type="button" data-theme="light" aria-label="Светлая тема" aria-pressed="true">
<img src="./assets/white-theme.svg" alt="" />
</button>
<button class="theme-btn" type="button" data-theme="dark" aria-label="Темная тема" aria-pressed="false">
<img src="./assets/dark-theme.svg" alt="" />
</button>
</div>
<button class="catalog-btn" type="button" aria-label="Каталог" aria-expanded="false" aria-controls="catalogMegaMenu">
<img src="./assets/catalog.svg" alt="" />
<span>Каталог</span>
</button>
<form class="search-form" action="#">
<input type="search" placeholder="Игра, приложение или услуга..." />
<button class="search-favorite" type="button" aria-label="Избранное">
<img src="./assets/favorite.svg" alt="" />
</button>
<button class="search-submit" type="submit" aria-label="Найти">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="m21 21-4.35-4.35m2.35-5.65a8 8 0 1 1-16 0 8 8 0 0 1 16 0Z" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" />
</svg>
</button>
</form>
<button class="bonus-btn" aria-label="Бонусы">
<img src="./assets/bonus.svg" alt="Бонусы" />
</button>
<div class="profile-menu">
<button class="profile-btn" type="button" aria-label="Профиль" aria-expanded="false" aria-controls="profilePopover">
<img src="./assets/profile.svg" alt="" />
<span class="profile-toggle-indicator" aria-hidden="true">
<svg viewBox="0 0 12 8" fill="none">
<path d="m2 2 4 4 4-4" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</button>
<section class="profile-popover" id="profilePopover" aria-hidden="true" aria-label="Меню профиля" inert>
<div class="profile-popover-heading">
<h2>Вы не авторизованы</h2>
<p>
<span>Войдите, чтобы видеть бонусы и</span>
<span>рефералов</span>
</p>
</div>
<nav class="profile-popover-nav" aria-label="Разделы профиля">
<button class="profile-menu-item" type="button" disabled>
<img class="profile-menu-icon" src="./assets/profile-menu-profile.svg" alt="" />
<span>Профиль</span>
</button>
<button class="profile-menu-item" type="button" disabled>
<img class="profile-menu-icon" src="./assets/profile-menu-referrals.svg" alt="" />
<span>Рефералы</span>
</button>
<button class="profile-menu-item" type="button" disabled>
<img class="profile-menu-icon" src="./assets/profile-menu-bonus.svg" alt="" />
<span>Бонусы</span>
</button>
<button class="profile-menu-item" type="button" disabled>
<img class="profile-menu-icon" src="./assets/profile-menu-topup.svg" alt="" />
<span>Пополнить</span>
</button>
<button class="profile-menu-item profile-help" type="button">
<img class="profile-menu-icon" src="./assets/profile-menu-help.svg" alt="" />
<span>Помощь</span>
</button>
<button class="profile-menu-item profile-login" type="button" data-auth-open="login">
<img class="profile-menu-icon" src="./assets/profile-menu-login.svg" alt="" />
<span>Войти</span>
</button>
</nav>
</section>
</div>
</div>
<div class="catalog-layer" id="catalogMegaMenu" aria-hidden="true" inert>
<div class="shell catalog-mega" role="dialog" aria-label="Каталог товаров">
<aside class="catalog-sidebar" aria-label="Разделы каталога">
<button class="catalog-side-link is-active" type="button">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M7.5 8.2h9a4.5 4.5 0 0 1 4.2 6.1l-1.1 2.8a2.2 2.2 0 0 1-3.7.7l-1.2-1.5H9.3l-1.2 1.5a2.2 2.2 0 0 1-3.7-.7l-1.1-2.8a4.5 4.5 0 0 1 4.2-6.1Z" stroke="currentColor" stroke-width="1.8"/><path d="M8 11v3m-1.5-1.5h3M16.5 11.7h.01m2 2h.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
<span>Игры и игровые сервисы</span>
<span class="catalog-chevron" aria-hidden="true">›</span>
</button>
<button class="catalog-side-link" type="button">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="m12 2.8 8.1 5.5L12 21.2 3.9 8.3 12 2.8Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="m3.9 8.3 5.1.2 3-5.7 3 5.7 5.1-.2M9 8.5l3 12.7 3-12.7" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>
<span>Игровые ценности</span>
<span class="catalog-chevron" aria-hidden="true">›</span>
</button>
<button class="catalog-side-link" type="button">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><rect x="6.2" y="2.5" width="11.6" height="19" rx="2.2" stroke="currentColor" stroke-width="1.8"/><path d="M10 5h4m-2 13.5h.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
<span>Мобильные игры</span>
<span class="catalog-chevron" aria-hidden="true">›</span>
</button>
<button class="catalog-side-link" type="button">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="1.8"/><path d="M3.4 12h17.2M12 3c2.2 2.5 3.3 5.5 3.3 9S14.2 18.5 12 21c-2.2-2.5-3.3-5.5-3.3-9S9.8 5.5 12 3Z" stroke="currentColor" stroke-width="1.5"/></svg>
<span>Сервисы и соцсети</span>
<span class="catalog-chevron" aria-hidden="true">›</span>
</button>
<button class="catalog-side-link" type="button">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><rect x="3" y="4.2" width="18" height="12.3" rx="1.8" stroke="currentColor" stroke-width="1.8"/><path d="M8.5 20h7M12 16.5V20" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
<span>Программы</span>
<span class="catalog-chevron" aria-hidden="true">›</span>
</button>
</aside>
<div class="catalog-content">
<section class="catalog-showcase" aria-labelledby="catalogFeaturedTitle">
<h2 id="catalogFeaturedTitle">Игры и игровые сервисы <span aria-hidden="true">›</span></h2>
<div class="catalog-showcase-row" id="catalogFeatured"></div>
</section>
<section class="catalog-showcase catalog-new" aria-labelledby="catalogNewTitle">
<h2 id="catalogNewTitle">Новинки и предзаказы <span aria-hidden="true">›</span></h2>
<div class="catalog-showcase-row" id="catalogNew"></div>
</section>
<div class="catalog-platforms">
<section class="catalog-link-group">
<h3>Steam <span aria-hidden="true">›</span></h3>
<a href="#">Игры и DLC</a>
<a href="#">Пополнение баланса</a>
<a href="#">Подарочные карты</a>
<a href="#">Коллекционные карточки</a>
<a href="#">Смена региона</a>
</section>
<section class="catalog-link-group">
<h3>PlayStation <span aria-hidden="true">›</span></h3>
<a href="#">Игры и DLC</a>
<a href="#">Пополнение баланса</a>
<a href="#">Новые аккаунты</a>
<a href="#">PS Plus</a>
<a href="#">EA Play</a>
</section>
<section class="catalog-link-group">
<h3>Xbox <span aria-hidden="true">›</span></h3>
<a href="#">Игры и DLC</a>
<a href="#">Пополнение баланса</a>
<a href="#">Новые аккаунты</a>
<a href="#">Xbox Game Pass</a>
<a href="#">Услуги</a>
</section>
<section class="catalog-link-group">
<h3>Nintendo <span aria-hidden="true">›</span></h3>
<a href="#">Игры и DLC</a>
<a href="#">Подарочные карты</a>
<a href="#">Новые аккаунты</a>
<a href="#">NS Online</a>
</section>
<section class="catalog-link-group">
<h3>Battle.net <span aria-hidden="true">›</span></h3>
<a href="#">World of Warcraft</a>
<a href="#">Подарочные карты</a>
<a href="#">Прямое пополнение</a>
<a href="#">Новые аккаунты</a>
<a href="#">Смена региона</a>
</section>
</div>
</div>
</div>
</div>
</header>
<main>
<section class="shell hero-section">
<picture class="hero-picture">
<source media="(max-width: 767px)" srcset="./assets/hero-steam-mobile.jpg" />
<img class="hero-img" src="./assets/hero-steam-cutout.jpg" alt="Пополнение Steam" />
</picture>
<div class="hero-arrows">
<button aria-label="Назад">
<svg viewBox="0 0 24 24" fill="none"><path d="M19 12H6m5-5-5 5 5 5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" /></svg>
</button>
<button aria-label="Вперед">
<svg viewBox="0 0 24 24" fill="none"><path d="M5 12h13m-5-5 5 5-5 5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" /></svg>
</button>
</div>
<div class="hero-dots" aria-hidden="true"><span></span><span></span><span></span><span></span><span></span><span></span></div>
</section>
<section class="shell services-card">
<div class="services-row" id="servicesRow"></div>
<div class="topup-row">
<div class="topup-info">
<img src="./assets/steam-topup.png" alt="" />
<div>
<div class="topup-title">
Пополнение Steam
<span>5%</span>
</div>
<button class="promo-small" type="button" aria-expanded="false" aria-controls="topupPromoSection">
<span class="promo-small-label">Ввести промокод</span>
<svg viewBox="0 0 16 16" fill="none"><path d="m4 6 4 4 4-4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" /></svg>
</button>
</div>
</div>
<label class="form-field login-field">
<img src="./assets/profile-gray.svg" alt="" />
<input type="text" name="steam-login" placeholder="Логин Steam" />
<span class="field-info" aria-hidden="true"><img src="./assets/info-i.svg" alt="" /></span>
</label>
<div class="form-field amount-field">
<div class="amount-field-shell">
<span class="currency-mark"><span class="currency-icon currency-icon-ruble" aria-hidden="true"></span></span>
<label class="amount-control">
<small>Сумма</small>
<span class="amount-value">
<input type="text" name="amount" inputmode="numeric" value="500" maxlength="6" aria-label="Сумма" aria-expanded="false" aria-controls="topupQuickPopover" />
<span class="currency-icon currency-icon-ruble" aria-hidden="true"></span>
</span>
</label>
<span class="currency-tabs" role="group" aria-label="Валюта">
<button type="button" aria-label="Доллар"><span class="currency-icon currency-icon-dollar" aria-hidden="true"></span></button>
<button type="button" aria-label="Тенге"><span class="currency-icon currency-icon-tenge" aria-hidden="true"></span></button>
<button class="is-active" type="button" aria-label="Рубль"><span class="currency-icon currency-icon-ruble" aria-hidden="true"></span></button>
</span>
</div>
<div class="topup-quick-popover" id="topupQuickPopover" aria-hidden="true" inert>
<span class="topup-quick-popover-label">Быстрый выбор суммы</span>
<div class="topup-quick-popover-buttons" aria-label="Быстрый выбор суммы">
<button class="is-active" type="button" data-quick-amount="500">500 ₽</button>
<button type="button" data-quick-amount="1000">1 000 ₽</button>
<button type="button" data-quick-amount="2500">2 500 ₽</button>
<button type="button" data-quick-amount="5000">5 000 ₽</button>
</div>
</div>
</div>
<button class="pay-btn" type="button" aria-expanded="false" aria-controls="topupPaymentSection">Оплатить 500<span class="currency-icon currency-icon-ruble" aria-hidden="true"></span></button>
<div class="topup-expand" id="topupDetails" aria-hidden="true" inert>
<div class="topup-expand-clip">
<div class="topup-expand-content">
<section class="topup-expand-section topup-promo-section" id="topupPromoSection" aria-hidden="true" inert>
<div class="topup-expand-section-inner">
<label class="topup-detail-label" for="topupPromoInput">Промокод</label>
<div class="topup-promo-row">
<label class="topup-promo-input">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M4 10h16v10H4V10Zm0-4h16v4H4V6Zm8 0v14M12 6c-1.7-3.1-5.2-2.8-5.2-.5C6.8 7.2 9 7.5 12 6Zm0 0c1.7-3.1 5.2-2.8 5.2-.5C17.2 7.2 15 7.5 12 6Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" />
</svg>
<input id="topupPromoInput" type="text" placeholder="Введите промокод" autocomplete="off" />
</label>
<button class="topup-promo-apply" type="button">Применить</button>
</div>
</div>
</section>
<div class="topup-promo-benefit" aria-live="polite" aria-hidden="true">
<img src="./assets/discount-percent.png" alt="" />
<strong>Скидка <span>5%</span> — вы экономите <b data-promo-saving>25 ₽</b></strong>
<small><span>Вы платите примерно на 12% меньше,</span><span>чем на других площадках</span></small>
</div>
<section class="topup-expand-section topup-payment-section" id="topupPaymentSection" aria-hidden="true" inert>
<div class="topup-expand-section-inner">
<h3 class="topup-detail-label topup-payment-title">Способ оплаты</h3>
<div class="topup-payment-methods" role="radiogroup" aria-label="Способ оплаты">
<button class="topup-payment-method is-selected" type="button" role="radio" aria-checked="true" data-fee="0">
<span class="topup-payment-icon"><img src="./assets/payment-sbp.svg" alt="" /></span>
<span class="topup-payment-copy"><b>СБП</b><small>Без комиссии</small></span>
<span class="topup-payment-check" aria-hidden="true"><svg viewBox="0 0 20 20" fill="none"><path d="m5 10 3 3 7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg></span>
</button>
<button class="topup-payment-method" type="button" role="radio" aria-checked="false" data-fee="2">
<span class="topup-payment-icon"><img src="./assets/payment-mir-option.svg" alt="" /></span>
<span class="topup-payment-copy"><b>Карта МИР</b><small>+2% комиссия</small></span>
<span class="topup-payment-check" aria-hidden="true"><svg viewBox="0 0 20 20" fill="none"><path d="m5 10 3 3 7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg></span>
</button>
<button class="topup-payment-method" type="button" role="radio" aria-checked="false" data-fee="0">
<span class="topup-payment-icon"><img src="./assets/payment-btc.svg" alt="" /></span>
<span class="topup-payment-copy"><b>Криптовалюта</b><small>Без комиссии</small></span>
<span class="topup-payment-check" aria-hidden="true"><svg viewBox="0 0 20 20" fill="none"><path d="m5 10 3 3 7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg></span>
</button>
</div>
<div class="topup-total-row">
<div class="topup-total-copy">
<small>К зачислению на Steam</small>
<span><strong data-topup-credit>500 ₽</strong><b data-topup-fee-badge>Без комиссии</b></span>
</div>
<button class="topup-final-pay" type="button">Оплатить 500₽</button>
</div>
</div>
</section>
</div>
</div>
</div>
</div>
</section>
<section class="shell product-section popular-section">
<div class="section-head compact-head">
<h2><img src="./assets/icon-popular.svg" alt="" />Популярные товары</h2>
<nav class="chip-row" aria-label="Категории">
<button class="chip is-active"><img src="./assets/cat-donate.svg" alt="" />Донат</button>
<button class="chip"><img src="./assets/cat-subscribes.svg" alt="" />Подписки</button>
<button class="chip"><img src="./assets/cat-items.svg" alt="" />Предметы</button>
<button class="chip"><img src="./assets/cat-accounts.svg" alt="" />Аккаунты</button>
<button class="chip"><img src="./assets/cat-keys.svg" alt="" />Ключи</button>
<button class="chip"><img src="./assets/cat-currency.svg" alt="" />Steam Gift</button>
<button class="chip"><img src="./assets/cat-other.svg" alt="" />Другое</button>
</nav>
</div>
<div class="product-grid" data-products="popular"></div>
<a class="show-all mobile-show-all" href="/catalog">Показать все</a>
</section>
<section class="shell product-section">
<div class="section-head">
<h2><img src="./assets/icon-recommended.svg" alt="" />Рекомендованные товары</h2>
<a class="show-all" href="/catalog">Показать все</a>
</div>
<div class="product-grid" data-products="recommended"></div>
</section>
<section class="shell blogger-section">
<div class="section-head">
<h2><img src="./assets/icon-recommended-alt.svg" alt="" />Подборка от блогера</h2>
<a class="show-all" href="/catalog">Показать все</a>
</div>
<div class="blogger-layout">
<article class="blogger-card">
<div class="blogger-card-head">
<div class="blogger-author">
<img src="./assets/polka.png" alt="" />
<strong>Рекомендует Polk Zone</strong>
</div>
<button class="promo-inside">
<img src="./assets/blogger-promo-blob.svg" alt="" />
<span>Промокод внутри</span>
</button>
</div>
<img class="blogger-banner" src="./assets/blogger-promo.png" alt="Личная подборка от блогера" />
<div class="blogger-stats">
<div class="coupon-stat">
<span class="stat-icon"><img src="./assets/blogger-icon-coupon.svg" alt="" /></span>
<span class="coupon-text">Промокод<br /><b>BLOGGER5</b></span>
<span class="coupon-copy" aria-hidden="true"><img src="./assets/blogger-icon-copy.svg" alt="" /></span>
</div>
<div class="stat-item"><span class="stat-icon"><img src="./assets/blogger-icon-cart.svg" alt="" /></span><span class="stat-text"><b>12 товаров</b><small>в подборке</small></span></div>
<div class="stat-item wide"><span class="stat-icon"><img src="./assets/blogger-icon-services.svg" alt="" /></span><span class="stat-text"><b>Steam · Roblox · PUBG</b><small>и другие сервисы</small></span></div>
</div>
</article>
<aside class="blogger-side">
<article class="side-card steam-side">
<div class="side-title">
<img src="./assets/steam-topup.png" alt="" />
<div><b>Пополнение Steam</b><span>Без комиссии</span></div>
</div>
<div class="side-features">
<div><img src="./assets/blogger-icon-wallet.svg" alt="" /><b>от 500 ₽</b></div>
<div><img src="./assets/blogger-icon-lightning.svg" alt="" /><b>Моментально</b></div>
</div>
<button>Пополнить</button>
</article>
<article class="side-card keys-side">
<div class="side-title">
<img src="./assets/blogger-playpapa-logo.svg" alt="" />
<div><b>Топ ключи игр</b><span>Выбор подписчиков</span></div>
</div>
<div class="thumb-row">
<img src="./assets/thumb-game-1.jpg" alt="" />
<img src="./assets/thumb-game-2.png" alt="" />
<img src="./assets/thumb-game-3.png" alt="" />
<span>Ещё 7</span>
</div>
<button>Смотреть</button>
</article>
</aside>
</div>
</section>
<section class="shell product-section other-products">
<div class="section-head">
<h2><img src="./assets/icon-recommended-alt.svg" alt="" />Другие товары</h2>
<a class="show-all" href="/catalog">Показать все</a>
</div>
<div class="product-grid" data-products="other"></div>
</section>
<section class="shell articles-section">
<div class="section-head">
<h2><img src="./assets/icon-articles.svg" alt="" />Интересные статьи</h2>
<a class="show-all" href="/catalog">Показать все</a>
</div>
<div class="article-grid">
<article class="article-card">
<div class="article-image"><img src="./assets/article-paradise.png" alt="" /><span>Статьи</span></div>
<h3>Тайные игры EGS: Paradise Killer — детектив, который можно забрать прямо сейчас</h3>
<div class="article-meta"><span><img src="./assets/article-calendar.svg" alt="" />13 июня 2026</span><span><img src="./assets/article-eye.svg" alt="" />4 892</span></div>
</article>
<article class="article-card">
<div class="article-image"><img src="./assets/article-sale.png" alt="" /><span>Статьи</span></div>
<h3>Тайные игры EGS: Paradise Killer — детектив, который можно забрать прямо сейчас</h3>
<div class="article-meta"><span><img src="./assets/article-calendar.svg" alt="" />13 июня 2026</span><span><img src="./assets/article-eye.svg" alt="" />4 892</span></div>
</article>
<article class="article-card">
<div class="article-image"><img src="./assets/article-mobile.png" alt="" /><span>Статьи</span></div>
<h3>Тайные игры EGS: Paradise Killer — детектив, который можно забрать прямо сейчас</h3>
<div class="article-meta"><span><img src="./assets/article-calendar.svg" alt="" />13 июня 2026</span><span><img src="./assets/article-eye.svg" alt="" />4 892</span></div>
</article>
</div>
</section>
<section class="shell reviews-section">
<div class="section-head reviews-head">
<div>
<h2><img src="./assets/icon-reviews.svg" alt="" />Последние отзывы</h2>
<p>Все отзывы взяты с независимой площадки</p>
</div>
<a class="show-all" href="/catalog">Показать все</a>
</div>
<div class="review-grid">
<article class="review-card">
<div class="review-top">
<img src="./assets/review-avatar.png" alt="" />
<div><b>Bizidin</b><span>★★★★★ <strong>5.0</strong></span></div>
<time>Сегодня в 11:48</time>
</div>
<p class="review-text">Отзывчивый и приятный продавец, помог не только с товаром но и с другим вопросом. Рекомендую!</p>
<div class="review-product">
<img src="./assets/product-pubg.png" alt="" />
<b>🌸 FunTime | Полностью готовый сервер под ключ ⚡</b>
<span>139₽</span>
</div>
</article>
<article class="review-card">
<div class="review-top">
<img src="./assets/review-avatar.png" alt="" />
<div><b>Bizidin</b><span>★★★★★ <strong>5.0</strong></span></div>
<time>Сегодня в 11:48</time>
</div>
<p class="review-text">Отзывчивый и приятный продавец, помог не только с товаром но и с другим вопросом. Рекомендую!</p>
<div class="review-product">
<img src="./assets/product-pubg.png" alt="" />
<b>🌸 FunTime | Полностью готовый сервер под ключ ⚡</b>
<span>139₽</span>
</div>
</article>
<article class="review-card">
<div class="review-top">
<img src="./assets/review-avatar.png" alt="" />
<div><b>Bizidin</b><span>★★★★★ <strong>5.0</strong></span></div>
<time>Сегодня в 11:48</time>
</div>
<p class="review-text">Отзывчивый и приятный продавец, помог не только с товаром но и с другим вопросом. Рекомендую!</p>
<div class="review-product">
<img src="./assets/product-pubg.png" alt="" />
<b>🌸 FunTime | Полностью готовый сервер под ключ ⚡</b>
<span>139₽</span>
</div>
</article>
</div>
</section>
<footer class="shell site-footer">
<div class="footer-top">
<img src="./assets/logo.svg" alt="PlayPapa" />
<nav>
<a href="#">Стать продавцом</a>
<a href="#">Бонусы</a>
<a href="#">Поддержка</a>
<a href="#">Гарантии</a>
<a href="#">Отзывы</a>
</nav>
</div>
<div class="footer-mid">
<div class="footer-social">
<b>PlayPapa</b>
<a class="social-icon" href="#" aria-label="VK"><img src="./assets/footer-vk.svg" alt="" /></a>
<a class="social-icon" href="#" aria-label="Telegram"><img src="./assets/footer-telegram.svg" alt="" /></a>
<a class="footer-channel" href="#">Polk Zone</a>
<a class="social-icon" href="#" aria-label="TikTok"><img src="./assets/footer-tiktok.svg" alt="" /></a>
<a class="social-icon" href="#" aria-label="YouTube"><img src="./assets/footer-youtube.svg" alt="" /></a>
</div>
<div class="payments">
<span><img src="./assets/payment-visa.svg" alt="VISA" /></span>
<span><img src="./assets/payment-mir.svg" alt="МИР" /></span>
<span><img src="./assets/payment-mastercard.svg" alt="Mastercard" /></span>
</div>
</div>
<div class="footer-bottom">
<nav>
<a href="#">Политика конфиденциальности</a>
<a href="#">Соглашение</a>
<a href="#">Договор-оферта</a>
</nav>
<span>© 2026 PlayPapa</span>
</div>
</footer>
</main>
<section class="mobile-search-layer" id="mobileSearch" role="dialog" aria-modal="true" aria-label="Мобильный поиск" aria-hidden="true" inert>
<div class="mobile-search-page">
<header class="mobile-search-topbar">
<button class="mobile-search-back" id="mobileSearchBack" type="button" aria-label="Назад">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M19 12H5m6-6-6 6 6 6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</button>
<form class="mobile-search-form" role="search">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<circle cx="10.8" cy="10.8" r="6.8" stroke="currentColor" stroke-width="2" />
<path d="m16 16 4.2 4.2" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
<input type="search" name="mobile-query" placeholder="Найти товар" aria-label="Найти товар" autocomplete="off" />
</form>
</header>
<section class="mobile-search-section mobile-search-services-section">
<h2>Игры и игровые сервисы</h2>
<div class="mobile-search-cards" aria-label="Игры и игровые сервисы">
<a class="mobile-search-card" href="#"><img src="./assets/service-steam.png" alt="" /><strong>Steam</strong></a>
<a class="mobile-search-card" href="#"><img src="./assets/service-telegram.png" alt="" /><strong>Telegram</strong></a>
<a class="mobile-search-card" href="#"><img src="./assets/service-roblox.png" alt="" /><strong>Roblox</strong></a>
<a class="mobile-search-card" href="#"><img src="./assets/service-brawl.png" alt="" /><strong>Brawl...</strong></a>
<a class="mobile-search-card mobile-search-more" href="#">
<span><img src="./assets/more-service.svg" alt="" /></span>
<strong>еще 841</strong>
</a>
</div>
</section>
<section class="mobile-search-section mobile-search-new-section">
<h2>Новинки и предзаказы</h2>
<div class="mobile-search-cards mobile-search-game-cards" aria-label="Новинки и предзаказы">
<a class="mobile-search-card" href="#"><img src="./assets/article-paradise.png" alt="" /><span>Gothic 1<br />Remake</span></a>
<a class="mobile-search-card" href="#"><img src="./assets/article-sale.png" alt="" /><span>Forza<br />Horizon 6</span></a>
<a class="mobile-search-card" href="#"><img src="./assets/product-pubg.png" alt="" /><span>Assassin's<br />Creed:...</span></a>
<a class="mobile-search-card" href="#"><img src="./assets/article-mobile.png" alt="" /><span>007 First<br />Light</span></a>
<a class="mobile-search-card" href="#"><img src="./assets/article-sale.png" alt="" /><span>Call of Duty:<br />Modern...</span></a>
</div>
</section>
<nav class="mobile-search-platforms" aria-label="Разделы каталога">
<a href="#"><span>Steam</span><span aria-hidden="true">›</span></a>
<a href="#"><span>PlayStation</span><span aria-hidden="true">›</span></a>
<a href="#"><span>Xbox</span><span aria-hidden="true">›</span></a>
<a href="#"><span>Nintendo</span><span aria-hidden="true">›</span></a>
<a href="#"><span>Battle.net</span><span aria-hidden="true">›</span></a>
<a href="#"><span>Подборки</span><span aria-hidden="true">›</span></a>
</nav>
</div>
</section>
<section class="auth-modal-layer" id="authModal" data-auth-screen="login" aria-hidden="true" inert>
<div class="auth-modal-dialog" role="dialog" aria-modal="true" aria-label="Авторизация">
<div class="auth-toast auth-toast-success" aria-live="polite">
<img src="./assets/auth-check.svg" alt="" />
<span>Письмо отправлено на почту</span>
</div>
<div class="auth-toast auth-toast-error" aria-live="polite">
<img src="./assets/auth-error.svg" alt="" />
<span>Ошибка отправки письма</span>
</div>
<button class="auth-close" type="button" aria-label="Закрыть" data-auth-close>
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="m4.5 4.5 7 7m0-7-7 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
</button>
<img class="auth-logo" src="./assets/logo.svg" alt="PlayPapa" />
<section class="auth-view auth-view-login" aria-label="Вход">
<h2>С возвращением!</h2>
<div class="auth-tabs" role="tablist" aria-label="Авторизация">
<button class="auth-tab" type="button" role="tab" data-auth-screen-target="login">Вход</button>
<button class="auth-tab" type="button" role="tab" data-auth-screen-target="register">Регистрация</button>
</div>
<form class="auth-form" data-auth-form="login">
<label class="auth-field">
<img src="./assets/auth-user.svg" alt="" />
<input type="text" name="login" placeholder="Логин" autocomplete="username" />
</label>
<label class="auth-field">
<img src="./assets/auth-lock.svg" alt="" />
<input type="password" name="password" placeholder="Пароль" autocomplete="current-password" />
</label>
<button class="auth-link auth-forgot" type="button" data-auth-screen-target="recover">Забыли пароль?</button>
<button class="auth-primary" type="submit">Войти</button>
</form>
<div class="auth-social-block">
<div class="auth-divider"><span>Другие методы входа</span></div>
<div class="auth-socials" aria-label="Другие методы входа">
<button class="auth-social auth-social-telegram" type="button" aria-label="Telegram"><img src="./assets/footer-telegram.svg" alt="" /></button>
<button class="auth-social auth-social-vk" type="button" aria-label="VK"><img src="./assets/footer-vk.svg" alt="" /></button>
<button class="auth-social auth-social-steam" type="button" aria-label="Steam"><img src="./assets/auth-steam.svg" alt="" /></button>
<button class="auth-social auth-social-yandex" type="button" aria-label="Яндекс"><img src="./assets/auth-yandex.svg" alt="" /></button>
</div>
<p class="auth-recaptcha">Защищено reCAPTCHA · <a href="#">Политика</a> и <a href="#">Условия</a></p>
</div>
</section>
<section class="auth-view auth-view-register" aria-label="Регистрация">
<h2>Создание аккаунта</h2>
<div class="auth-tabs" role="tablist" aria-label="Авторизация">
<button class="auth-tab" type="button" role="tab" data-auth-screen-target="login">Вход</button>
<button class="auth-tab" type="button" role="tab" data-auth-screen-target="register">Регистрация</button>
</div>
<form class="auth-form" data-auth-form="register">
<label class="auth-field">
<img src="./assets/auth-user.svg" alt="" />
<input type="text" name="register-login" placeholder="Логин" autocomplete="username" />
</label>
<label class="auth-field">
<img src="./assets/auth-mail.svg" alt="" />
<input type="email" name="register-email" placeholder="E-mail" autocomplete="email" />
</label>
<label class="auth-field">
<img src="./assets/auth-lock.svg" alt="" />
<input type="password" name="register-password" placeholder="Пароль" autocomplete="new-password" />
</label>
<label class="auth-field">
<img src="./assets/auth-lock.svg" alt="" />
<input type="password" name="register-password-repeat" placeholder="Повторите пароль" autocomplete="new-password" />
</label>
<label class="auth-consent">
<input type="checkbox" checked />
<span aria-hidden="true"></span>
<b>Я принимаю <a href="#">условия</a> и <a href="#">политику конфиденциальности</a>.</b>
</label>
<button class="auth-primary" type="submit">Создать аккаунт</button>
</form>
<div class="auth-social-block">
<div class="auth-divider"><span>Другие методы входа</span></div>
<div class="auth-socials" aria-label="Другие методы входа">
<button class="auth-social auth-social-telegram" type="button" aria-label="Telegram"><img src="./assets/footer-telegram.svg" alt="" /></button>
<button class="auth-social auth-social-vk" type="button" aria-label="VK"><img src="./assets/footer-vk.svg" alt="" /></button>
<button class="auth-social auth-social-steam" type="button" aria-label="Steam"><img src="./assets/auth-steam.svg" alt="" /></button>
<button class="auth-social auth-social-yandex" type="button" aria-label="Яндекс"><img src="./assets/auth-yandex.svg" alt="" /></button>
</div>
<p class="auth-recaptcha">Защищено reCAPTCHA · <a href="#">Политика</a> и <a href="#">Условия</a></p>
</div>
</section>
<section class="auth-view auth-view-recover" aria-label="Восстановление пароля">
<button class="auth-back" type="button" data-auth-screen-target="login">
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M10.5 3.5 6 8l4.5 4.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
<span>Назад ко входу</span>
</button>
<h2>Восстановление пароля</h2>
<p class="auth-subtitle">Введите e-mail - пришлем ссылку для сброса пароля.</p>
<form class="auth-form" data-auth-form="recover">
<label class="auth-field">
<img src="./assets/auth-mail.svg" alt="" />
<input type="email" name="recover-email" placeholder="you@mail.ru" autocomplete="email" />
</label>
<button class="auth-primary" type="submit">Отправить ссылку</button>
</form>
<div class="auth-social-block">
<div class="auth-divider"><span>Другие методы входа</span></div>
<div class="auth-socials" aria-label="Другие методы входа">
<button class="auth-social auth-social-telegram" type="button" aria-label="Telegram"><img src="./assets/footer-telegram.svg" alt="" /></button>
<button class="auth-social auth-social-vk" type="button" aria-label="VK"><img src="./assets/footer-vk.svg" alt="" /></button>
<button class="auth-social auth-social-steam" type="button" aria-label="Steam"><img src="./assets/auth-steam.svg" alt="" /></button>
<button class="auth-social auth-social-yandex" type="button" aria-label="Яндекс"><img src="./assets/auth-yandex.svg" alt="" /></button>
</div>
<p class="auth-recaptcha">Защищено reCAPTCHA · <a href="#">Политика</a> и <a href="#">Условия</a></p>
</div>
</section>
<section class="auth-view auth-view-success" aria-label="Письмо отправлено">
<div class="auth-status auth-status-success"><img src="./assets/auth-check.svg" alt="" /></div>
<h2>Проверьте почту</h2>
<p class="auth-message">Мы отправили ссылку для сброса пароля на <strong>you@mail.ru</strong>. Перейдите по ней, чтобы задать новый пароль.</p>
<button class="auth-text-action" type="button" data-auth-screen-target="recover">Не пришло письмо? Отправить повторно</button>
<button class="auth-secondary" type="button" data-auth-screen-target="login">Вернуться ко входу</button>
</section>
<section class="auth-view auth-view-error" aria-label="Ошибка отправки">
<div class="auth-status auth-status-error"><img src="./assets/auth-error.svg" alt="" /></div>
<h2>Не удалось отправить</h2>
<p class="auth-message">Письмо не отправлено - возможно, неверный адрес или проблема со связью. Проверьте e-mail и попробуйте снова.</p>
<button class="auth-primary" type="button" data-auth-screen-target="recover">Попробовать снова</button>
<button class="auth-support" type="button">Написать в поддержку</button>
</section>
</div>
</section>
<div data-mobile-panel></div>
<script src="./assets/mobile-panel.js"></script>
<script>
const root = document.documentElement;
const themeSwitch = document.querySelector(".theme-switch");
const themeButtons = document.querySelectorAll(".theme-btn[data-theme]");
const preloader = document.getElementById("pagePreloader");
if (preloader) {
const preloaderStart = window.__preloaderStart || performance.now();
const minPreloaderTime = 600;
const maxPreloaderTime = 3000;
let preloaderHidden = false;
const hidePreloader = () => {
if (preloaderHidden) return;
preloaderHidden = true;
preloader.classList.add("is-hiding");
document.body.classList.remove("preloader-active");
window.setTimeout(() => preloader.remove(), 260);
};
const requestPreloaderHide = () => {
const elapsed = performance.now() - preloaderStart;
window.setTimeout(hidePreloader, Math.max(minPreloaderTime - elapsed, 0));
};
window.setTimeout(hidePreloader, Math.max(maxPreloaderTime - (performance.now() - preloaderStart), 0));
if (document.readyState === "complete") {
requestPreloaderHide();
} else {
window.addEventListener("load", requestPreloaderHide, { once: true });
}
}
const setTheme = (theme, animate = false) => {
if (animate) {
document.body.classList.remove("theme-animating");
void document.body.offsetWidth;
document.body.classList.add("theme-animating");
}
root.dataset.theme = theme;
try {
localStorage.setItem("playpapa-theme", theme);
} catch {}
themeButtons.forEach((button) => {
const active = button.dataset.theme === theme;
button.classList.toggle("is-active", active);
button.setAttribute("aria-pressed", active ? "true" : "false");
});
if (animate) window.setTimeout(() => document.body.classList.remove("theme-animating"), 560);
};
setTheme(root.dataset.theme === "dark" ? "dark" : "light");
themeButtons.forEach((button) => {
button.addEventListener("click", () => setTheme(button.dataset.theme, true));
});
themeSwitch?.addEventListener("click", (event) => {
if (event.target.closest(".theme-btn")) return;
setTheme(root.dataset.theme === "dark" ? "light" : "dark", true);
});
const mobileSearchLayer = document.getElementById("mobileSearch");
const mobileSearchTrigger = document.querySelector("[data-mobile-search-trigger]");
const mobileSearchBack = document.getElementById("mobileSearchBack");
const setMobileSearchOpen = (open) => {
if (!mobileSearchLayer) return;
mobileSearchLayer.classList.toggle("is-open", open);
mobileSearchLayer.setAttribute("aria-hidden", open ? "false" : "true");
mobileSearchLayer.toggleAttribute("inert", !open);
mobileSearchTrigger?.setAttribute("aria-expanded", open ? "true" : "false");
document.body.classList.toggle("mobile-search-open", open);
if (open) mobileSearchLayer.scrollTop = 0;
};
mobileSearchTrigger?.addEventListener("click", (event) => {
event.preventDefault();
setProfileOpen(false);
setCatalogOpen(false);
setMobileSearchOpen(true);
});
mobileSearchBack?.addEventListener("click", () => {
setMobileSearchOpen(false);
mobileSearchTrigger?.focus();
});
mobileSearchLayer?.querySelector(".mobile-search-form")?.addEventListener("submit", (event) => event.preventDefault());
mobileSearchLayer?.querySelectorAll('a[href="#"]').forEach((link) => {
link.addEventListener("click", (event) => event.preventDefault());
});
document.addEventListener("keydown", (event) => {
if (event.key !== "Escape" || !mobileSearchLayer?.classList.contains("is-open")) return;
setMobileSearchOpen(false);
mobileSearchTrigger?.focus();
});
const profileMenu = document.querySelector(".profile-menu");
const profileButton = profileMenu?.querySelector(".profile-btn");
const profilePopover = document.getElementById("profilePopover");
const setProfileOpen = (open, returnFocus = false) => {
if (!profileMenu || !profilePopover || !profileButton) return;
profileMenu.classList.toggle("is-open", open);
profileButton.setAttribute("aria-expanded", open ? "true" : "false");
profilePopover.setAttribute("aria-hidden", open ? "false" : "true");
profilePopover.toggleAttribute("inert", !open);
document.body.classList.toggle("profile-open", open);
if (returnFocus) profileButton.focus();
};
profileButton?.addEventListener("click", (event) => {
event.stopPropagation();
const shouldOpen = !profileMenu?.classList.contains("is-open");
setProfileOpen(shouldOpen);
});
profilePopover?.querySelectorAll(".profile-menu-item:not(:disabled)").forEach((item) => {
item.addEventListener("click", () => setProfileOpen(false));
});
document.addEventListener("pointerdown", (event) => {
if (!profileMenu?.classList.contains("is-open") || profileMenu.contains(event.target)) return;
setProfileOpen(false);
});
document.addEventListener("keydown", (event) => {
if (event.key !== "Escape" || !profileMenu?.classList.contains("is-open")) return;
setProfileOpen(false, true);
});
const catalogLayer = document.getElementById("catalogMegaMenu");
const catalogButton = document.querySelector(".catalog-btn:not([href])");
const catalogTriggers = [catalogButton, ...document.querySelectorAll("[data-catalog-trigger]")].filter(Boolean);
const catalogSideLinks = document.querySelectorAll(".catalog-side-link");
const catalogFeaturedItems = [
["service-steam.png", "Пополнение Steam"],
["service-brawl.png", "Game Pass"],
["service-steam.png", "Пополнение PSN"],
["service-brawl.png", "PS Plus"],
["service-pubg.png", "Grand Theft Auto V"],
["service-roblox.png", "Minecraft"],
["service-playstation.png", "Diablo 4"],
["service-mobile.png", "ARC Raiders"],
["service-chatgpt.png", "Dead by Daylight"],
];
const catalogNewItems = [
["article-paradise.png", "Gothic 1 Remake"],
["article-sale.png", "Forza Horizon 6"],
["product-pubg.png", "Assassin's Creed: Black..."],
["article-mobile.png", "007 First Light"],
["article-sale.png", "Call of Duty: Modern..."],
["product-pubg.png", "Marvel's Wolverine"],
["article-paradise.png", "UFC 6"],
["article-sale.png", "Subnautica 2"],
["product-pubg.png", "SILENT HILL: Townfall"],
];
const catalogItemMarkup = ([image, label]) => `
<a class="catalog-showcase-item" href="#" aria-label="${label}">
<img src="./assets/${image}" alt="">
<span>${label}</span>
</a>
`;
const catalogFeatured = document.getElementById("catalogFeatured");
const catalogNew = document.getElementById("catalogNew");
if (catalogFeatured) catalogFeatured.innerHTML = catalogFeaturedItems.map(catalogItemMarkup).join("");
if (catalogNew) catalogNew.innerHTML = catalogNewItems.map(catalogItemMarkup).join("");
const setCatalogOpen = (open) => {
if (!catalogLayer) return;
catalogLayer.classList.toggle("is-open", open);
catalogLayer.setAttribute("aria-hidden", open ? "false" : "true");
catalogLayer.toggleAttribute("inert", !open);
document.body.classList.toggle("catalog-open", open);
catalogTriggers.forEach((trigger) => trigger.setAttribute("aria-expanded", open ? "true" : "false"));
};
catalogTriggers.forEach((trigger) => {
trigger.addEventListener("click", (event) => {
event.preventDefault();
setProfileOpen(false);
setMobileSearchOpen(false);
setCatalogOpen(!catalogLayer?.classList.contains("is-open"));
});
});
catalogSideLinks.forEach((link) => {
link.addEventListener("click", () => {
catalogSideLinks.forEach((item) => item.classList.toggle("is-active", item === link));
});
});
catalogLayer?.querySelectorAll('a[href="#"]').forEach((link) => {
link.addEventListener("click", (event) => event.preventDefault());
});
document.addEventListener("pointerdown", (event) => {
if (!catalogLayer?.classList.contains("is-open")) return;
if (catalogLayer.contains(event.target) || catalogTriggers.some((trigger) => trigger.contains(event.target))) return;
setCatalogOpen(false);
});
document.addEventListener("keydown", (event) => {
if (event.key !== "Escape" || !catalogLayer?.classList.contains("is-open")) return;
setCatalogOpen(false);
catalogButton?.focus();
});
const authModal = document.getElementById("authModal");
const authDialog = authModal?.querySelector(".auth-modal-dialog");
const authScreens = new Set(["login", "register", "recover", "success", "error"]);
let authReturnFocus = null;
const syncAuthScreenState = (screen = "login") => {
if (!authModal || !authScreens.has(screen)) return;
authModal.dataset.authScreen = screen;
authModal.querySelectorAll(".auth-tab").forEach((tab) => {
const active = tab.dataset.authScreenTarget === screen;
tab.setAttribute("aria-selected", active ? "true" : "false");
tab.tabIndex = active ? 0 : -1;
});
authModal.querySelectorAll(".auth-view").forEach((view) => {
const active = view.classList.contains(`auth-view-${screen}`);
view.setAttribute("aria-hidden", active ? "false" : "true");
});
};
const setAuthScreen = (screen = "login") => {
if (!authModal || !authScreens.has(screen)) return;
syncAuthScreenState(screen);
};
const setAuthOpen = (open, screen = "login", trigger = null) => {
if (!authModal) return;
if (open) {
authReturnFocus = trigger || document.activeElement;
setProfileOpen(false);
setCatalogOpen(false);
setMobileSearchOpen(false);
setAuthScreen(screen);
}
authModal.classList.toggle("is-open", open);
authModal.setAttribute("aria-hidden", open ? "false" : "true");
authModal.toggleAttribute("inert", !open);
document.body.classList.toggle("auth-modal-open", open);
if (open) {
window.setTimeout(() => authModal.querySelector("[data-auth-close]")?.focus(), 80);
} else if (authReturnFocus && typeof authReturnFocus.focus === "function") {
authReturnFocus.focus();
authReturnFocus = null;
}
};
document.querySelectorAll("[data-auth-open]").forEach((trigger) => {
trigger.addEventListener("click", (event) => {
event.preventDefault();
setAuthOpen(true, trigger.dataset.authOpen || "login", trigger);
});
});
authModal?.querySelectorAll("[data-auth-screen-target]").forEach((control) => {
control.addEventListener("click", () => setAuthScreen(control.dataset.authScreenTarget || "login"));
});
authModal?.querySelectorAll("[data-auth-close]").forEach((control) => {
control.addEventListener("click", () => setAuthOpen(false));
});
authModal?.addEventListener("pointerdown", (event) => {
if (event.target !== authModal || authDialog?.contains(event.target)) return;
setAuthOpen(false);
});
authModal?.querySelectorAll(".auth-form").forEach((form) => {
form.addEventListener("submit", (event) => {
event.preventDefault();
if (form.dataset.authForm === "recover") {
const email = form.querySelector('input[type="email"]')?.value.trim().toLowerCase() || "";
setAuthScreen(email.includes("error") || email.includes("fail") ? "error" : "success");
}
});
});
document.addEventListener("keydown", (event) => {
if (event.key !== "Escape" || !authModal?.classList.contains("is-open")) return;
setAuthOpen(false);
});
const initialAuthScreen = (() => {
const param = new URLSearchParams(window.location.search).get("auth");
const hash = window.location.hash.startsWith("#auth-") ? window.location.hash.replace("#auth-", "") : "";
return authScreens.has(param) ? param : authScreens.has(hash) ? hash : "";
})();
setAuthScreen("login");
if (initialAuthScreen) setAuthOpen(true, initialAuthScreen);
if (window.matchMedia("(pointer: coarse)").matches) {
let lastTouchEnd = 0;
const stopZoom = (event) => {
event.preventDefault();
};
const stopMultiTouch = (event) => {
if (event.touches && event.touches.length > 1) event.preventDefault();
};
document.addEventListener("gesturestart", stopZoom, { passive: false });
document.addEventListener("gesturechange", stopZoom, { passive: false });
document.addEventListener("gestureend", stopZoom, { passive: false });
document.addEventListener("touchstart", stopMultiTouch, { passive: false });
document.addEventListener("touchmove", stopMultiTouch, { passive: false });
document.addEventListener(
"touchend",
(event) => {
const now = Date.now();
if (now - lastTouchEnd < 320) event.preventDefault();
lastTouchEnd = now;
},
{ passive: false }
);
}
const amountInput = document.querySelector('input[name="amount"]');
const amountField = document.querySelector(".amount-field");
const servicesCard = document.querySelector(".services-card");
const topupQuickPopover = document.getElementById("topupQuickPopover");
const payButton = document.querySelector(".pay-btn");
const payCurrencyIcon = payButton?.querySelector(".currency-icon");
const promoToggleButton = document.querySelector(".promo-small");
const promoToggleLabel = promoToggleButton?.querySelector(".promo-small-label");
const topupDetails = document.getElementById("topupDetails");
const topupPromoSection = document.getElementById("topupPromoSection");
const topupPaymentSection = document.getElementById("topupPaymentSection");
const topupPromoInput = document.getElementById("topupPromoInput");
const topupPromoApply = document.querySelector(".topup-promo-apply");
const topupPromoBenefit = document.querySelector(".topup-promo-benefit");
const topupPromoSaving = document.querySelector("[data-promo-saving]");
const topupQuickAmounts = document.querySelectorAll("[data-quick-amount]");
const topupPaymentMethods = document.querySelectorAll(".topup-payment-method");
const topupCredit = document.querySelector("[data-topup-credit]");
const topupFeeBadge = document.querySelector("[data-topup-fee-badge]");
const topupFinalPay = document.querySelector(".topup-final-pay");
const maxTopupAmount = 100000;
let promoSectionOpen = false;
let paymentSectionOpen = false;
let promoApplied = false;
let selectedPaymentFee = 0;
let quickPopoverOpen = false;
const formatRubles = (value) => new Intl.NumberFormat("ru-RU").format(Math.max(0, Math.round(value)));
const syncQuickPopover = () => {
topupQuickPopover?.classList.toggle("is-open", quickPopoverOpen);
topupQuickPopover?.setAttribute("aria-hidden", quickPopoverOpen ? "false" : "true");
topupQuickPopover?.toggleAttribute("inert", !quickPopoverOpen);
amountInput?.setAttribute("aria-expanded", quickPopoverOpen ? "true" : "false");
servicesCard?.classList.toggle("has-quick-popover", quickPopoverOpen);
};
const syncTopupExpansion = () => {
const detailsOpen = promoSectionOpen || paymentSectionOpen;
topupDetails?.classList.toggle("is-open", detailsOpen);
topupDetails?.setAttribute("aria-hidden", detailsOpen ? "false" : "true");
topupDetails?.toggleAttribute("inert", !detailsOpen);
topupPromoSection?.classList.toggle("is-visible", promoSectionOpen);
topupPromoSection?.setAttribute("aria-hidden", promoSectionOpen ? "false" : "true");
topupPromoSection?.toggleAttribute("inert", !promoSectionOpen);
promoToggleButton?.setAttribute("aria-expanded", promoSectionOpen ? "true" : "false");
if (promoToggleLabel) promoToggleLabel.textContent = promoSectionOpen ? "Скрыть промокод" : "Ввести промокод";
topupPaymentSection?.classList.toggle("is-visible", paymentSectionOpen);
topupPaymentSection?.setAttribute("aria-hidden", paymentSectionOpen ? "false" : "true");
topupPaymentSection?.toggleAttribute("inert", !paymentSectionOpen);
payButton?.setAttribute("aria-expanded", paymentSectionOpen ? "true" : "false");
servicesCard?.classList.toggle("is-payment-open", paymentSectionOpen);
};
const syncAmount = () => {
if (!amountInput) return;
let value = amountInput.value.replace(/\D/g, "");
if (value) value = String(Math.min(Number(value), maxTopupAmount));
amountInput.value = value;
amountInput.style.setProperty("--amount-digits", String(Math.max(value.length, 3)));
const numericAmount = Number(value || 0);
if (payButton && payCurrencyIcon) {
payButton.textContent = `Оплатить ${value || 0}`;
payButton.append(payCurrencyIcon);
}
topupQuickAmounts.forEach((button) => {
button.classList.toggle("is-active", Number(button.dataset.quickAmount) === numericAmount);
});
if (topupCredit) topupCredit.textContent = `${formatRubles(numericAmount)} ₽`;
const amountToPay = numericAmount * (1 + selectedPaymentFee / 100);
if (topupFinalPay) topupFinalPay.textContent = `Оплатить ${formatRubles(amountToPay)}₽`;
if (topupFeeBadge) {
topupFeeBadge.textContent = selectedPaymentFee ? `+${selectedPaymentFee}% комиссия` : "Без комиссии";
topupFeeBadge.classList.toggle("has-fee", selectedPaymentFee > 0);
}
if (topupPromoSaving) topupPromoSaving.textContent = `${formatRubles(numericAmount * 0.05)} ₽`;
};
amountInput?.addEventListener("input", syncAmount);
amountInput?.addEventListener("focus", () => {
quickPopoverOpen = true;
syncQuickPopover();
});
amountInput?.addEventListener("click", () => {
quickPopoverOpen = true;
syncQuickPopover();
});
amountInput?.addEventListener("keydown", (event) => {
if (event.key !== "Escape") return;
quickPopoverOpen = false;
syncQuickPopover();
amountInput.blur();
});
amountInput?.addEventListener("blur", () => {
if (!amountInput.value) amountInput.value = "500";
syncAmount();
});
promoToggleButton?.addEventListener("click", () => {
promoSectionOpen = !promoSectionOpen;
syncTopupExpansion();
});
payButton?.addEventListener("click", () => {
quickPopoverOpen = false;
syncQuickPopover();
paymentSectionOpen = true;
syncTopupExpansion();
});
topupQuickAmounts.forEach((button) => {
button.addEventListener("click", () => {
if (!amountInput) return;
amountInput.value = button.dataset.quickAmount || "500";
syncAmount();
if (button.closest(".topup-quick-popover") && (!paymentSectionOpen || window.matchMedia("(min-width: 768px)").matches)) {
quickPopoverOpen = false;
syncQuickPopover();
}
});
});
document.addEventListener("pointerdown", (event) => {
if (!quickPopoverOpen || amountField?.contains(event.target)) return;
if (paymentSectionOpen && window.matchMedia("(max-width: 767px)").matches) return;
quickPopoverOpen = false;
syncQuickPopover();
});
topupPaymentMethods.forEach((method) => {
method.addEventListener("click", () => {
selectedPaymentFee = Number(method.dataset.fee || 0);
topupPaymentMethods.forEach((item) => {
const selected = item === method;
item.classList.toggle("is-selected", selected);
item.setAttribute("aria-checked", selected ? "true" : "false");
});
syncAmount();
});
});
topupPromoApply?.addEventListener("click", () => {
if (!topupPromoInput?.value.trim()) {
topupPromoInput?.focus();
return;
}
promoApplied = true;
topupPromoBenefit?.classList.add("is-visible");
topupPromoBenefit?.setAttribute("aria-hidden", "false");
topupPromoApply.textContent = "Применено";
syncAmount();
});
topupPromoInput?.addEventListener("input", () => {
if (!promoApplied) return;
promoApplied = false;
topupPromoBenefit?.classList.remove("is-visible");
topupPromoBenefit?.setAttribute("aria-hidden", "true");
if (topupPromoApply) topupPromoApply.textContent = "Применить";
});
syncTopupExpansion();
syncQuickPopover();
syncAmount();
const services = [
["service-steam.png", "Steam"],
["service-telegram.png", "Telegram"],
["service-roblox.png", "Roblox"],
["service-brawl.png", "Brawl Stars"],
["service-pubg.png", "PUBG Mob..."],
["service-appstore.png", "App Store"],
["service-chatgpt.png", "ChatGPT"],
["service-playstation.png", "PlayStation"],
["service-tiktok.png", "TikTok"],
["service-mobile.png", "Mobile Leg..."],
];
const servicesRow = document.getElementById("servicesRow");
if (servicesRow) {
services.forEach(([icon, label, active]) => {
servicesRow.insertAdjacentHTML(
"beforeend",
`<button class="service-item ${active ? "is-active" : ""}"><img src="./assets/${icon}" alt=""><span>${label}</span></button>`
);
});
servicesRow.insertAdjacentHTML(
"beforeend",
`<button class="service-item more-service"><span class="more-icon"><img class="more-icon-img" src="./assets/more-service.svg" alt=""></span><span>еще 841</span></button>`
);
}
const discountPattern = ["red", "orange", "red", "green", "red"];
const escapeHtml = (value) =>
String(value ?? "")
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
const catalogProducts = Array.isArray(window.playpapaCatalog?.products) ? window.playpapaCatalog.products : [];
const fallbackProducts = [
{
name: "DOOM 2016 STEAM KEY РФ+СНГ",
image_url: "./assets/product-pubg.png",
price_label: "990 ₽",
url: "/product",
},
];
const renderProducts = catalogProducts.length ? catalogProducts : fallbackProducts;
const productMarkup = (product, color, index) => `
<article class="product-card">
<div class="product-cover">
<img src="${escapeHtml(product.image_url || "./assets/product-pubg.png")}" alt="">
${product.discount_label ? `<span class="discount ${color}">${escapeHtml(product.discount_label)}</span>` : ""}
</div>
<div class="product-body">
<h3>${escapeHtml(product.name || "Товар PlayPapa")}</h3>
<div class="price-line"><strong>${escapeHtml(product.price_label || "Цена уточняется")}</strong></div>
<a href="${escapeHtml(product.url || "/product")}">Купить</a>
</div>
</article>
`;
document.querySelectorAll("[data-products]").forEach((grid) => {
const items = Array.from({ length: 5 }, (_, i) =>
productMarkup(renderProducts[i % renderProducts.length], discountPattern[i % discountPattern.length], i)
).join("");
grid.innerHTML = items;
});
</script>
<script src="/assets/playpapa-auth.js"></script>
</body>
</html>