const MOCK=(()=>{const e=window.__WEBAPP_DEV_MOCK__,n=window.location.hostname,a=window.location.protocol==="file:"||n==="localhost"||n==="127.0.0.1"||n==="";return e&&a?e:null})();function readJsonScript(e){const n=document.getElementById(e);if(!n||!n.textContent)return null;try{return JSON.parse(n.textContent)}catch(a){return console.warn("Failed to parse JSON config from #"+e,a),null}}const CFG=readJsonScript("webapp-config")||MOCK&&MOCK.config||{},tg=window.Telegram&&window.Telegram.WebApp?window.Telegram.WebApp:null,TELEGRAM_LOGIN_WIDGET_URL="./telegram-widget.js",state={token:MOCK?"local-preview":localStorage.getItem("rw_webapp_token")||"",csrfToken:MOCK?"":readCookie("rw_webapp_csrf")||"",data:null,selectedPlan:null,referralParam:readReferralParam(),promoApplying:!1,payment:null,paymentFlowOpen:!1,promoModalOpen:!1,referralModalOpen:!1,accountMergeModalOpen:!1,accountMergeNotice:null,creatingPayment:!1,authInProgress:!1,authMode:CFG.emailAuthEnabled===!1?"telegram":"email",emailLoginPending:!1,emailLoginEmail:"",emailLoginCodeModalOpen:!1,emailLoginVerifying:!1,emailLoginResending:!1,emailLinkPending:!1,emailLinkEmail:"",promoStatusTimer:null,promoStatusType:"",promoStatusText:"",telegramLinkRendered:!1,telegramLinkInProgress:!1,toastTimer:null,userMenuOpen:!1,userMenuCloseTimer:null,langOverride:(function(){try{return localStorage.getItem("rw_webapp_lang")||""}catch(e){return""}})(),langMenuOpen:!1,langMenuCloseTimer:null},LANG_OPTIONS=[{code:"ru",label:"Русский",short:"RU",flag:"🇷🇺"},{code:"en",label:"English",short:"EN",flag:"🇬🇧"}],TW={iconBtn:"icon-btn",btnBase:"btn",btnIconOnly:"w-12 min-w-12 p-0",panelHead:"panel-head",flowCaption:"section-caption",sectionTitle:"section-title",metricLabel:"metric-label",metricValue:"metric-value",referralLinkRow:"referral-link-row",referralLinkValue:"referral-link-value",bonusRow:"bonus-row",empty:"empty-state",planCard:"plan-card",planCardActive:"plan-card-active",planName:"plan-name",planMeta:"plan-meta",planPrice:"plan-price",paymentMethodCard:"payment-method-card",paymentMethodCardPlatega:"payment-method-card--platega",paymentMethodCardPlategaSbp:"payment-method-card--platega payment-method-card--platega-sbp",paymentMethodCardPlategaCrypto:"payment-method-card--platega payment-method-card--platega-crypto",paymentMethodCardCryptopay:"payment-method-card--cryptopay",notice:"notice",stepNum:"step-num",stepName:"step-name"},FALLBACK_I18N={ru:{page_title:"Моя подписка",loading:"Загрузка...",refresh:"Обновить",logout:"Выйти",subscription:"Подписка",subscription_subtitle:"Ваша ссылка подключения и срок доступа",ends_at:"Окончание",traffic:"Трафик",connect:"Подключиться",copy_link:"Скопировать ссылку",extend_subscription:"Купить подписку / Добавить дни",payment_title:"Оплата подписки",payment_caption:"Выберите период и нажмите способ оплаты. Сервис оплаты откроется сразу.",close:"Закрыть",close_payment:"Закрыть оплату",payment_steps:"Шаги оплаты",step_plan:"Срок",step_method:"Метод",step_result:"Платеж",select_period:"Выберите период",select_method:"Выберите способ оплаты",payment_status:"Статус платежа",payment_amount_label:"Стоимость выбранного периода",choose_payment_method:"Способ оплаты",back:"Назад",create_payment:"Создать платеж",open_payment:"Открыть оплату",check_payment:"Проверить оплату",choose_other_method:"Выбрать другой способ",pay_with_platega_button:"Оплатить картой (СБП)",pay_with_platega_sbp_button:"Оплата через СБП",pay_with_platega_crypto_button:"Оплата криптой",pay_with_cryptopay_button:"Оплатить криптой",support:"Поддержка",account_title:"Аккаунт",account_caption:"Способы входа",email_label:"Email",telegram_label:"Telegram",linked:"Привязан",not_linked:"Не привязан",email_login_tab:"Email",telegram_login_tab:"Telegram",email_placeholder:"mail@example.com",code_placeholder:"000000",send_code:"Отправить код",resend_code:"Отправить еще раз",confirm:"Подтвердить",login:"Войти",login_title:"Войдите или зарегистрируйтесь",login_continue:"Продолжить",email_code_title:"Подтвердите вход",email_code_caption:"Введите 6-значный код из письма.",email_code_aria:"Код подтверждения",email_auth_disabled:"Вход по email пока не настроен.",email_required:"Введите email",email_invalid:"Введите корректный email",email_code_sending:"Отправляю код...",email_code_sent:"Код отправлен на почту",email_code_send_failed:"Не удалось отправить код",email_code_invalid:"Неверный код",email_code_expired:"Код устарел",email_rate_limited:"Повторная отправка доступна через {seconds} сек.",email_linked:"Email привязан",telegram_linked:"Telegram привязан",account_merge_toast:"Аккаунты объединены",account_merge_title:"Аккаунты объединены",account_merge_caption:"Оплаченные периоды сложились, и теперь у вас один аккаунт.",account_merge_body:"Мы объединили ваш Telegram и email в один профиль. Оплаченные периоды сложились, ссылка на подписку осталась прежней, а более поздний аккаунт был удалён автоматически.",account_merge_primary_account_label:"Оставлен аккаунт",account_merge_removed_account_label:"Удалён аккаунт",account_merge_end_date_label:"Новая дата окончания",account_merge_conflict:"Этот аккаунт уже связан с другими данными.",telegram_auth:"Telegram auth",telegram_auth_verifying:"Проверяю вход...",telegram_auth_failed:"Не удалось подтвердить Telegram-вход. Попробуйте еще раз.",telegram_auth_unavailable:"Telegram Login Widget недоступен. Проверьте username бота и доступ к telegram.org.",telegram_auth_access_denied:"Доступ запрещен.",active:"Активна",inactive:"Не активна",subscription_active:"Подписка активна",subscription_inactive:"Подписка не активна",sub_remaining_template:"Действует еще {value}",sub_ends_template:"Закончится {date}",sub_ended_template:"Закончилась {date}",sub_no_expiry:"Бессрочно",traffic_unlimited:"∞ бесконечный трафик",link_panel_title:"Привяжите способ входа",link_panel_caption:"Чтобы не потерять доступ к кабинету",link_email_title:"Привяжите email",link_email_caption:"Получайте код для входа на почту",link_telegram_title:"Привяжите Telegram",link_telegram_caption:"Входите одним нажатием через Telegram",guest_user:"Гость",no_active_subscription:"Нет активной подписки",not_available:"N/A",no_plans:"Тарифы не настроены.",access_period:"Срок доступа",choose_plan_first:"Сначала выберите срок подписки.",no_methods:"Нет доступных способов оплаты.",payment_not_created:"Платеж еще не создан.",invoice_sent:"Счет отправлен в чат с ботом. После оплаты вернитесь сюда и проверьте статус.",payment_created:"Платеж создан. Откройте оплату, завершите ее у провайдера и затем проверьте статус.",updating:"Обновляю данные",choose_plan_toast:"Выберите срок подписки",choose_method_toast:"Выберите способ оплаты",create_payment_toast:"Создайте платеж",payment_confirmed:"Оплата подтверждена",payment_pending:"Платеж пока не подтвержден",link_copied:"Ссылка скопирована",no_link:"Ссылка пока недоступна",payment_error:"Ошибка оплаты",privacy_policy:"Политика конфиденциальности",user_agreement:"Пользовательское соглашение",promo_title:"Промокод",promo_caption:"Введите код, чтобы начислить бонусные дни.",promo_placeholder:"PROMO2026",apply_promo:"Применить",promo_applied:"Промокод применен",promo_applied_ok:"Промокод применен, всё ок.",promo_empty:"Введите промокод",promo_invalid:"Промокод не найден или недействителен.",referral_title:"Пригласить друга",referral_caption:"Поделитесь ссылкой и получайте бонусы.",referral_code:"Ваш код",invited_friends:"Приглашено",purchased_friends:"Оплатили",copy_code:"Скопировать код",copy_webapp_link:"Скопировать ссылку Web App",copy_bot_link:"Скопировать ссылку бота",referral_copied:"Ссылка скопирована",code_copied:"Код скопирован",referral_site_label:"Пригласить через сайт",referral_telegram_label:"Пригласить через телеграм",referral_bonus_title:"Бонусы",referral_bonus_pair:"Вы: {inviter} дн. / друг: {friend} дн.",referral_no_bonuses:"Бонусы пока не настроены.",referral_bonus_explanation:"Бонусы начисляются один раз за каждого приглашенного пользователя, когда приглашенный пользователь покупает подписку."},en:{page_title:"My subscription",loading:"Loading...",refresh:"Refresh",logout:"Log out",subscription:"Subscription",subscription_subtitle:"Your connection link and access time",ends_at:"Ends at",traffic:"Traffic",connect:"Connect",copy_link:"Copy link",extend_subscription:"Renew subscription/Add days",payment_title:"Subscription payment",payment_caption:"Choose a period and tap a payment method. The payment service will open right away.",close:"Close",close_payment:"Close payment",payment_steps:"Payment steps",step_plan:"Period",step_method:"Method",step_result:"Payment",select_period:"Select period",select_method:"Select payment method",payment_status:"Payment status",payment_amount_label:"Selected period cost",choose_payment_method:"Payment method",back:"Back",create_payment:"Create payment",open_payment:"Open payment",check_payment:"Check payment",choose_other_method:"Choose another method",pay_with_platega_button:"Pay by card (SBP)",pay_with_platega_sbp_button:"Pay via SBP",pay_with_platega_crypto_button:"Pay with crypto",pay_with_cryptopay_button:"Pay with crypto",support:"Support",account_title:"Account",account_caption:"Sign-in methods",email_label:"Email",telegram_label:"Telegram",linked:"Linked",not_linked:"Not linked",email_login_tab:"Email",telegram_login_tab:"Telegram",email_placeholder:"mail@example.com",code_placeholder:"000000",send_code:"Send code",resend_code:"Send again",confirm:"Confirm",login:"Log in",login_title:"Log in or sign up",login_continue:"Continue",email_code_title:"Confirm login",email_code_caption:"Enter the 6-digit code from the email.",email_code_aria:"Verification code",email_auth_disabled:"Email sign-in is not configured yet.",email_required:"Enter your email",email_invalid:"Enter a valid email address",email_code_sending:"Sending code...",email_code_sent:"Code sent to email",email_code_send_failed:"Could not send code",email_code_invalid:"Invalid code",email_code_expired:"Code expired",email_rate_limited:"Try again in {seconds} sec.",email_linked:"Email linked",telegram_linked:"Telegram linked",account_merge_toast:"Accounts merged",account_merge_title:"Accounts merged",account_merge_caption:"Your paid periods were combined and you now have one account.",account_merge_body:"We merged your Telegram and email accounts into one profile. Your paid periods were combined, your subscription link stayed the same, and the later account was removed automatically.",account_merge_primary_account_label:"Kept account",account_merge_removed_account_label:"Removed account",account_merge_end_date_label:"New end date",account_merge_conflict:"This account is already linked to different data.",telegram_auth:"Telegram auth",telegram_auth_verifying:"Verifying login...",telegram_auth_failed:"Could not verify Telegram login. Try again.",telegram_auth_unavailable:"Telegram Login Widget is unavailable. Check the bot username and access to telegram.org.",telegram_auth_access_denied:"Access denied.",active:"Active",inactive:"Inactive",subscription_active:"Subscription is active",subscription_inactive:"Subscription is inactive",sub_remaining_template:"Valid for {value} more",sub_ends_template:"Expires {date}",sub_ended_template:"Expired {date}",sub_no_expiry:"No expiration",traffic_unlimited:"∞ unlimited traffic",link_panel_title:"Link a sign-in method",link_panel_caption:"So you never lose access",link_email_title:"Link email",link_email_caption:"Receive sign-in codes by email",link_telegram_title:"Link Telegram",link_telegram_caption:"Sign in with one tap via Telegram",guest_user:"Guest",no_active_subscription:"No active subscription",not_available:"N/A",no_plans:"Plans are not configured.",access_period:"Access period",choose_plan_first:"Choose a subscription period first.",no_methods:"No payment methods available.",payment_not_created:"Payment has not been created yet.",invoice_sent:"The invoice was sent to the bot chat. Pay it, then return here and check the status.",payment_created:"Payment was created. Open it, complete payment with the provider, then check the status.",updating:"Refreshing data",choose_plan_toast:"Choose a subscription period",choose_method_toast:"Choose a payment method",create_payment_toast:"Create a payment",payment_confirmed:"Payment confirmed",payment_pending:"Payment is not confirmed yet",link_copied:"Link copied",no_link:"Link is not available yet",payment_error:"Payment error",privacy_policy:"Privacy policy",user_agreement:"User agreement",promo_title:"Promo code",promo_caption:"Enter a code to add bonus days.",promo_placeholder:"PROMO2026",apply_promo:"Apply",promo_applied:"Promo code applied",promo_applied_ok:"Promo code applied, all good.",promo_empty:"Enter promo code",promo_invalid:"Promo code was not found or is not valid.",referral_title:"Invite friend",referral_caption:"Share your link and receive bonuses.",referral_code:"Your code",invited_friends:"Invited",purchased_friends:"Purchased",copy_code:"Copy code",copy_webapp_link:"Copy Web App link",copy_bot_link:"Copy bot link",referral_copied:"Link copied",code_copied:"Code copied",referral_site_label:"Invite via site",referral_telegram_label:"Invite via Telegram",referral_bonus_title:"Bonuses",referral_bonus_pair:"You: {inviter} d. / friend: {friend} d.",referral_no_bonuses:"Bonuses are not configured yet.",referral_bonus_explanation:"Bonuses are awarded once for each invited user when they purchase a subscription."}},I18N=(function(){const e=readJsonScript("i18n")||MOCK&&MOCK.i18n||{},n={};return new Set(Object.keys(FALLBACK_I18N).concat(Object.keys(e))).forEach(function(i){n[i]=Object.assign({},FALLBACK_I18N[i]||{},e[i]||{})}),n})(),accent=CFG.primaryColor||"#00fe7a";if(document.documentElement.style.setProperty("--accent",accent),setBrand(),applyI18n(),applyLegalLinks(),CFG.supportUrl){const e=document.getElementById("support-link");e.href=CFG.supportUrl,e.classList.remove("hidden")}if(tg)try{tg.ready(),tg.expand(),typeof tg.isVersionAtLeast=="function"&&tg.isVersionAtLeast("6.1")&&(tg.setHeaderColor("#05070a"),tg.setBackgroundColor("#05070a"))}catch(e){}bindEmailLoginInput(),bindEmailCodeInput(),bindPromoInput(),document.addEventListener("keydown",e=>{handleDocumentKeyForUserMenu(e),e.key==="Escape"&&(state.emailLoginCodeModalOpen?closeEmailLoginCodeModal():state.accountMergeModalOpen?closeAccountMergeModal():state.promoModalOpen?closePromoModal():state.referralModalOpen?closeReferralModal():state.paymentFlowOpen&&closePaymentFlow())}),document.addEventListener("click",handleDocumentActionClick),document.addEventListener("click",handleDocumentClickForUserMenu),document.addEventListener("click",handleDocumentClickForLangMenu),renderLangMenu(),boot();async function boot(){if(showLoader(),MOCK){await loadData();return}const e=readTelegramLoginWidgetAuthData();if(e){if(await finalizeTelegramAuth(e))return;clearToken(),startExternalAuth({resetStatus:!1});return}if(tg&&tg.initData)try{if(await finalizeTelegramAuth(tg.initData,"init_data"))return}catch(n){}if(state.token||readCookie("rw_webapp_csrf"))try{await loadData();return}catch(n){clearToken()}await startExternalAuth()}function readTelegramLoginWidgetAuthData(){const e=new URLSearchParams(window.location.search),n=["id","first_name","last_name","username","photo_url","auth_date","hash"],a={};let i=!1;return n.forEach(o=>{e.has(o)&&(a[o]=e.get(o)||"",i=!0)}),!i||!a.id||!a.auth_date||!a.hash?null:a}function readReferralParam(){const e=new URLSearchParams(window.location.search),n=e.get("ref")||e.get("start")||e.get("start_param")||"",a=tg&&tg.initDataUnsafe&&tg.initDataUnsafe.start_param?tg.initDataUnsafe.start_param:"",i=String(a||n||"").trim();return i?(localStorage.setItem("rw_webapp_referral",i),i):localStorage.getItem("rw_webapp_referral")||""}function clearTelegramLoginWidgetQuery(){const e=new URL(window.location.href);["id","first_name","last_name","username","photo_url","auth_date","hash"].forEach(a=>e.searchParams.delete(a)),window.history&&window.history.replaceState&&window.history.replaceState({},document.title,e.pathname+e.search+e.hash)}async function finalizeTelegramAuth(e,n="auth_data"){if(state.authInProgress)return!1;state.authInProgress=!0,setAuthStatus(t("telegram_auth_verifying"));try{const a=n==="init_data"?{init_data:e}:{auth_data:e};state.referralParam&&(a.referral_code=state.referralParam);const i=await fetch(CFG.apiBase+"/auth/token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}),o=await i.json();if(i.ok&&o.ok&&o.token){setToken(o.token,o.csrf_token),clearTelegramLoginWidgetQuery();try{return setAuthStatus(""),await loadData(),!0}catch(l){return clearToken(),setAuthStatus(t("telegram_auth_failed"),!0),!1}}const r=o.error==="banned"||o.error==="access_denied"?"telegram_auth_access_denied":"telegram_auth_failed";setAuthStatus(t(r),!0)}catch(a){setAuthStatus(t("telegram_auth_failed"),!0)}finally{state.authInProgress=!1}return clearTelegramLoginWidgetQuery(),!1}async function handleTelegramLoginWidgetAuth(e){if(!e){setAuthStatus(t("telegram_auth_failed"),!0);return}await finalizeTelegramAuth(e,"auth_data")}function setAuthMode(e){state.authMode=e==="telegram"?"telegram":"email",renderAuthMode()}function renderAuthMode(){const e=document.getElementById("email-auth-tab"),n=document.getElementById("telegram-auth-tab"),a=document.getElementById("email-login-pane"),i=document.getElementById("telegram-login-pane"),o=document.querySelector(".login-auth-body"),r=CFG.emailAuthEnabled!==!1;!r&&state.authMode==="email"&&(state.authMode="telegram"),e.classList.toggle("active",state.authMode==="email"),n.classList.toggle("active",state.authMode==="telegram"),a.classList.toggle("hidden",state.authMode!=="email"),i.classList.toggle("hidden",state.authMode!=="telegram"),o&&o.classList.toggle("login-auth-body--telegram",state.authMode==="telegram"),e.disabled=!r,state.authMode==="telegram"?renderTelegramLoginWidget():r||setAuthStatus(t("email_auth_disabled"),!0)}function renderTelegramLoginWidget(){const e=document.getElementById("telegram-login-widget");if(!e)return;e.innerHTML="";const n=String(CFG.telegramLoginBotUsername||"").trim();if(!n){setAuthStatus(t("telegram_auth_unavailable"),!0);return}typeof window.onTelegramAuth!="function"&&(window.onTelegramAuth=async function(i){await handleTelegramLoginWidgetAuth(i)});const a=document.createElement("script");a.async=!0,a.src=TELEGRAM_LOGIN_WIDGET_URL,a.setAttribute("data-telegram-login",n),a.setAttribute("data-size","large"),a.setAttribute("data-userpic","true"),a.setAttribute("data-request-access","write"),a.setAttribute("data-onauth","onTelegramAuth(user)"),a.onerror=()=>setAuthStatus(t("telegram_auth_unavailable"),!0),e.appendChild(a)}function bindEmailLoginInput(){const e=document.getElementById("email-login-input");e&&(e.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),requestEmailLoginCode())}),e.addEventListener("input",()=>{e.getAttribute("aria-invalid")==="true"&&(e.removeAttribute("aria-invalid"),setAuthStatus(""))}))}function bindEmailCodeInput(){const e=document.getElementById("email-login-code-input");e&&(e.addEventListener("input",()=>{e.value=sanitizeCode(e.value),updateEmailLoginCodeSlots()}),e.addEventListener("focus",updateEmailLoginCodeSlots),e.addEventListener("blur",updateEmailLoginCodeSlots),e.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),sanitizeCode(e.value).length===6&&!state.emailLoginVerifying&&verifyEmailLoginCode())}))}function sanitizeCode(e){return String(e||"").replace(/\D/g,"").slice(0,6)}function isValidEmail(e){const n=normalizeEmail(e);return!!(n&&n.length<=254&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(n))}function readValidEmailLoginInput(){const e=document.getElementById("email-login-input"),n=normalizeEmail(e&&e.value);return!n||!isValidEmail(n)?(e&&(e.setAttribute("aria-invalid","true"),e.focus()),setAuthStatus(t(n?"email_invalid":"email_required"),!0),""):(e&&(e.value=n,e.removeAttribute("aria-invalid")),n)}function openEmailLoginCodeModal(e,n,a=!1){state.emailLoginEmail=e,state.emailLoginCodeModalOpen=!0;const i=document.getElementById("email-login-code-input");i&&(i.value=""),renderEmailLoginCodeModal(),setEmailCodeStatus(n||t("email_code_sent"),a),window.setTimeout(()=>{const o=document.getElementById("email-login-code-input");state.emailLoginCodeModalOpen&&o&&o.focus()},80)}function closeEmailLoginCodeModal(){state.emailLoginCodeModalOpen=!1;const e=document.getElementById("email-login-code-input");e&&(e.value=""),setEmailCodeStatus(""),renderEmailLoginCodeModal()}function renderEmailLoginCodeModal(){const e=document.getElementById("email-code-modal");if(!e)return;if(!state.emailLoginCodeModalOpen){e.classList.remove("show"),syncModalLock(),window.setTimeout(()=>{state.emailLoginCodeModalOpen||e.classList.add("hidden")},180);return}const n=document.getElementById("email-code-address");n&&(n.textContent=state.emailLoginEmail||"..."),e.classList.remove("hidden"),syncModalLock(),applyI18n(e),updateEmailLoginCodeSlots(),window.requestAnimationFrame(()=>e.classList.add("show"))}function updateEmailLoginCodeSlots(){const e=document.getElementById("email-login-code-input"),n=sanitizeCode(e&&e.value);e&&e.value!==n&&(e.value=n);for(let o=0;o<6;o+=1){const r=document.getElementById("email-code-slot-"+o);if(!r)continue;const l=n[o]||"";r.textContent=l,r.classList.toggle("filled",!!l),r.classList.toggle("active",state.emailLoginCodeModalOpen&&document.activeElement===e&&o===Math.min(n.length,5))}const a=document.getElementById("email-login-verify-btn");a&&(a.disabled=n.length!==6||state.emailLoginVerifying||state.emailLoginPending);const i=document.getElementById("email-login-resend-btn");i&&(i.disabled=state.emailLoginPending||state.emailLoginResending)}async function requestEmailLoginCode(){if(state.emailLoginPending)return;if(CFG.emailAuthEnabled===!1){setAuthStatus(t("email_auth_disabled"),!0);return}const e=readValidEmailLoginInput();if(e){state.emailLoginPending=!0,setButtonBusy("email-login-send-btn",!0),openEmailLoginCodeModal(e,t("email_code_sending")),setAuthStatus("");try{const n=await publicApi("/auth/email/request",{email:e,language:getLanguage()});if(!n.ok)throw n;setEmailCodeStatus(t("email_code_sent"))}catch(n){const a=emailErrorMessage(n,"email_code_send_failed");if(n&&n.error==="invalid_email"){closeEmailLoginCodeModal();const i=document.getElementById("email-login-input");i&&i.setAttribute("aria-invalid","true"),setAuthStatus(a,!0)}else setEmailCodeStatus(a,!0)}finally{state.emailLoginPending=!1,setButtonBusy("email-login-send-btn",!1),updateEmailLoginCodeSlots()}}}async function resendEmailLoginCode(){if(state.emailLoginPending||state.emailLoginResending)return;const e=state.emailLoginEmail||normalizeEmail(document.getElementById("email-login-input").value);if(!e||!isValidEmail(e)){setEmailCodeStatus(t(e?"email_invalid":"email_required"),!0);return}state.emailLoginResending=!0,updateEmailLoginCodeSlots(),setEmailCodeStatus(t("email_code_sending"));try{const n=await publicApi("/auth/email/request",{email:e,language:getLanguage()});if(!n.ok)throw n;state.emailLoginEmail=e;const a=document.getElementById("email-login-code-input");a&&(a.value=""),setEmailCodeStatus(t("email_code_sent"))}catch(n){setEmailCodeStatus(emailErrorMessage(n,"email_code_send_failed"),!0)}finally{state.emailLoginResending=!1,updateEmailLoginCodeSlots()}}async function verifyEmailLoginCode(){const e=state.emailLoginEmail||normalizeEmail(document.getElementById("email-login-input").value),n=document.getElementById("email-login-code-input"),a=sanitizeCode(n&&n.value);if(!e||a.length!==6){setEmailCodeStatus(t("email_code_invalid"),!0),updateEmailLoginCodeSlots();return}state.emailLoginVerifying=!0,updateEmailLoginCodeSlots(),setEmailCodeStatus(t("telegram_auth_verifying"));try{const i=await publicApi("/auth/email/verify",{email:e,code:a,referral_code:state.referralParam||""});if(!i.ok||!i.token)throw i;setToken(i.token,i.csrf_token),closeEmailLoginCodeModal(),await loadData()}catch(i){clearToken(),setEmailCodeStatus(emailErrorMessage(i,"email_code_invalid"),!0)}finally{state.emailLoginVerifying=!1,updateEmailLoginCodeSlots()}}function startExternalAuth(e={}){const n=e.resetStatus!==!1;showLogin(),n&&setAuthStatus(""),renderAuthMode()}async function loadData(){const e=await api("/me");if(!e.ok)throw new Error(e.error||"load failed");state.data=e,setBrand(),applyI18n(),applyLegalLinks();const n=e.plans||[];state.selectedPlan=getDefaultPaymentPlan(n),state.payment=null,state.creatingPayment=!1,state.telegramLinkRendered=!1,render(),showApp()}function render(){renderSubscription(state.data.subscription),renderUserMenu(state.data.user||{}),renderAccount(state.data.user||{}),renderReferral(state.data.referral||{}),renderAccountMergeModal(),renderPaymentFlow()}function renderSubscription(e){const n=document.getElementById("sub-status"),a=document.getElementById("sub-status-text"),i=document.getElementById("remaining"),o=document.getElementById("end-date-caption");if(n.classList.toggle("active",!!e.active),a.textContent=e.active?t("subscription_active"):t("subscription_inactive"),e.active){const r=formatCompactRemaining(e.days_left,getLanguage())||e.remaining_text||"";i.textContent=r}else i.textContent=t("no_active_subscription");if(e.end_date_text){const r=e.active?"sub_ends_template":"sub_ended_template";o.textContent=t(r,{date:e.end_date_text}),o.classList.remove("hidden")}else e.active?(o.textContent=t("sub_no_expiry"),o.classList.remove("hidden")):(o.textContent="",o.classList.add("hidden"));renderTraffic(e),document.getElementById("connect-actions").classList.toggle("hidden",!e.connect_url&&!e.config_link)}function renderTraffic(e){const n=document.getElementById("traffic-bar"),a=document.getElementById("traffic-bar-fill"),i=document.getElementById("traffic");if(!n||!a||!i)return;const o=Number(e.traffic_limit_bytes),r=Number(e.traffic_used_bytes),l=Number.isFinite(o)&&o>0,s=Number.isFinite(r)&&r>=0,d=e.traffic_used||t("not_available"),c=e.traffic_limit||t("not_available");if(n.classList.remove("over","unlimited"),!l){n.classList.add("unlimited"),a.style.width="100%",i.textContent=t("traffic_unlimited"),n.setAttribute("aria-valuenow","0");return}const m=s?r/o:0,u=Math.max(0,Math.min(100,Math.round(m*100)));a.style.width=u+"%",i.textContent=d+" / "+c,n.setAttribute("aria-valuenow",String(u)),s&&r>=o&&n.classList.add("over")}function formatCompactRemaining(e,n){const a=Math.max(0,Math.floor(Number(e)||0));if(a<=0)return null;if(a>=365){const i=Math.round(a/365*2)/2;return formatDecimal(i,n)+" "+pluralizeUnit(i,"year",n)}if(a>=30){const i=Math.round(a/30*2)/2;return formatDecimal(i,n)+" "+pluralizeUnit(i,"month",n)}return formatDecimal(a,n)+" "+pluralizeUnit(a,"day",n)}function formatDecimal(e,n){if(Number.isInteger(e))return String(e);const a=e.toFixed(1);return n==="ru"?a.replace(".",","):a}function pluralizeUnit(e,n,a){const i={year:["year","years"],month:["month","months"],day:["day","days"]},o={year:["год","года","лет"],month:["месяц","месяца","месяцев"],day:["день","дня","дней"]};if(a==="en")return e===1?i[n][0]:i[n][1];const r=o[n];if(!Number.isInteger(e))return r[1];const l=Math.abs(e),s=l%10,d=l%100;return s===1&&d!==11?r[0]:s>=2&&s<=4&&(d<12||d>14)?r[1]:r[2]}function renderUserMenu(e){const n=!!(e.email&&e.email_verified),a=!!e.telegram_linked,i=getUserDisplayName(e),o=getUserSecondaryText(e,n,a),r=getUserAvatarSrc(e),l=buildIdenticon(getUserAvatarSeed(e,n)),s=document.getElementById("user-chip-name"),d=document.getElementById("user-chip-avatar"),c=document.getElementById("user-dropdown-avatar"),m=document.getElementById("user-dropdown-name"),u=document.getElementById("user-dropdown-sub"),p=document.getElementById("user-dropdown-email-status"),g=document.getElementById("user-dropdown-telegram-status");s.textContent=i,setAvatarWithFallback(d,r,l,i),setAvatarWithFallback(c,r,l,i),m.textContent=i,u.textContent=o,u.classList.toggle("hidden",!o),p.textContent=n?e.email:t("not_linked"),p.classList.toggle("linked",n),p.classList.toggle("unlinked",!n),g.textContent=a?e.telegram_id?String(e.telegram_id):t("linked"):t("not_linked"),g.classList.toggle("linked",a),g.classList.toggle("unlinked",!a)}function renderAccount(e){const n=!!(e.email&&e.email_verified),a=!!e.telegram_linked,i=!!(state.data.settings&&state.data.settings.email_auth_enabled),o=!n&&i,r=!a,l=document.getElementById("email-link-box"),s=document.getElementById("telegram-link-box"),d=document.getElementById("link-panel");l.classList.toggle("hidden",!o),s.classList.toggle("hidden",!r),d.classList.toggle("hidden",!o&&!r),a?state.telegramLinkRendered=!1:renderTelegramLinkWidget()}function getTelegramInitUser(){return!tg||!tg.initDataUnsafe||!tg.initDataUnsafe.user?null:tg.initDataUnsafe.user}function getUserAvatarSeed(e,n){const a=getTelegramInitUser();return n&&e&&e.email?e.email.trim().toLowerCase():String(e&&e.id||e&&e.telegram_id||a&&a.id||"guest")}function getUserAvatarSrc(e){const n=getTelegramInitUser();return n&&n.photo_url?n.photo_url:e&&e.telegram_photo_url?e.telegram_photo_url:""}function getUserDisplayName(e){const n=getTelegramInitUser();return n&&n.first_name?n.first_name:e&&e.first_name?e.first_name:e&&e.username?"@"+e.username:n&&n.username?"@"+n.username:e&&e.email?e.email:t("guest_user")}function getUserSecondaryText(e,n,a){return n&&e.email?e.email:a&&e.telegram_id?"#"+e.telegram_id:""}function setAvatarWithFallback(e,n,a,i){if(e){if(e.alt=i||"",!n){e.onerror=null,e.src=a;return}e.onerror=()=>{e.onerror=null,e.src=a},e.src=n}}function buildIdenticon(e){const n=String(e||"guest");let a=2166136261;for(let c=0;c>>0;const i=a%360,o="hsl("+i+", 60%, 18%)",r="hsl("+(i+180)%360+", 78%, 62%)";let l="",s=a;for(let c=0;c<5;c++)for(let m=0;m<3;m++){const u=s&1;s=s>>>1^(s&1?46080:0),u&&(l+='',m!==2&&(l+=''))}const d=''+l+"";return"data:image/svg+xml;utf8,"+encodeURIComponent(d)}function toggleUserMenu(e){const n=typeof e=="boolean"?e:!state.userMenuOpen;state.userMenuOpen=n;const a=document.getElementById("user-chip"),i=document.getElementById("user-dropdown");if(!(!a||!i)){if(state.userMenuCloseTimer&&(window.clearTimeout(state.userMenuCloseTimer),state.userMenuCloseTimer=null),a.setAttribute("aria-expanded",n?"true":"false"),n){i.classList.remove("hidden"),i.classList.remove("show"),window.requestAnimationFrame(()=>{state.userMenuOpen&&i.classList.add("show")});return}i.classList.remove("show"),state.userMenuCloseTimer=window.setTimeout(()=>{state.userMenuOpen||i.classList.add("hidden"),state.userMenuCloseTimer=null},180)}}function handleDocumentClickForUserMenu(e){if(!state.userMenuOpen)return;const n=document.querySelector(".user-menu");n&&n.contains(e.target)||toggleUserMenu(!1)}function handleDocumentKeyForUserMenu(e){e.key==="Escape"&&state.userMenuOpen&&toggleUserMenu(!1),e.key==="Escape"&&state.langMenuOpen&&toggleLangMenu(!1)}function renderLangMenu(){const e=getLanguage(),n=document.getElementById("lang-chip-label"),a=document.getElementById("lang-chip-flag"),i=LANG_OPTIONS.find(r=>r.code===e)||LANG_OPTIONS[0];n&&(n.textContent=i.short),a&&(a.textContent=i.flag);const o=document.getElementById("lang-dropdown");o&&(o.innerHTML=LANG_OPTIONS.map(r=>'").join(""),o.querySelectorAll("[data-lang]").forEach(r=>{r.addEventListener("click",()=>setLanguage(r.dataset.lang))}))}function toggleLangMenu(e){const n=typeof e=="boolean"?e:!state.langMenuOpen;state.langMenuOpen=n;const a=document.getElementById("lang-chip"),i=document.getElementById("lang-dropdown");if(!(!a||!i)){if(state.langMenuCloseTimer&&(window.clearTimeout(state.langMenuCloseTimer),state.langMenuCloseTimer=null),a.setAttribute("aria-expanded",n?"true":"false"),n){i.classList.remove("hidden"),i.classList.remove("show"),window.requestAnimationFrame(()=>{state.langMenuOpen&&i.classList.add("show")});return}i.classList.remove("show"),state.langMenuCloseTimer=window.setTimeout(()=>{state.langMenuOpen||i.classList.add("hidden"),state.langMenuCloseTimer=null},180)}}function handleDocumentClickForLangMenu(e){if(!state.langMenuOpen)return;const n=document.querySelector(".lang-menu");n&&n.contains(e.target)||toggleLangMenu(!1)}function handleDocumentActionClick(e){const n=e.target instanceof Element?e.target.closest("[data-action]"):null;if(!n||!document.contains(n)||n.disabled)return;const a=String(n.dataset.action||"");if(a){switch(a){case"toggle-user-menu":toggleUserMenu();break;case"toggle-lang-menu":toggleLangMenu();break;case"logout":logout();break;case"open-connect-link":openConnectLink();break;case"toggle-payment-flow":togglePaymentFlow();break;case"open-referral-modal":openReferralModal();break;case"open-promo-modal":openPromoModal();break;case"close-payment-flow":closePaymentFlow();break;case"close-promo-modal":closePromoModal();break;case"close-referral-modal":closeReferralModal();break;case"close-account-merge-modal":closeAccountMergeModal();break;case"close-email-login-code-modal":closeEmailLoginCodeModal();break;case"request-email-link-code":requestEmailLinkCode();break;case"verify-email-link-code":verifyEmailLinkCode();break;case"request-email-login-code":requestEmailLoginCode();break;case"verify-email-login-code":verifyEmailLoginCode();break;case"resend-email-login-code":resendEmailLoginCode();break;case"set-auth-mode":setAuthMode(n.dataset.mode||"email");break;case"apply-promo-code":applyPromoCode();break;case"select-plan":selectPlan(n.dataset.months||"");break;case"create-payment":createAndOpenPayment(n.dataset.method||"");break;case"copy-referral-link":copyReferralLink(n.dataset.kind||"webapp");break;case"copy-config-link":copyConfigLink();break;case"check-payment":checkPayment();break;default:return}e.preventDefault()}}function openPromoModal(){state.promoModalOpen=!0,clearPromoStatus(),renderPromoModal(),window.setTimeout(()=>{const e=document.getElementById("promo-code-input");e&&e.focus()},80)}function closePromoModal(){state.promoModalOpen=!1,clearPromoStatus(),renderPromoModal()}function renderPromoModal(){const e=document.getElementById("promo-modal");if(e){if(!state.promoModalOpen){e.classList.remove("show"),syncModalLock(),window.setTimeout(()=>{state.promoModalOpen||e.classList.add("hidden")},180);return}e.classList.remove("hidden"),syncModalLock(),renderPromoStatus(),applyI18n(e),window.requestAnimationFrame(()=>e.classList.add("show"))}}function bindPromoInput(){const e=document.getElementById("promo-code-input");e&&(e.addEventListener("input",()=>{e.getAttribute("aria-invalid")==="true"&&e.removeAttribute("aria-invalid"),state.promoStatusText&&clearPromoStatus()}),e.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),applyPromoCode())}))}function setPromoStatus(e,n="error"){state.promoStatusType=n==="success"?"success":"error",state.promoStatusText=normalizeStatusText(e||""),renderPromoStatus()}function clearPromoStatus(){state.promoStatusType="",state.promoStatusText="",renderPromoStatus()}function renderPromoStatus(){const e=document.getElementById("promo-status");if(e){if(!state.promoStatusText){e.textContent="",e.classList.add("hidden"),e.classList.remove("error","success");return}e.textContent=state.promoStatusText,e.classList.remove("hidden"),e.classList.toggle("error",state.promoStatusType==="error"),e.classList.toggle("success",state.promoStatusType==="success")}}function normalizeStatusText(e){const n=String(e||""),a=document.createElement("div");return a.innerHTML=n,(a.textContent||a.innerText||"").trim()}function openReferralModal(){state.referralModalOpen=!0,renderReferral(state.data&&state.data.referral||{})}function closeReferralModal(){state.referralModalOpen=!1,renderReferral(state.data&&state.data.referral||{})}function closeToolModals(){state.promoModalOpen=!1,state.referralModalOpen=!1,state.accountMergeModalOpen=!1,clearPromoStatus(),renderPromoModal(),renderReferral(state.data&&state.data.referral||{}),renderAccountMergeModal()}function openAccountMergeModal(e=null){e&&(state.accountMergeNotice=e),state.accountMergeModalOpen=!0,renderAccountMergeModal()}function closeAccountMergeModal(){state.accountMergeModalOpen=!1,renderAccountMergeModal()}function renderAccountMergeModal(){const e=document.getElementById("account-merge-modal"),n=document.getElementById("account-merge-panel");if(!e||!n)return;if(!state.accountMergeModalOpen){e.classList.remove("show"),syncModalLock(),window.setTimeout(()=>{state.accountMergeModalOpen||e.classList.add("hidden")},180);return}e.classList.remove("hidden"),syncModalLock();const a=state.accountMergeNotice||{},i=a.primary_user_id!=null?String(a.primary_user_id):t("not_available"),o=a.removed_user_id!=null?String(a.removed_user_id):t("not_available"),r=a.final_end_date_text||t("not_available");n.innerHTML=`
${escapeHtml(t("account_merge_title"))}
${escapeHtml(t("account_merge_caption"))}
${escapeHtml(t("account_merge_body"))}
${escapeHtml(t("account_merge_primary_account_label"))}
#${escapeHtml(i)}
${escapeHtml(t("account_merge_removed_account_label"))}
#${escapeHtml(o)}
${escapeHtml(t("account_merge_end_date_label"))}
${escapeHtml(r)}
`,applyI18n(e),window.requestAnimationFrame(()=>e.classList.add("show"))}function renderReferral(e){const n=document.getElementById("referral-modal"),a=document.getElementById("referral-panel");if(!n||!a)return;if(!state.referralModalOpen){n.classList.remove("show"),syncModalLock(),window.setTimeout(()=>{state.referralModalOpen||n.classList.add("hidden")},180);return}if(n.classList.remove("hidden"),syncModalLock(),!state.referralModalOpen)return;const i=(e.bonus_details||[]).map(o=>`
${escapeHtml(o.title||"")} ${escapeHtml(t("referral_bonus_pair",{inviter:o.inviter_days||0,friend:o.friend_days||0}))}
`).join("");a.innerHTML=`
${escapeHtml(t("referral_title"))}
${escapeHtml(t("referral_caption"))}
${escapeHtml(t("referral_bonus_explanation"))}
${i||'
'+escapeHtml(t("referral_no_bonuses"))+"
"}
`,applyI18n(n),window.requestAnimationFrame(()=>n.classList.add("show"))}function renderReferralLinkRow(e,n,a){return`
${escapeHtml(n)}
${escapeHtml(a||t("not_available"))}
`}async function applyPromoCode(){if(state.promoApplying)return;const e=document.getElementById("promo-code-input"),n=String(e&&e.value||"").trim();if(!n){setPromoStatus(t("promo_empty"),"error"),e&&e.setAttribute("aria-invalid","true"),e&&e.focus();return}state.promoApplying=!0,setButtonBusy("promo-apply-btn",!0),clearPromoStatus(),e&&e.removeAttribute("aria-invalid");try{const a=await api("/promo/apply",{method:"POST",body:JSON.stringify({code:n})});if(!a.ok)throw a;e&&(e.value=""),setPromoStatus(t("promo_applied_ok"),"success"),await loadData()}catch(a){const i=a&&a.error,o=a&&(a.message||a.detail);e&&e.setAttribute("aria-invalid","true"),setPromoStatus(i==="empty_code"?t("promo_empty"):o||t(i==="promo_apply_failed"?"promo_invalid":"payment_error"),"error")}finally{state.promoApplying=!1,setButtonBusy("promo-apply-btn",!1)}}async function copyReferralLink(e){const n=state.data&&state.data.referral,a=n&&(e==="bot"?n.bot_link:n.webapp_link);if(!a){showToast(t("no_link"));return}await copyText(a),showToast(t("referral_copied"))}async function copyReferralCode(){const e=state.data&&state.data.referral,n=e&&e.code;if(!n){showToast(t("no_link"));return}await copyText(n),showToast(t("code_copied"))}async function requestEmailLinkCode(){const e=document.getElementById("email-link-input"),n=normalizeEmail(e.value);if(!n){showToast(t("email_code_send_failed"));return}state.emailLinkPending=!0,setButtonBusy("email-link-send-btn",!0);try{const a=await api("/account/email/request",{method:"POST",body:JSON.stringify({email:n})});if(!a.ok)throw a;if(a.already_linked){showToast(t("email_linked")),await loadData();return}state.emailLinkEmail=n,document.getElementById("email-link-code-row").classList.remove("hidden"),showToast(t("email_code_sent"))}catch(a){showToast(emailErrorMessage(a,"email_code_send_failed"))}finally{state.emailLinkPending=!1,setButtonBusy("email-link-send-btn",!1)}}async function verifyEmailLinkCode(){const e=state.emailLinkEmail||normalizeEmail(document.getElementById("email-link-input").value),n=document.getElementById("email-link-code-input").value;setButtonBusy("email-link-verify-btn",!0);let a=null;try{const i=await api("/account/email/verify",{method:"POST",body:JSON.stringify({email:e,code:n})});if(!i.ok)throw i;i.token&&setToken(i.token,i.csrf_token),a=i.account_merge&&i.account_merge.merged?i.account_merge:null,state.accountMergeNotice=a,showToast(t(a?"account_merge_toast":"email_linked")),state.emailLinkEmail="";try{await loadData(),a&&openAccountMergeModal(a)}catch(o){console.warn("Email account linked, but data refresh failed",o),a&&openAccountMergeModal(a)}}catch(i){showToast(emailErrorMessage(i,"email_code_invalid"))}finally{setButtonBusy("email-link-verify-btn",!1)}}function renderTelegramLinkWidget(){const e=document.getElementById("telegram-link-widget");if(!e||state.telegramLinkRendered)return;e.innerHTML="";const n=String(CFG.telegramLoginBotUsername||"").trim();if(!n){setTelegramLinkStatus(t("telegram_auth_unavailable"),!0);return}window.onTelegramLinkAuth=async function(i){await linkTelegramAccount(i)};const a=document.createElement("script");a.async=!0,a.src=TELEGRAM_LOGIN_WIDGET_URL,a.setAttribute("data-telegram-login",n),a.setAttribute("data-size","large"),a.setAttribute("data-userpic","true"),a.setAttribute("data-request-access","write"),a.setAttribute("data-onauth","onTelegramLinkAuth(user)"),a.onerror=()=>setTelegramLinkStatus(t("telegram_auth_unavailable"),!0),e.appendChild(a),state.telegramLinkRendered=!0}async function linkTelegramAccount(e){if(!(!e||state.telegramLinkInProgress)){state.telegramLinkInProgress=!0,setTelegramLinkStatus(t("telegram_auth_verifying"));try{const n=await api("/account/telegram/link",{method:"POST",body:JSON.stringify({auth_data:e})});if(!n.ok)throw n;await finishTelegramLink(n,e.id)}catch(n){if(await refreshLinkedTelegramAfterError()){setTelegramLinkStatus("");try{showToast(t("telegram_linked"))}catch(a){console.warn("Telegram link success toast failed",a)}return}setTelegramLinkStatus(emailErrorMessage(n,"telegram_auth_failed"),!0)}finally{state.telegramLinkInProgress=!1}}}async function finishTelegramLink(e,n){e.token&&setToken(e.token,e.csrf_token),markTelegramLinked(e.telegram_id||n),setTelegramLinkStatus(""),state.telegramLinkRendered=!1;const a=e.account_merge&&e.account_merge.merged?e.account_merge:null;state.accountMergeNotice=a;try{showToast(t(a?"account_merge_toast":"telegram_linked"))}catch(i){console.warn("Telegram link success toast failed",i)}try{await loadData(),a&&openAccountMergeModal(a)}catch(i){console.warn("Telegram account linked, but data refresh failed",i),a&&openAccountMergeModal(a)}}function markTelegramLinked(e){!state.data||!state.data.user||(state.data.user.telegram_linked=!0,e&&(state.data.user.telegram_id=Number(e)),renderAccount(state.data.user))}async function refreshLinkedTelegramAfterError(){try{return await loadData(),!!(state.data&&state.data.user&&state.data.user.telegram_linked)}catch(e){return console.warn("Telegram link status refresh failed",e),!1}}function togglePaymentFlow(){if(state.paymentFlowOpen){closePaymentFlow();return}state.paymentFlowOpen=!0,state.creatingPayment=!1,state.payment=null,state.selectedPlan=getDefaultPaymentPlan(state.data&&state.data.plans||[]),renderPaymentFlow()}function closePaymentFlow(){state.paymentFlowOpen=!1,state.creatingPayment=!1,state.payment=null,renderPaymentFlow()}function renderPaymentFlow(){const e=document.getElementById("payment-modal");if(e){if(!state.paymentFlowOpen){e.classList.remove("show"),syncModalLock(),window.setTimeout(()=>{state.paymentFlowOpen||e.classList.add("hidden")},180);return}e.classList.remove("hidden"),syncModalLock(),window.requestAnimationFrame(()=>e.classList.add("show")),renderPlans(state.data&&state.data.plans||[]),renderPaymentSummary(),renderMethods(),applyI18n(e)}}function syncModalLock(){document.body.classList.toggle("modal-open",!!(state.paymentFlowOpen||state.emailLoginCodeModalOpen||state.promoModalOpen||state.referralModalOpen||state.accountMergeModalOpen))}function getDefaultPaymentPlan(e=[]){return e.length&&(e.find(n=>Number(n.months)===3)||e[0])||null}function renderPlans(e){const n=document.getElementById("plans");if(n){if(!e.length){n.innerHTML='
'+escapeHtml(t("no_plans"))+"
";return}(!state.selectedPlan||!e.some(a=>Number(a.months)===Number(state.selectedPlan.months)))&&(state.selectedPlan=getDefaultPaymentPlan(e)),n.innerHTML=e.map(a=>{const i=Number(a.months),o=state.selectedPlan&&Number(state.selectedPlan.months)===i;return` `}).join("")}}function renderPaymentSummary(){const e=document.getElementById("selected-plan-price");if(e){if(!state.selectedPlan){e.textContent=t("no_plans");return}e.textContent=formatMoney(state.selectedPlan.price,state.selectedPlan.currency)}}function renderMethods(){const e=document.getElementById("payment-methods");if(!e)return;if(!state.selectedPlan){e.innerHTML='
'+escapeHtml(t("choose_plan_first"))+"
";return}const n=getAvailableMethods();if(!n.length){e.innerHTML='
'+escapeHtml(t("no_methods"))+"
";return}e.innerHTML=n.map(a=>{let i,o;return a.id==="platega_sbp"?(i="pay_with_platega_sbp_button",o=TW.paymentMethodCardPlategaSbp):a.id==="platega_crypto"?(i="pay_with_platega_crypto_button",o=TW.paymentMethodCardPlategaCrypto):a.id==="platega"?(i="pay_with_platega_button",o=TW.paymentMethodCardPlatega):(i="pay_with_cryptopay_button",o=TW.paymentMethodCardCryptopay),` `}).join("")}function selectPlan(e){state.creatingPayment||(state.selectedPlan=(state.data&&state.data.plans||[]).find(n=>Number(n.months)===Number(e))||null,state.payment=null,renderPaymentFlow())}async function createAndOpenPayment(e){if(state.creatingPayment)return;if(!state.selectedPlan){showToast(t("choose_plan_toast"));return}if(!getAvailableMethods().some(a=>a.id===e)){showToast(t("no_methods"));return}state.creatingPayment=!0,state.payment=null,renderPaymentFlow();try{const a=await api("/payments",{method:"POST",body:JSON.stringify({months:state.selectedPlan.months,method:e})});if(!a.ok||!a.payment_url)throw new Error(a.message||t("payment_error"));state.payment=a,openPaymentUrl(a.payment_url)&&closePaymentFlow()}catch(a){showToast(a.message||t("payment_error"))}finally{state.creatingPayment=!1,state.paymentFlowOpen&&renderPaymentFlow()}}function getAvailableMethods(){if(!state.data||!state.selectedPlan)return[];const e=new Map((state.data.payment_methods||[]).map(n=>[String(n.id||"").toLowerCase(),n]));return["platega_sbp","platega_crypto","platega","cryptopay"].map(n=>e.get(n)).filter(Boolean)}function openPaymentUrl(e){const n=String(e||state.payment&&state.payment.payment_url||"").trim();return n?tg&&tg.openLink?(tg.openLink(n),!0):(window.open(n,"_blank","noopener")||window.location.assign(n),!0):!1}async function checkPayment(){if(!state.payment||!state.payment.payment_id)return;(await api("/payments/"+state.payment.payment_id)).paid?(showToast(t("payment_confirmed")),state.paymentFlowOpen=!1,await loadData()):showToast(t("payment_pending"))}function openConnectLink(){const e=state.data&&state.data.subscription,n=e&&(e.connect_url||e.config_link);if(!n){showToast(t("no_link"));return}tg&&tg.openLink?tg.openLink(n):window.open(n,"_blank","noopener")}async function copyConfigLink(){const e=state.data&&state.data.subscription,n=e&&e.config_link;if(!n){showToast(t("no_link"));return}await copyText(n),showToast(t("link_copied"))}async function copyText(e){try{await navigator.clipboard.writeText(e)}catch(n){const a=document.createElement("textarea");a.value=e,document.body.appendChild(a),a.select(),document.execCommand("copy"),a.remove()}}async function api(e,n={}){if(MOCK)return mockApi(e,n);const a=String(n.method||"GET").toUpperCase(),i=Object.assign({},n.headers||{});state.token&&(i.Authorization="Bearer "+state.token);const o=state.csrfToken||readCookie("rw_webapp_csrf")||"";o&&["POST","PUT","PATCH","DELETE"].includes(a)&&(i["X-CSRF-Token"]=o),n.body&&!i["Content-Type"]&&(i["Content-Type"]="application/json");const r=await fetch(CFG.apiBase+e,Object.assign({},n,{headers:i}));if(r.status===401)throw clearToken(),await startExternalAuth(),new Error("Unauthorized");return r.json()}async function publicApi(e,n={}){return MOCK?mockApi(e,{method:"POST",body:JSON.stringify(n)}):(await fetch(CFG.apiBase+e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)})).json()}async function mockApi(e,n={}){return await new Promise(a=>window.setTimeout(a,120)),e==="/me"?JSON.parse(JSON.stringify(MOCK.data)):e==="/auth/email/request"||e==="/account/email/request"?{ok:!0}:e==="/auth/email/verify"?{ok:!0,token:"local-preview",csrf_token:"local-preview-csrf"}:e==="/account/email/verify"?(MOCK.data.user.email="preview@example.com",MOCK.data.user.email_verified=!0,{ok:!0,token:"local-preview",csrf_token:"local-preview-csrf"}):e==="/account/telegram/link"?(MOCK.data.user.telegram_linked=!0,MOCK.data.user.telegram_id=100200300,{ok:!0,token:"local-preview",csrf_token:"local-preview-csrf"}):e==="/auth/logout"?{ok:!0}:e==="/promo/apply"?{ok:!0,end_date_text:"20.05.2026 12:00"}:e==="/payments"&&String(n.method||"").toUpperCase()==="POST"?{ok:!0,action:"open_link",payment_url:"https://example.com/payment-preview",payment_id:10001}:e.startsWith("/payments/")?{ok:!0,payment_id:10001,status:"pending",paid:!1}:{ok:!1,error:"not_found"}}function setToken(e,n=""){state.token=e,state.csrfToken=n||readCookie("rw_webapp_csrf")||state.csrfToken||""}function clearToken(){state.token="",state.csrfToken="",localStorage.removeItem("rw_webapp_token")}function readCookie(e){const n=e+"=",a=document.cookie.split("; ").find(i=>i.startsWith(n));return a?decodeURIComponent(a.slice(n.length)):""}function normalizeEmail(e){return String(e||"").trim().toLowerCase()}function emailErrorMessage(e,n){const a=e&&e.error;return a==="rate_limited"?t("email_rate_limited",{seconds:e.retry_after||60}):t(a==="invalid_email"?"email_invalid":a==="expired_code"?"email_code_expired":a==="invalid_code"||a==="too_many_attempts"?"email_code_invalid":a==="email_auth_not_configured"?"email_auth_disabled":a==="account_merge_conflict"?"account_merge_conflict":a==="invalid_auth"?"telegram_auth_failed":n)}function setButtonBusy(e,n){const a=document.getElementById(e);a&&(a.disabled=!!n)}function logout(){toggleUserMenu(!1),publicApi("/auth/logout",{}).catch(()=>{}),clearToken(),closePaymentFlow(),closeEmailLoginCodeModal(),startExternalAuth()}function showLoader(){document.getElementById("loader").classList.remove("hidden"),document.getElementById("app").classList.add("hidden"),document.getElementById("login").classList.remove("show")}function showApp(){document.getElementById("loader").classList.add("hidden"),document.getElementById("login").classList.remove("show"),document.getElementById("login").classList.add("hidden"),document.getElementById("app").classList.remove("hidden")}function showLogin(){document.getElementById("loader").classList.add("hidden"),document.getElementById("app").classList.add("hidden"),document.getElementById("login").classList.remove("hidden"),document.getElementById("login").classList.add("show")}function setAuthStatus(e,n=!1){const a=document.getElementById("auth-status");if(a){if(!e){a.textContent="",a.classList.add("hidden"),a.classList.remove("error");return}a.textContent=e,a.classList.remove("hidden"),a.classList.toggle("error",!!n)}}function setEmailCodeStatus(e,n=!1){const a=document.getElementById("email-code-status");if(a){if(!e){a.textContent="",a.classList.add("hidden"),a.classList.remove("error");return}a.textContent=e,a.classList.remove("hidden"),a.classList.toggle("error",!!n)}}function setTelegramLinkStatus(e,n=!1){const a=document.getElementById("telegram-link-status");if(a){if(!e){a.textContent="",a.classList.add("hidden"),a.classList.remove("error");return}a.textContent=e,a.classList.remove("hidden"),a.classList.toggle("error",!!n)}}function showToast(e){const n=document.getElementById("toast");if(n){if(n.textContent=e,n.classList.remove("hidden"),n.offsetWidth,n.classList.add("show"),tg&&tg.HapticFeedback)try{tg.HapticFeedback.notificationOccurred("success")}catch(a){console.warn("Haptic feedback failed",a)}state.toastTimer&&window.clearTimeout(state.toastTimer),state.toastTimer=window.setTimeout(()=>{n.classList.remove("show"),window.setTimeout(()=>{n.classList.contains("show")||n.classList.add("hidden")},250)},2200)}}function setFavicon(e){let n=document.getElementById("app-favicon");n||(n=document.createElement("link"),n.id="app-favicon",n.rel="icon",n.setAttribute("sizes","any"),document.head.appendChild(n)),n.href=e||"data:,"}function setBrandLogo(e,n){if(!e)return;const a=e.querySelector("[data-brand-logo]"),i=e.querySelector("[data-brand-logo-spinner]");if(!a)return;if(a.onload=null,a.onerror=null,a.removeAttribute("data-brand-logo-url"),!n){a.removeAttribute("src"),a.classList.add("hidden"),i&&i.classList.add("hidden"),e.classList.add("hidden");return}const o=n;e.classList.remove("hidden"),i&&i.classList.remove("hidden"),a.classList.add("hidden"),a.dataset.brandLogoUrl=o,a.onload=()=>{a.dataset.brandLogoUrl===o&&(a.classList.remove("hidden"),i&&i.classList.add("hidden"))},a.onerror=()=>{a.dataset.brandLogoUrl===o&&(a.removeAttribute("src"),a.classList.add("hidden"),i&&i.classList.add("hidden"),e.classList.add("hidden"))},a.src=n,a.complete&&a.naturalWidth>0&&(a.classList.remove("hidden"),i&&i.classList.add("hidden"))}function setBrand(){const e=CFG.title||document.title||t("page_title"),n=CFG.logoUrl||"";document.title=e,setFavicon(n),document.querySelectorAll("[data-brand-title]").forEach(a=>{a.textContent=e}),document.querySelectorAll("[data-brand-logo-shell]").forEach(a=>{setBrandLogo(a,n)})}function applyI18n(e=document){document.documentElement.lang=getLanguage(),e.querySelectorAll("[data-i18n]").forEach(n=>{n.textContent=t(n.dataset.i18n)}),e.querySelectorAll("[data-title-i18n]").forEach(n=>{const a=t(n.dataset.titleI18n);n.setAttribute("title",a),n.setAttribute("aria-label",a)}),e.querySelectorAll("[data-aria-i18n]").forEach(n=>{n.setAttribute("aria-label",t(n.dataset.ariaI18n))}),e.querySelectorAll("[data-placeholder-i18n]").forEach(n=>{n.setAttribute("placeholder",t(n.dataset.placeholderI18n))})}function applyLegalLinks(e=document){const n={privacyPolicyUrl:CFG.privacyPolicyUrl||"",userAgreementUrl:CFG.userAgreementUrl||""};e.querySelectorAll("[data-legal-key]").forEach(a=>{const i=a.dataset.legalKey,o=n[i]||"";a.href=o||"#",a.classList.toggle("hidden",!o),a.setAttribute("aria-hidden",o?"false":"true")}),e.querySelectorAll("[data-legal-links]").forEach(a=>{const i=Array.from(a.querySelectorAll("[data-legal-key]")).some(o=>!o.classList.contains("hidden"));a.classList.toggle("hidden",!i)})}function getLanguage(){const e=[];state.langOverride&&e.push(state.langOverride),state.data&&state.data.user&&state.data.user.language_code&&e.push(state.data.user.language_code);const n=tg&&tg.initDataUnsafe&&tg.initDataUnsafe.user;n&&n.language_code&&e.push(n.language_code),typeof navigator!="undefined"&&(Array.isArray(navigator.languages)&&navigator.languages.forEach(a=>a&&e.push(a)),navigator.language&&e.push(navigator.language)),CFG.language&&e.push(CFG.language),document.documentElement.lang&&e.push(document.documentElement.lang);for(const a of e){const i=String(a).toLowerCase().split("-")[0];if(I18N&&I18N[i])return i}return"ru"}function setLanguage(e){const n=String(e||"").toLowerCase().split("-")[0];if(!(I18N&&Object.keys(I18N).length&&!I18N[n])){state.langOverride=n;try{localStorage.setItem("rw_webapp_lang",n)}catch(a){}if(applyI18n(),state.data)try{render()}catch(a){}renderLangMenu(),toggleLangMenu(!1)}}function t(e,n={}){const a=I18N&&I18N[getLanguage()]||I18N&&I18N.ru||{},i=I18N&&I18N.ru&&I18N.ru[e]||e;return(a[e]||i).replace(/\{(\w+)\}/g,(r,l)=>Object.prototype.hasOwnProperty.call(n,l)?String(n[l]):"")}function formatMoney(e,n){const a=Number(e||0);return(Number.isInteger(a)?String(a):a.toFixed(2))+" "+(n||CFG.currency||"RUB")}function escapeHtml(e){return String(e==null?"":e).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function escapeAttr(e){return escapeHtml(e).replaceAll("`","`")}