<!DOCTYPE html><html lang="ru"><head> <meta charset="UTF-8" /> <title>👑 King WebApp</title> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> <script src="https://telegram.org/js/telegram-web-app.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js"></script> <!-- QR library --> <script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script> <style> /* ========= THEME / TOKENS ========= */ :root{ --bg: var(--tg-theme-bg-color, #0e0e12); --text: var(--tg-theme-text-color, #f7f7fb); --muted: var(--tg-theme-hint-color, #9aa0a6); --accent: var(--tg-theme-button-color, #8b5cf6); --accent-text: var(--tg-theme-button-text-color, #ffffff); --glass: rgba(255,255,255,.06); --stroke: rgba(255,255,255,.08); --radius: 16px; --shadow-1: 0 10px 30px rgba(0,0,0,.35); --shadow-2: 0 6px 18px rgba(0,0,0,.28); } *{ box-sizing:border-box; -webkit-tap-highlight-color:transparent; } html,body{ height:100%; } body{ margin:0; background: var(--bg); color: var(--text); font: 500 16px/1.4 "Inter","Segoe UI",system-ui,-apple-system,Roboto,Arial,sans-serif; letter-spacing:.2px; padding-bottom: calc(60px + 12px + env(safe-area-inset-bottom, 0px)); } /* ========= LIVING BACKGROUND ========= */ .bg{ position:fixed; inset:0; z-index:-2; overflow:hidden; background: radial-gradient(1200px 1200px at -10% -10%, rgba(139,92,246,.12), transparent 60%), radial-gradient(1000px 1000px at 110% 10%, rgba(56,189,248,.12), transparent 60%), radial-gradient(900px 900px at 80% 110%, rgba(236,72,153,.12), transparent 60%), var(--bg); } .blob{ position:absolute; filter:blur(40px); opacity:.55; mix-blend-mode:screen; border-radius:50%; animation:float 18s ease-in-out infinite; } .blob.b1{ width:380px;height:380px;background:#8b5cf6; left:-80px; top:-80px; animation-delay:0s; } .blob.b2{ width:320px;height:320px;background:#22d3ee; right:-60px; top:10vh; animation-delay:4s; } .blob.b3{ width:420px;height:420px;background:#f472b6; right:-120px; bottom:-120px; animation-delay:8s; } @keyframes float{ 0%,100%{ transform:translate3d(0,0,0) scale(1); } 50%{ transform:translate3d(0,-20px,0) scale(1.06); } } @media (prefers-reduced-motion: reduce){ .blob{ animation:none; } } /* ========= LAYOUT ========= */ .container{ max-width:480px; margin:0 auto; padding:18px 16px; } .tabs .tab-content{ display:none; } .tabs .tab-content.active{ display:block; } /* ========= GLASS ========= */ .glass{ background: var(--glass); border:1px solid var(--stroke); border-radius: var(--radius); box-shadow: var(--shadow-2); backdrop-filter: saturate(140%) blur(14px); -webkit-backdrop-filter: saturate(140%) blur(14px); } /* ========= PROFILE ========= */ .profile{ text-align:center; } .profile-header{ display:flex; flex-direction:column; align-items:center; padding:18px 12px 8px; } .avatar-wrapper{ display:inline-grid; place-items:center; margin-bottom:0; --av:92px; width:var(--av); height:var(--av); border-radius:50%; background:linear-gradient(180deg, rgba(255,255,255,.16), rgba(255,255,255,.04)); padding:2px; } .avatar-wrapper img{ width:100%; height:100%; object-fit:cover; border-radius:50%; box-shadow:0 0 0 2px rgba(255,255,255,.06), 0 8px 24px rgba(0,0,0,.35); animation:pulse 2.6s ease-in-out infinite; } @keyframes pulse{ 0%,100%{ box-shadow:0 0 0 2px rgba(255,255,255,.06), 0 8px 24px rgba(0,0,0,.35); transform:scale(1); } 50%{ box-shadow:0 0 0 2px rgba(139,92,246,.35), 0 12px 36px rgba(139,92,246,.25); transform:scale(1.02); } } .status-row{ width:100%; display:flex; justify-content:center; margin-top:10px; } .status-badge{ position:static!important; display:inline-flex; align-items:center; gap:8px; padding:6px 12px; border-radius:999px; font-size:12px; font-weight:700; background:linear-gradient(135deg, rgba(139,92,246,.25), rgba(56,189,248,.25)); border:1px solid rgba(255,255,255,.16); box-shadow:inset 0 0 0 1px rgba(255,255,255,.06), 0 4px 18px rgba(0,0,0,.22); margin:0!important; } .status-dot{ width:8px;height:8px;border-radius:50%;background:#22d3ee; box-shadow:0 0 10px #22d3ee; } .title{ margin:10px 0 2px; font-size:20px; font-weight:800; letter-spacing:.2px; } .muted{ color:var(--muted); font-size:13px; } .actions{ display:flex; justify-content:center; gap:12px; margin:14px 0 6px; } .circle-btn{ width:56px;height:56px;border-radius:16px; display:grid; place-items:center; background:linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.03)); border:1px solid var(--stroke); box-shadow:var(--shadow-1); transition:transform .12s ease, background .2s ease, border-color .2s ease; } .circle-btn:active{ transform:scale(.98); } .circle-btn svg{ width:24px;height:24px; stroke:var(--accent-text); } .circle-btn:hover{ border-color:rgba(139,92,246,.55); background:linear-gradient(180deg, rgba(139,92,246,.18), rgba(255,255,255,.04)); } .balance-card{ margin:14px 0 18px; padding:16px 18px; display:flex; align-items:center; justify-content:space-between; background: linear-gradient(135deg, rgba(139,92,246,.22), rgba(56,189,248,.18)), linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03)); border:1px solid rgba(139,92,246,.35); border-radius:18px; box-shadow:0 10px 30px rgba(139,92,246,.18); } .balance-card small{ color:var(--muted); display:block; margin-bottom:4px; } .balance-card strong{ font-size:22px; font-weight:800; letter-spacing:.3px; } /* ========= ACTIVITY ========= */ .activity-log{ padding:8px; } .activity-item{ display:flex; align-items:center; gap:12px; padding:12px; margin:10px 0; border-radius:14px; background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03)); border:1px solid var(--stroke); } .activity-icon{ width:36px; height:36px; border-radius:12px; display:grid; place-items:center; background:rgba(139,92,246,.18); color:#fff; flex:0 0 36px; } .activity-main{ display:flex; justify-content:space-between; align-items:center; gap:10px; width:100%; } .number{ font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } .date{ color:var(--muted); font-size:12px; white-space:nowrap; } /* ========= SECTIONS ========= */ .section-card{ padding:16px; border-radius:var(--radius); } .center{ text-align:center; } .lottie{ width:110px; height:110px; margin:4px auto 10px; } .headline{ font:800 20px/1.15 inherit; margin:4px 0 6px; } .subline{ font-size:14px; color:var(--muted); margin:0; } /* ========= TOP (под podium) ========= */ .top-three{ display:flex; justify-content:center; align-items:flex-end; gap:24px; margin:18px 0 8px; } .podium{ text-align:center; position:relative; } .podium img{ border-radius:50%; object-fit:cover; display:block; } .podium.p1 img{ width:108px; height:108px; border-radius:50%; box-shadow: 0 0 0 4px rgba(255,215,0,1), 0 0 12px rgba(255,215,0,.85), 0 4px 8px rgba(0,0,0,.45), 0 14px 28px rgba(255,215,0,.25); } .podium.p2 img{ width:90px; height:90px; border-radius:50%; box-shadow: 0 0 0 4px rgba(192,192,192,1), 0 0 12px rgba(192,192,192,.75), 0 4px 8px rgba(0,0,0,.45), 0 14px 28px rgba(192,192,192,.20); } .podium.p3 img{ width:90px; height:90px; border-radius:50%; box-shadow: 0 0 0 4px rgba(205,127,50,1), 0 0 12px rgba(205,127,50,.75), 0 4px 8px rgba(0,0,0,.45), 0 14px 28px rgba(205,127,50,.20); } .medal { position: absolute; top: -12px; left: 50%; transform: translateX(-50%); width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; font-weight: 900; font-size: 14px; letter-spacing: .2px; color: #111; background: radial-gradient(circle at 30% 30%, #ffffff, #ffd700); border: 1px solid rgba(255, 255, 255, .55); box-shadow: 0 4px 12px rgba(255, 215, 0, .55), inset 0 1px 2px rgba(255, 255, 255, .85), 0 0 0 4px rgba(255, 215, 0, .45); backdrop-filter: blur(4px) saturate(150%); -webkit-backdrop-filter: blur(4px) saturate(150%); z-index: 2; } .podium.p2 .medal { background: radial-gradient(circle at 30% 30%, #ffffff, #c0c0c0); box-shadow: 0 4px 12px rgba(192, 192, 192, .55), inset 0 1px 2px rgba(255, 255, 255, .85), 0 0 0 4px rgba(192, 192, 192, .45); } .podium.p3 .medal { background: radial-gradient(circle at 30% 30%, #ffffff, #cd7f32); box-shadow: 0 4px 12px rgba(205, 127, 50, .55), inset 0 1px 2px rgba(255, 255, 255, .85), 0 0 0 4px rgba(205, 127, 50, .45); } .top-list{ margin-top:8px; } .row{ display:flex; align-items:center; gap:12px; padding:10px 12px; border-bottom:1px dashed rgba(255,255,255,.06); } .row:last-child{ border-bottom:none; } .row .ava{ width:42px;height:42px;border-radius:50%; object-fit:cover; border:2px solid rgba(139,92,246,.5); } .row .nm{ font-weight:600; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; } .row .cnt{ margin-left:auto; color:var(--muted); font-size:13px; } /* ========= QUEUE ========= */ .queue-card{ padding:14px; border-radius:var(--radius); } .queue-top{ display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; } .queue-name{ display:flex; align-items:center; gap:10px; font-weight:700; } .queue-name img{ width:24px; height:24px; } .queue-status{ font-weight:800; } .queue-status.off{ color:#ef4444; } .queue-status.on{ color:#22c55e; } .queue-stats{ display:grid; grid-template-columns:repeat(3,1fr); gap:10px; } .q-item{ padding:10px 8px; border-radius:12px; text-align:center; border:1px solid var(--stroke); background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03)); } .q-item small{ display:block; color:var(--muted); margin-bottom:2px; } .q-item strong{ font-size:16px; } /* ========= REF (QR вариант) ========= */ .sr-only{ position:absolute!important; width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0; } .ref-qr{ margin-top:12px; display:grid; grid-template-columns: 92px 1fr; gap:12px; padding:12px; border-radius:14px; border:1px solid rgba(255,255,255,.12); background: linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03)); } .qr-box{ width:92px; height:92px; border-radius:10px; overflow:hidden; background:#fff; display:grid; place-items:center; } .qr-side{ display:grid; gap:8px; align-content:start; } .chip{ display:flex; align-items:center; gap:8px; padding:27px 12px; border-radius:12px; background: rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.14); box-shadow: inset 0 0 0 1px rgba(255,255,255,.06); } .chip__url { flex: 1; min-width: 0; max-width: 93px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .icon-btn{ display:grid; place-items:center; width:36px; height:36px; border-radius:10px; background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.12); color:var(--text); } .icon-btn:active{ transform:scale(.98); } .qr-buttons{ display:flex; gap:8px; } .cta{ width:100%; margin-top:10px; padding:12px 14px; border:0; border-radius:12px; cursor:pointer; font-weight:800; color: var(--accent-text); background: linear-gradient(90deg, #8b5cf6, #22d3ee, #ec4899); background-size: 200% 100%; animation: gradientMove 8s linear infinite; box-shadow: 0 10px 28px rgba(139,92,246,.28); } @keyframes gradientMove{ 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } /* ========= BOTTOM NAV ========= */ .bottom-nav{ position:fixed; left:0; right:0; bottom:0; max-width:480px; margin:0 auto; padding:8px 10px; z-index:100; } .nav-wrap{ height:60px; padding:0 8px; border-radius:20px; background:rgba(18,18,22,.6); border:1px solid rgba(255,255,255,.08); box-shadow:0 10px 30px rgba(0,0,0,.45); backdrop-filter: blur(10px) saturate(130%); -webkit-backdrop-filter: blur(10px) saturate(130%); display:grid; grid-template-columns:repeat(4,1fr); align-items:center; position:relative; overflow:hidden; } .nav-item{ display:flex; flex-direction:column; align-items:center; gap:6px; justify-content:center; height:100%; color:var(--muted); text-decoration:none; font-size:12px; font-weight:700; position:relative; z-index:1; } .nav-item svg{ width:22px; height:22px; stroke:currentColor; opacity:.9; } .nav-item.active{ color:#fff; } .nav-pill{ position:absolute; top:8px; bottom:8px; left:0; width:0; border-radius:16px; background:linear-gradient(180deg, rgba(139,92,246,.35), rgba(255,255,255,.06)); transition: transform .22s ease, width .22s ease; will-change: transform, width; pointer-events:none; } /* ========= SKELETON / UTILS ========= */ .skeleton{ position:relative; overflow:hidden; border-radius:12px; background:rgba(255,255,255,.06); } .skeleton::after{ content:""; position:absolute; inset:0; transform:translateX(-100%); background:linear-gradient(90deg, transparent, rgba(255,255,255,.12), transparent); animation:shimmer 1.3s infinite; } @keyframes shimmer{ 100%{ transform:translateX(100%); } } .error{ color:#ff6b6b; text-align:center; padding:14px 0; } .mt-12{ margin-top:12px; } .mt-16{ margin-top:16px; } /* ========= SETTINGS SHEET — expanded tabs ========= */ .sheet-wrap{ display:grid; gap:12px; } .sheet-tabs{ display:flex; gap:8px; flex-wrap:wrap; background: linear-gradient(135deg, rgba(255,255,255,.08), rgba(255,255,255,.03)); border:1px solid rgba(255,255,255,.10); border-radius:14px; padding:6px; } .sheet-tab-btn{ padding:10px 12px; border:0; border-radius:12px; cursor:pointer; font-weight:800; letter-spacing:.2px; color:inherit; background:transparent; } .sheet-tab-btn.active{ background: radial-gradient(120% 150% at 50% 0%, rgba(139,92,246,.28), rgba(139,92,246,0) 70%), linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,.04)); box-shadow: 0 6px 18px rgba(139,92,246,.22), inset 0 1px 0 rgba(255,255,255,.2); } .sheet-panels{ position:relative; } .sheet-panel{ display:none; } .sheet-panel.active{ display:block; } .kpi-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; } @media (min-width: 480px){ .kpi-grid{ grid-template-columns:repeat(4,minmax(0,1fr)); } } .kpi{ padding:12px; border-radius:14px; text-align:left; background: linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.04)); border:1px solid rgba(255,255,255,.10); box-shadow: inset 0 1px 0 rgba(255,255,255,.12); } .kpi small{ color:var(--muted); display:block; margin-bottom:4px; } .kpi strong{ font-size:18px; font-weight:900; } .list{ display:grid; } .item{ display:grid; grid-template-columns: 1fr auto; align-items:center; gap:12px; padding:12px; border-bottom:1px dashed rgba(255,255,255,.08); } .item:last-child{ border-bottom:none; } .item .meta{ display:grid; gap:4px; } .badge{ display:inline-flex; align-items:center; gap:6px; padding:4px 8px; border-radius:999px; font-size:12px; font-weight:800; border:1px solid rgba(255,255,255,.14); background:rgba(255,255,255,.06); } .btn{ display:inline-flex; align-items:center; gap:8px; padding:10px 12px; border-radius:12px; border:1px solid rgba(255,255,255,.12); background: linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.04)); color:inherit; cursor:pointer; font-weight:800; } .btn:active{ transform:scale(.98); } .btn.primary{ color: var(--accent-text); background: linear-gradient(90deg,#8b5cf6,#22d3ee,#ec4899); background-size:200% 100%; animation: gradientMove 8s linear infinite; border-color: rgba(139,92,246,.45); } @keyframes gradientMove{ 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } .progress-bar{ position:relative; height:10px; border-radius:999px; overflow:hidden; background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.10); } .progress-bar > span{ position:absolute; left:0; top:0; bottom:0; width:0%; background:linear-gradient(90deg,#8b5cf6,#22d3ee,#ec4899); transition:width .3s ease; } .skeleton-line{ height:16px; border-radius:8px; background:rgba(255,255,255,.08); position:relative; overflow:hidden; } .skeleton-line::after{ content:""; position:absolute; inset:0; transform:translateX(-100%); background:linear-gradient(90deg, transparent, rgba(255,255,255,.14), transparent); animation: shimmer 1.4s infinite; } @keyframes shimmer{ 100%{ transform:translateX(100%);} } .empty{ color:var(--muted); text-align:center; padding:16px 8px; } .error{ color:#ff6b6b; text-align:center; padding:12px 8px; } </style></head><body> <!-- живой фон --> <div class="bg"> <div class="blob b1"></div> <div class="blob b2"></div> <div class="blob b3"></div> </div> <div class="container"> <div class="tabs"> <!-- Игры --><section id="tab-friends" class="tab-content"> <div class="glass section-card center profit-calc"> <h2 class="headline">Калькулятор прибыли</h2> <p class="subline">Выбери сервис, часы и количество номеров</p> <!-- Сервисы --> <div class="service-switch" role="tablist" aria-label="Сервисы"> <button class="svc-btn active" data-svc="vk" aria-selected="true">VK</button> <button class="svc-btn" data-svc="wa" aria-selected="false">WhatsApp</button> <button class="svc-btn" data-svc="max" aria-selected="false">MAX</button> </div> <!-- Ползунки --> <div class="sliders"> <div class="slider-row"> <div class="slider-head"> <span>Часы работы</span> <strong id="hoursVal">1 ч</strong> </div> <input id="hoursRange" type="range" min="1" max="24" step="1" value="1" /> <div class="ticks"> <span>1</span><span>6</span><span>12</span><span>18</span><span>24</span> </div> </div> <div class="slider-row"> <div class="slider-head"> <span>Кол-во номеров</span> <strong id="qtyVal">1</strong> </div> <input id="qtyRange" type="range" min="1" max="200" step="1" value="1" /> <div class="ticks"> <span>1</span><span>50</span><span>100</span><span>150</span><span>200</span> </div> </div> </div> <!-- Итоги --> <div class="result-grid"> <div class="result-card"> <span class="label">Сервис</span> <div class="value" id="svcName">VK</div> </div> <div class="result-card"> <span class="label">Ставка/час (текущий слой)</span> <div class="value" id="rateNow">$2.50</div> <div class="hint" id="layerHint">1–2 ч: $2.50/ч</div> </div> <div class="result-card"> <span class="label">Итого за 1 номер</span> <div class="value accent" id="perOne">$2.50</div> </div> <div class="result-card total"> <span class="label">Итого за все номера</span> <div class="value big" id="grandTotal">$2.50</div> </div> </div> <p class="fine-print"> Модель выплат: базовая ставка за 1–2 ч, затем каждые 2 часа ставка растёт на размер базовой.<br> Примеры: VK — $2.5/ч, 3–4 ч: $5/ч, 5–6 ч: $7.5/ч. WA — $4/ч, затем $8/ч, $12/ч… MAX — $5/ч, затем $10/ч, $15/ч… </p> </div></section> <style>/* ---- калькулятор ---- */.profit-calc { padding: 18px 16px 20px; max-width: 860px; margin: 0 auto; }.profit-calc .headline { margin-top: 6px; }.profit-calc .subline { opacity: .9; margin-bottom: 16px; } /* Переключатель сервисов */.service-switch{ display:flex; gap:8px; padding:6px; border-radius:16px; background: linear-gradient(135deg, rgba(255,255,255,.08), rgba(255,255,255,.03)); box-shadow: inset 0 1px 0 rgba(255,255,255,.09); width:100%; justify-content:center; margin: 6px 0 14px;}.svc-btn{ position:relative; padding:10px 14px; border-radius:12px; border:0; cursor:pointer; font-weight:700; letter-spacing:.2px; background:transparent; color:inherit; transition: transform .08s ease, background .2s ease;}.svc-btn.active{ background: radial-gradient(120% 150% at 50% 0%, rgba(255,165,0,.20), rgba(255,165,0,0) 70%) , linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,.04)); box-shadow: 0 6px 20px rgba(255,165,0,.15), inset 0 1px 0 rgba(255,255,255,.2);}.svc-btn:active{ transform: scale(.98); } /* Ползунки */.sliders{ display:grid; gap:16px; width:100%; }.slider-row{ background: rgba(255,255,255,.06); border-radius:16px; padding:12px 14px; }.slider-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }.slider-head strong{ font-weight:800; }.ticks{ display:flex; justify-content:space-between; font-size:12px; opacity:.7; margin-top:6px; }input[type="range"]{ -webkit-appearance: none; appearance: none; width:100%; height:10px; border-radius:999px; background: var(--rng-bg, linear-gradient(90deg,currentColor 0%, currentColor 0%, rgba(255,255,255,.18) 0%)); outline: none;}input[type="range"]::-webkit-slider-thumb{ -webkit-appearance: none; appearance: none; width:24px; height:24px; border-radius:50%; background: #fff; box-shadow: 0 6px 16px rgba(0,0,0,.25), 0 0 0 6px rgba(255,165,0,.25); border: 3px solid rgba(255,165,0,.9);}input[type="range"]::-moz-range-thumb{ width:24px; height:24px; border-radius:50%; background:#fff; border:3px solid rgba(255,165,0,.9); box-shadow: 0 6px 16px rgba(0,0,0,.25), 0 0 0 6px rgba(255,165,0,.25);}input[type="range"]::-moz-range-progress{ background: currentColor; height:10px; border-radius:999px; } /* Итоги */.result-grid{ display:grid; gap:12px; grid-template-columns: repeat(4,minmax(0,1fr)); margin-top:16px;}.result-card{ background: linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.05)); border-radius:16px; padding:12px 14px; text-align:left; box-shadow: inset 0 1px 0 rgba(255,255,255,.12);}.result-card.total{ grid-column: span 2; }@media (max-width: 780px){ .result-grid{ grid-template-columns: repeat(2,minmax(0,1fr)); } .result-card.total{ grid-column: span 2; }}.label{ font-size:12px; opacity:.8; }.value{ font-weight:800; font-size:18px; margin-top:2px; }.value.big{ font-size:24px; }.value.accent{ background: linear-gradient(90deg, #ffd39a, #fff); -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 0 0 24px rgba(255,165,0,.25);}.hint{ font-size:12px; opacity:.75; margin-top:2px; }.fine-print{ font-size:12px; opacity:.7; margin-top:12px; } /* Цвет заливки трека по значению */.profit-calc input[type="range"]{ color: rgba(255,165,0, .95); }</style> <script>(() => { // Фиксированные ставки за каждый ОПЛАЧИВАЕМЫЙ (нечётный) час const BASE = { vk: 2.5, wa: 4, max: 5 }; const NAMES = { vk: "VK", wa: "WhatsApp", max: "MAX" }; const svcButtons = document.querySelectorAll('.svc-btn'); const hoursRange = document.getElementById('hoursRange'); const qtyRange = document.getElementById('qtyRange'); const hoursVal = document.getElementById('hoursVal'); const qtyVal = document.getElementById('qtyVal'); const svcNameEl = document.getElementById('svcName'); const rateNowEl = document.getElementById('rateNow'); const layerHint = document.getElementById('layerHint'); const perOneEl = document.getElementById('perOne'); const totalEl = document.getElementById('grandTotal'); let currentSvc = 'vk'; function paintTrack(input){ const min = +input.min, max = +input.max, val = +input.value; const pct = ((val - min) / (max - min)) * 100; input.style.setProperty('--rng-bg', `linear-gradient(90deg, currentColor ${pct}%, rgba(255,255,255,.18) ${pct}%)`); } // 👉 Оплата за текущий (выбранный) час: фиксированная ставка, только если час нечётный function hourlyRateAtHour(base, hour){ return (hour % 2 === 1) ? base : 0; } // 👉 Итог за N часов: платим только за нечётные, их количество = ceil(N/2) function sumForHours(base, hours){ const paidHours = Math.ceil(hours / 2); return base * paidHours; } function fmt(n){ return `$${n.toFixed(2)}`; } function update(){ const hours = +hoursRange.value; const qty = +qtyRange.value; const base = BASE[currentSvc]; const rateNow = hourlyRateAtHour(base, hours); // фиксированная ставка или 0 const perOne = sumForHours(base, hours); // сумма за 1 номер const grand = perOne * qty; // общая сумма const hint = (hours % 2 === 1) ? `${hours}-й час оплачивается: ${fmt(base)}/ч (фикс)` : `${hours}-й час не оплачивается`; svcNameEl.textContent = NAMES[currentSvc]; rateNowEl.textContent = fmt(rateNow); layerHint.textContent = `Оплата только за нечётные часы (1, 3, 5, …). Фиксированная ставка ${fmt(base)} за каждый оплачиваемый час. ${hint}`; perOneEl.textContent = fmt(perOne); totalEl.textContent = fmt(grand); hoursVal.textContent = `${hours} ч`; qtyVal.textContent = `${qty}`; paintTrack(hoursRange); paintTrack(qtyRange); } svcButtons.forEach(btn => { btn.addEventListener('click', () => { svcButtons.forEach(b => { b.classList.remove('active'); b.setAttribute('aria-selected','false'); }); btn.classList.add('active'); btn.setAttribute('aria-selected','true'); currentSvc = btn.dataset.svc; update(); }); }); hoursRange.addEventListener('input', update); qtyRange.addEventListener('input', update); paintTrack(hoursRange); paintTrack(qtyRange); update();})();</script> <!-- Топ --> <section id="tab-top" class="tab-content"> <div class="glass section-card center"> <div id="topLottie" class="lottie"></div> <h2 class="headline">Топ сдающих</h2> <p class="subline">Ежедневный рейтинг активности</p> </div> <div id="topList" class="glass section-card mt-12"> <div class="skeleton" style="height:70px;margin-bottom:8px;"></div> <div class="skeleton" style="height:70px;margin-bottom:8px;"></div> <div class="skeleton" style="height:70px;"></div> </div> </section> <!-- Реф --> <section id="tab-ref" class="tab-content"> <div class="glass section-card"> <div id="Que_stk" class="lottie"></div> <h2 class="headline center">Реферальная программа</h2> <p class="subline center">Приглашайте друзей и получайте бонусы</p> <!-- QR вариант --><div class="ref-qr"> <div id="qrBox" class="qr-box"></div> <div class="qr-side"> <div class="chip" id="refChip" title="Нажми стрелку, чтобы развернуть ссылку"> <button class="icon-btn icon-sm" id="refExpandBtn" aria-label="Развернуть/свернуть">▾</button> <span id="refLinkText" class="chip__url">https://t.me/king_wa_bot?start=...</span> <button class="icon-btn" id="refCopyBtn" aria-label="Скопировать"> <svg viewBox="0 0 24 24" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2"> <rect x="9" y="9" width="13" height="13" rx="2"></rect> <rect x="2" y="2" width="13" height="13" rx="2"></rect> </svg> </button> <button class="icon-btn" id="refShareBtn" aria-label="Поделиться">↗️</button> </div> </div> <input id="refLinkField" type="text" readonly class="sr-only"></div> <div class="glass section-card mt-12" id="ref-balance-card"> <div style="display:flex;align-items:center;justify-content:space-between;"> <div> <small class="muted">Баланс</small> <div style="font-size:22px;font-weight:800;"><span id="ref-balance">0.00</span> <span class="muted" style="font-size:12px;">SM</span></div> <div class="muted" id="ref-usd">≈ $0.00</div> </div> <button class="icon-btn" disabled style="cursor:not-allowed;opacity:.6;">💸</button> </div> </div> </div> </section> <!-- Очередь --> <section id="tab-nft" class="tab-content"> <div class="glass section-card center"> <div id="Que_stk_queue" class="lottie"></div> <h2 class="headline">📦 Очередь</h2> <p class="subline">Актуальная статистика</p> </div> <div class="glass section-card queue-card"> <div class="queue-top"> <div class="queue-name"> <img src="https://img.icons8.com/color/48/whatsapp.png" alt="wa"> <span>WhatsApp Россия</span> </div> <div class="queue-status off" id="queueStatus">Не работает</div> </div> <div class="queue-stats"> <div class="q-item"><small>В работе</small><strong id="workNow">0</strong></div> <div class="q-item"><small>В очереди</small><strong id="inQueue">0</strong></div> <div class="q-item"><small>Ожидание</small><strong id="waitTime">-</strong></div> </div> </div> </section> <!-- Профиль (дефолт) --> <section id="tab-profile" class="tab-content active"> <div class="glass section-card profile"> <div class="profile-header"> <div class="avatar-wrapper"> <img id="avatar" src="https://via.placeholder.com/92" alt="avatar"> </div> <div class="status-row"> <div class="status-badge"><span class="status-dot"></span><span id="statusLabel">Новичок</span></div> </div> <div class="title" id="userName">Загрузка…</div> <div class="muted" id="userId">ID: —</div> </div> <div class="actions"> <button class="circle-btn" title="Сдать номер" onclick="openBot('start=sdat')" aria-label="Сдать номер"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"> <path d="M16 2v6h6"/><path d="m22 2-6 6"/><path d="M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <button class="circle-btn" title="Профиль" onclick="openBot('start=cb_drop_status')" aria-label="Профиль"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"> <rect width="20" height="14" x="2" y="5" rx="2" stroke="currentColor" stroke-width="2"/> <line x1="2" x2="22" y1="10" y2="10" stroke="currentColor" stroke-width="2"/> </svg> </button> <button class="circle-btn" title="Статистика" onclick="openBot('start=cb_profile_analytics')" aria-label="Статистика"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"> <path d="M3 3v18h18" stroke="currentColor" stroke-width="2"/> <path d="M7 12v5" stroke="currentColor" stroke-width="2"/> <path d="M12 8v9" stroke="currentColor" stroke-width="2"/> <path d="M17 5v13" stroke="currentColor" stroke-width="2"/> </svg> </button> <button class="circle-btn" title="Пополнить" onclick="openBot('start=cb_business_topup')" aria-label="Пополнить"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"> <path d="M6 8.32a7.43 7.43 0 0 1 0 7.36" stroke="currentColor" stroke-width="2"/> <path d="M9.46 6.21a11.76 11.76 0 0 1 0 11.58" stroke="currentColor" stroke-width="2"/> <path d="M12.91 4.1a15.91 15.91 0 0 1 .01 15.8" stroke="currentColor" stroke-width="2"/> <path d="M16.37 2a20.16 20.16 0 0 1 0 20" stroke="currentColor" stroke-width="2"/> </svg> </button> </div> <div class="balance-card"> <div> <small>Ваш бизнес баланс</small> <strong id="balanceValue" data-usd="0">$0</strong> </div> <button class="icon-btn" onclick="openSheet('Настройки', 'settings')">⚙️</button> </div> <div id="logContainer" class="activity-log"> <div class="skeleton" style="height:52px;margin-bottom:8px;"></div> <div class="skeleton" style="height:52px;margin-bottom:8px;"></div> <div class="skeleton" style="height:52px;"></div> </div> </div> </section> </div> </div> <!-- Bottom Navigation --> <nav class="bottom-nav" role="navigation" aria-label="Нижняя навигация"> <div class="nav-wrap glass" id="navWrap"> <div class="nav-pill" id="navPill"></div> <a class="nav-item" data-tab="friends" onclick="setTab(this)"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 4H16L18 8V12L16 16H8L6 12V8L8 4z M10 10h4M10 14h4"/> </svg> <span>Ставка</span> </a> <a class="nav-item" data-tab="top" onclick="setTab(this)"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 17.27L18.18 21l-1.63-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.45 4.73L5.82 21z"/> </svg> <span>Топ</span> </a> <a class="nav-item" data-tab="ref" onclick="setTab(this)"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1M12 8h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> </svg> <span>Реф</span> </a> <a class="nav-item active" data-tab="profile" onclick="setTab(this)"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5.121 17.804A9 9 0 1118.88 6.196 9 9 0 015.121 17.804z M15 11a3 3 0 11-6 0 3 3 0 016 0z M12 14a6 6 0 00-5 2.292"/> </svg> <span>Профиль</span> </a> </div> </nav> <!-- Bottom Sheet --> <div id="bottomSheet" class="glass" style="position:fixed;left:0;right:0;bottom:-100%;max-width:480px;margin:0 auto;height:88%;border-top-left-radius:18px;border-top-right-radius:18px;transition:bottom .35s ease;z-index:120;"> <div style="display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--stroke);"> <span id="sheetTitle" style="font-weight:800;">Загрузка…</span> <button onclick="closeSheet()" class="icon-btn">✖</button> </div> <div id="sheetContent" style="padding:16px;"> <p class="muted">⏳ Пожалуйста, подождите…</p> </div> </div> <!-- Lottie init --> <script> document.addEventListener('DOMContentLoaded', () => { const s1 = document.getElementById('gameSticker'); s1 && lottie.loadAnimation({ container: s1, renderer:'svg', loop:true, autoplay:true, path:'11.json' }); const s2 = document.getElementById('topLottie'); s2 && lottie.loadAnimation({ container: s2, renderer:'svg', loop:true, autoplay:true, path:'emostar_1414.json' }); const s3 = document.getElementById('Que_stk'); s3 && lottie.loadAnimation({ container: s3, renderer:'svg', loop:true, autoplay:true, path:'Que_stk.json' }); const s4 = document.getElementById('Que_stk_queue'); s4 && lottie.loadAnimation({ container: s4, renderer:'svg', loop:true, autoplay:true, path:'Que_stk.json' }); }); </script> <!-- Helpers / Telegram --> <script> const tg = window.Telegram?.WebApp; tg?.expand?.(); function hapticClick(){ try{ tg?.HapticFeedback?.impactOccurred?.("light"); }catch(e){} } function openBot(query){ hapticClick(); window.open(`https://t.me/king_wa_bot?${query}`, "_blank"); } function waitForTelegramUser(callback, timeout=1200){ const start = Date.now(); (function check(){ const user = Telegram?.WebApp?.initDataUnsafe?.user; if (user?.id) return callback(user.id, user); if (Date.now() - start < timeout) return setTimeout(check, 50); console.warn("⛔ Telegram user.id не доступен"); })(); } </script> <!-- Data loaders --> <script> function loadTop(){ const list = document.getElementById('topList'); fetch('get_top.php') .then(r=>r.json()) .then(data=>{ list.innerHTML = ''; const top = Array.isArray(data.top) ? data.top : []; const podiumRaw = top.slice(0,3); const podium = [podiumRaw[1], podiumRaw[0], podiumRaw[2]].filter(Boolean); const others = top.slice(3); const wrap = document.createElement('div'); wrap.className='glass section-card'; const podiumEl = document.createElement('div'); podiumEl.className='top-three'; podium.forEach((u,i)=>{ const place = [2,1,3][i]; const p = document.createElement('div'); p.className = `podium p${place}`; p.innerHTML = ` <div class="medal">${place}</div> <img src="${u.photo || 'https://via.placeholder.com/96'}" alt=""> <div style="margin-top:8px;font-weight:700">${u.name}</div> <div class="muted" style="font-size:12px">${u.count}</div> `; podiumEl.appendChild(p); }); wrap.appendChild(podiumEl); list.appendChild(wrap); const rest = document.createElement('div'); rest.className='glass section-card mt-12'; others.forEach((u,i)=>{ const row = document.createElement('div'); row.className='row'; row.innerHTML = ` <img class="ava" src="${u.photo || 'https://via.placeholder.com/60'}" alt=""> <div class="nm">#${i+4} ${u.name}</div> <div class="cnt">${u.count}</div> `; rest.appendChild(row); }); list.appendChild(rest); }) .catch(()=>{ list.innerHTML = '<div class="error">❌ Не удалось загрузить топ.</div>'; }); } function loadQueueCard(){ fetch("get_queues.php") .then(res=>res.json()) .then(data=>{ document.getElementById("workNow").textContent = data.working_now ?? 0; document.getElementById("inQueue").textContent = data.in_queue ?? 0; document.getElementById("waitTime").textContent = data.estimated_wait ?? "-"; const st = document.getElementById("queueStatus"); if (data.status === "on"){ st.textContent="Работает"; st.classList.remove('off'); st.classList.add('on'); } else { st.textContent="Не работает"; st.classList.remove('on'); st.classList.add('off'); } }) .catch(()=>{ document.querySelector("#tab-nft .queue-card").innerHTML = '<div class="error">❌ Ошибка загрузки данных.</div>'; }); } function initRef(userId){ const refLink = `https://t.me/king_wa_bot?start=${userId}`; const fld = document.getElementById("refLinkField"); if (fld) fld.value = refLink; const txt = document.getElementById("refLinkText"); if (txt) txt.textContent = refLink; const qrBox = document.getElementById('qrBox'); if (qrBox){ qrBox.innerHTML = ""; new QRCode(qrBox, { text: refLink, width: 92, height: 92, colorDark : "#000000", colorLight : "#ffffff", correctLevel : QRCode.CorrectLevel.M }); } document.getElementById("refCopyBtn")?.addEventListener('click', ()=>{ navigator.clipboard.writeText(refLink).then(()=> alert("Ссылка скопирована!")); hapticClick(); }); document.getElementById("refShareBtn")?.addEventListener('click', ()=>{ const message = `👑 Присоединяйся к King WhatsApp и зарабатывай!\n\n${refLink}`; if (Telegram?.WebApp?.platform !== "unknown") { window.open(`https://t.me/share/url?url=${encodeURIComponent(message)}`, "_blank"); } else if (navigator.share) { navigator.share({ title: "King WhatsApp", text: message, url: refLink }).catch(()=>{}); } else { navigator.clipboard.writeText(refLink).then(()=> alert("Ссылка скопирована!")); } hapticClick(); }); fetch("get_ref_data.php", { method:"POST", headers:{ "Content-Type":"application/json" }, body: JSON.stringify({ telegram_id: userId }) }) .then(res=>res.json()) .then(data=>{ document.getElementById("ref-balance").textContent = (data.balance ?? 0).toFixed(2); document.getElementById("ref-usd").textContent = `≈ $${(data.balance_usd ?? 0).toFixed(2)}`; const footer = document.getElementById("ref-footer"); const list = document.getElementById("ref-list"); const arr = Array.isArray(data.referrals) ? data.referrals : []; if (!arr.length){ footer && (footer.textContent = "Вы ещё никого не пригласили"); return; } footer && (footer.textContent = `Приглашено: ${arr.length}`); if (!list) return; list.innerHTML = ""; arr.forEach(r=>{ const row = document.createElement("div"); row.className = "row"; row.innerHTML = ` <img class="ava" src="${r.photo || 'https://cdn-icons-png.flaticon.com/512/149/149071.png'}" alt=""> <div class="nm">${r.name}</div> <div class="cnt">+${r.earned} SM</div> `; list.appendChild(row); }); }) .catch(()=>{ const f = document.getElementById("ref-footer"); if (f) f.innerHTML = "<span class='error'>❌ Ошибка загрузки</span>"; }); } </script> <!-- Profile load --> <script> let usdToRubRate = 92.5; // fallback fetch('https://www.cbr-xml-daily.ru/daily_json.js') .then(r=>r.json()) .then(d=>{ usdToRubRate = d?.Valute?.USD?.Value || usdToRubRate; }) .catch(()=>{}); function renderProfile(userId, user){ document.getElementById('userId').textContent = `ID: ${userId}`; if (user?.photo_url) document.getElementById('avatar').src = user.photo_url; fetch("check_user.php", { method:"POST", headers:{ "Content-Type":"application/json" }, body: JSON.stringify({ telegram_id: userId }) }) .then(r=>r.json()) .then(data=>{ document.getElementById('userName').textContent = data.name || "Пользователь"; document.getElementById('balanceValue').dataset.usd = data.balance ?? 0; document.getElementById('balanceValue').textContent = `$${data.balance ?? 0}`; document.getElementById('statusLabel').textContent = data.status || "Новичок"; const logWrap = document.getElementById('logContainer'); const actions = Array.isArray(data.actions) ? data.actions : []; if (!actions.length){ logWrap.innerHTML = `<div class="muted center">Нет последних действий</div>`; } else{ logWrap.innerHTML = actions.map(a=>` <div class="activity-item"> <div class="activity-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none"> <rect x="2" y="2" width="14" height="14" rx="3" stroke="currentColor" stroke-width="2"/> </svg> </div> <div class="activity-main"> <div class="number">${a.number}</div> <div class="date">${a.date}</div> </div> </div> `).join(''); } }) .catch(()=>{ document.getElementById('logContainer').innerHTML = `<div class="error">❌ Ошибка загрузки профиля</div>`; }); } waitForTelegramUser((id, user)=>{ renderProfile(id, user); initRef(id); }); </script> <!-- Bottom sheet views (оригинальные) --> <script> function openSheet(title, type){ document.getElementById('sheetTitle').textContent = title; const c = document.getElementById('sheetContent'); const views = { settings: ` <div class="glass section-card"> <h3 style="margin:0 0 8px;">Настройки</h3> <p class="muted">Управляйте приложением и быстрыми действиями</p> <div class="mt-12" style="display:grid;gap:8px;"> <button class="icon-btn" onclick="requestAddToHome()">📲</button> <div id="homeStatus" class="muted"></div> </div> </div> `, balance: `<div class="glass section-card center"><div class="muted">📱 Сдать номер в боте</div><p class="mt-12"><button class="cta" onclick="openBot('start=sdat')">Сдать номер</button></p></div>`, numbers: `<div class="glass section-card center"><div class="muted">📦 Ваши номера</div><p class="mt-12"><button class="cta" onclick="openBot('start=cb_drop_status')">Открыть</button></p></div>`, stats: `<div class="glass section-card center"><div class="muted">📊 Аналитика профиля</div><p class="mt-12"><button class="cta" onclick="openBot('start=cb_profile_analytics')">Посмотреть</button></p></div>`, topup: `<div class="glass section-card center"><div class="muted">🧾 Пополнить бизнес-баланс</div><p class="mt-12"><button class="cta" onclick="openBot('start=cb_business_topup')">Пополнить</button></p></div>` }; c.innerHTML = views[type] || `<p class="muted">⏳ Пожалуйста, подождите…</p>`; document.getElementById('bottomSheet').style.bottom = '0'; } function closeSheet(){ document.getElementById('bottomSheet').style.bottom = '-100%'; } function requestAddToHome(){ const api = Telegram?.WebApp; if (!api?.addToHomeScreen || !api?.showPopup){ alert("❌ Эта функция не поддерживается."); return; } api.showPopup({ title:"Добавить на экран?", message:"Добавить King WebApp на главный экран?", buttons:[{id:"yes",type:"ok",text:"Да"},{id:"no",type:"close",text:"Нет"}] }, (id)=>{ if (id === "yes") api.addToHomeScreen(); else document.getElementById("homeStatus").textContent = "⛔ Вы отказались от добавления."; }); api.onEvent && api.onEvent('homeScreenAdded', ()=> document.getElementById("homeStatus").textContent = "✅ Успешно добавлено!"); } </script> <!-- Tabs + точное позиционирование капли --> <script> function positionPill(el){ const wrap = document.getElementById('navWrap'); const pill = document.getElementById('navPill'); const rectItem = el.getBoundingClientRect(); const gap = 6; const width = Math.max(0, rectItem.width - gap*2); const left = Math.max(0, el.offsetLeft + gap); pill.style.width = width + 'px'; pill.style.transform = `translateX(${left}px)`; } function setTab(el){ hapticClick(); const route = el.getAttribute('data-tab'); document.querySelectorAll('.tab-content').forEach(x=>x.classList.remove('active')); document.getElementById('tab-' + route)?.classList.add('active'); document.querySelectorAll('.nav-item').forEach(a=>a.classList.remove('active')); el.classList.add('active'); positionPill(el); if (route === 'top') loadTop(); if (route === 'nft') loadQueueCard(); } window.addEventListener('load', ()=>{ const active = document.querySelector('.nav-item.active') || document.querySelector('.nav-item[data-tab="profile"]'); if (active) setTab(active); }); window.addEventListener('resize', ()=>{ const active = document.querySelector('.nav-item.active'); if (active) positionPill(active); }); </script> <!-- ===== Расширенное меню Настроек (перехват openSheet('settings')) ===== --> <script> (function(){ const tg = window.Telegram?.WebApp; const haptic = ()=>{ try{ tg?.HapticFeedback?.impactOccurred?.("light"); }catch(e){} }; const _openSheet = window.openSheet; window.openSheet = function(title, type){ if (type !== 'settings'){ _openSheet?.(title, type); document.getElementById('bottomSheet').style.bottom = '0'; return; } document.getElementById('sheetTitle').textContent = title; const c = document.getElementById('sheetContent'); c.innerHTML = ` <div class="sheet-wrap"> <div class="sheet-tabs" role="tablist" aria-label="Разделы настроек"> <button class="sheet-tab-btn active" data-tab="mystats" aria-selected="true">Моя статистика</button> <button class="sheet-tab-btn" data-tab="bonuses" aria-selected="false">Бонусы</button> <button class="sheet-tab-btn" data-tab="contests" aria-selected="false">Конкурсы</button> </div> <div class="sheet-panels"> <div class="sheet-panel active" id="panel-mystats"> <div class="kpi-grid"> <div class="kpi"><small>Всего заработано</small><strong id="kpi-earned">—</strong></div> <div class="kpi"><small>Сдано номеров</small><strong id="kpi-count">—</strong></div> <div class="kpi"><small>Среднее/день</small><strong id="kpi-avg">—</strong></div> <div class="kpi"><small>Серия дней</small><strong id="kpi-streak">—</strong></div> </div> <div style="margin-top:12px; display:grid; gap:10px;"> <div class="item" style="grid-template-columns:1fr;"> <div class="meta"> <strong>Прогресс к цели</strong> <div class="progress-bar" aria-label="Прогресс к цели"><span id="statsGoal" style="width:0%"></span></div> </div> </div> <div><button class="btn" onclick="openBot('start=cb_profile_analytics')">Подробнее в боте</button></div> </div> </div> <div class="sheet-panel" id="panel-bonuses"> <div class="kpi-grid"> <div class="kpi"><small>Баллы</small><strong id="bonusPoints">—</strong></div> <div class="kpi"><small>Рефералы</small><strong id="bonusRefs">—</strong></div> <div class="kpi"><small>Бонус в $</small><strong id="bonusUsd">—</strong></div> <div class="kpi"><small>Статус</small><strong id="bonusTier">—</strong></div> </div> <div id="bonusList" class="list" style="margin-top:10px;"></div> </div> <div class="sheet-panel" id="panel-contests"> <div id="contestList" class="list"> <div class="empty">Загрузка конкурсов…</div> </div> </div> </div> </div>`; const tabs = c.querySelectorAll('.sheet-tab-btn'); tabs.forEach(btn=>{ btn.addEventListener('click',()=>{ haptic(); tabs.forEach(b=>{ b.classList.remove('active'); b.setAttribute('aria-selected','false'); }); btn.classList.add('active'); btn.setAttribute('aria-selected','true'); const id = btn.dataset.tab; c.querySelectorAll('.sheet-panel').forEach(p=>p.classList.remove('active')); c.querySelector('#panel-' + id)?.classList.add('active'); if (id==='mystats') loadMyStats(); if (id==='bonuses') loadBonuses(); if (id==='contests') loadContests(); }); }); loadMyStats(); document.getElementById('bottomSheet').style.bottom = '0'; }; function fmtUSD(n){ try{return new Intl.NumberFormat('en-US',{style:'currency',currency:'USD'}).format(Number(n||0));}catch(e){return `$${Number(n||0).toFixed(2)}`;} } function loadMyStats(){ fetch('get_profile_stats.php', { method:'POST' }) .then(r=>r.json()) .then(d=>{ document.getElementById('kpi-earned').textContent = fmtUSD(d?.earned_usd ?? 0); document.getElementById('kpi-count').textContent = d?.numbers_count ?? 0; document.getElementById('kpi-avg').textContent = fmtUSD(d?.avg_per_day ?? 0); document.getElementById('kpi-streak').textContent = d?.streak_days ?? 0; const goal = Math.max(0, Math.min(100, Number(d?.goal_progress_pct ?? 0))); document.getElementById('statsGoal').style.width = goal + '%'; }) .catch(()=>{ const panel = document.getElementById('panel-mystats'); panel.insertAdjacentHTML('beforeend','<div class="error">❌ Не удалось загрузить статистику</div>'); }); } function loadMyNumbers(){ const list = document.getElementById('numbersList'); fetch('get_num.php', { method:'POST' }) .then(r=>r.json()) .then(d=>{ const arr = Array.isArray(d?.items) ? d.items : []; if (!arr.length){ list.innerHTML = '<div class="empty">Пока нет номеров</div>'; return; } list.innerHTML = ''; arr.forEach(n=>{ const el = document.createElement('div'); el.className='item'; const meta = document.createElement('div'); meta.className='meta'; const t1 = document.createElement('div'); t1.innerHTML = `<strong>${n.mask || '+7•••'}</strong>`; const t2 = document.createElement('div'); t2.innerHTML = `<span class="badge">${n.status || 'неизв.'}</span> · <span class="muted">${n.date || ''}</span>`; meta.append(t1,t2); const btn = document.createElement('button'); btn.className='btn'; btn.textContent='Открыть'; btn.addEventListener('click',()=>{ haptic(); openBot('start=cb_drop_status'); }); el.append(meta, btn); list.appendChild(el); }); }) .catch(()=>{ list.innerHTML = '<div class="error">❌ Ошибка загрузки</div>'; }); } function loadBonuses(){ const list = document.getElementById('bonusList'); fetch('get_bonuses.php', { method:'POST' }) .then(r=>r.json()) .then(d=>{ document.getElementById('bonusPoints').textContent = d?.points ?? 0; document.getElementById('bonusRefs').textContent = d?.refs ?? 0; document.getElementById('bonusUsd').textContent = fmtUSD(d?.usd ?? 0); document.getElementById('bonusTier').textContent = d?.tier || '—'; const arr = Array.isArray(d?.list) ? d.list : []; if (!arr.length){ list.innerHTML = '<div class="empty">Пока бонусов нет</div>'; return; } list.innerHTML = ''; arr.forEach(b=>{ const it = document.createElement('div'); it.className='item'; const meta = document.createElement('div'); meta.className='meta'; const title = document.createElement('div'); title.innerHTML = `<strong>${b.title || 'Бонус'}</strong>`; const sub = document.createElement('div'); sub.innerHTML = `<span class="muted">${b.desc || ''}</span>`; meta.append(title, sub); const btn = document.createElement('button'); btn.className = b.claimed ? 'btn' : 'btn primary'; btn.textContent = b.claimed ? 'Получено' : 'Забрать'; btn.disabled = !!b.claimed; btn.addEventListener('click',()=>{ haptic(); fetch('claim_bonus.php',{method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ id:b.id })}) .then(r=>r.json()).then(res=>{ if (res?.ok){ btn.textContent='Получено'; btn.disabled=true; btn.className='btn'; } }); }); it.append(meta, btn); list.appendChild(it); }); }) .catch(()=>{ list.innerHTML = '<div class="error">❌ Не удалось загрузить бонусы</div>'; }); } function loadContests(){ const list = document.getElementById('contestList'); fetch('get_contests.php', { method:'POST' }) .then(r=>r.json()) .then(d=>{ const arr = Array.isArray(d?.contests) ? d.contests : []; if (!arr.length){ list.innerHTML = '<div class="empty">Активных конкурсов нет</div>'; return; } list.innerHTML = ''; arr.forEach(c=>{ const it = document.createElement('div'); it.className='item'; const meta = document.createElement('div'); meta.className='meta'; const title = document.createElement('div'); title.innerHTML = `<strong>${c.title || 'Конкурс'}</strong>`; const sub = document.createElement('div'); sub.innerHTML = `<span class="muted">до ${c.ends || '—'} · приз: ${c.prize || '—'}</span>`; const bar = document.createElement('div'); bar.className='progress-bar'; const span = document.createElement('span'); span.style.width = Math.max(0, Math.min(100, Number(c.progress_pct||0))) + '%'; bar.appendChild(span); meta.append(title, sub, bar); const btn = document.createElement('button'); btn.className='btn primary'; btn.textContent='Участвовать'; btn.addEventListener('click',()=>{ haptic(); openBot('start=cb_profile_analytics'); }); it.append(meta, btn); list.appendChild(it); }); }) .catch(()=>{ list.innerHTML = '<div class="error">❌ Ошибка загрузки конкурсов</div>'; }); } })(); </script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon='{"version":"2024.11.0","token":"5312e69668394053847c726ec76349e7","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script></body></html>