☰

BongaCams Unchained

Clean interface, PiP, fullscreen, recording, screenshots, bookmarks and more.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         BongaCams Unchained
// @name:ru       BongaCams Unchained
// @name:uk       BongaCams Unchained
// @name:es       BongaCams Unchained
// @name:de       BongaCams Unchained
// @name:fr       BongaCams Unchained
// @name:pt       BongaCams Unchained
// @name:it       BongaCams Unchained
// @name:pl       BongaCams Unchained
// @name:tr       BongaCams Unchained
// @name:nl       BongaCams Unchained
// @name:cs       BongaCams Unchained
// @name:ro       BongaCams Unchained
// @name:hu       BongaCams Unchained
// @name:bg       BongaCams Unchained
// @name:el       BongaCams Unchained
// @name:ja       BongaCams Unchained
// @name:zh-CN    BongaCams Unchained
// @name:ko       BongaCams Unchained
// @name:he       BongaCams Unchained
// @name:ar       BongaCams Unchained
// @name:hi       BongaCams Unchained
// @name:id       BongaCams Unchained
// @name:vi       BongaCams Unchained
// @name:th       BongaCams Unchained
// @namespace    DiadiaBonga
// @version      3.9.4
// @description:ru Чистый интерфейс, PiP, полный экран, запись, скриншоты, закладки и многое другое.
// @description Clean interface, PiP, fullscreen, recording, screenshots, bookmarks and more.
// @description:uk Чистий інтерфейс, PiP, повний екран, запис, скріншоти, закладки та багато іншого.
// @description:es Interfaz limpia, PiP, pantalla completa, grabación, capturas, favoritos y mucho más.
// @description:de Saubere Oberfläche, PiP, Vollbild, Aufnahme, Screenshots, Favoriten und vieles mehr.
// @description:fr Interface épurée, PiP, plein écran, enregistrement, captures d'écran, favoris et bien plus.
// @description:pt Interface limpa, PiP, tela cheia, gravação, capturas de tela, favoritos e muito mais.
// @description:it Interfaccia pulita, PiP, schermo intero, registrazione, screenshot, preferiti e molto altro.
// @description:pl Czysty interfejs, PiP, pełny ekran, nagrywanie, zrzuty ekranu, zakładki i wiele więcej.
// @description:tr Temiz arayüz, PiP, tam ekran, kayıt, ekran görüntüsü, yer imleri ve daha fazlası.
// @description:nl Schone interface, PiP, volledig scherm, opnemen, screenshots, favorieten en meer.
// @description:cs Čisté rozhraní, PiP, celá obrazovka, nahrávání, snímky obrazovky, záložky a mnoho dalšího.
// @description:ro Interfață curată, PiP, ecran complet, înregistrare, capturi de ecran, favorite și multe altele.
// @description:hu Tiszta felület, PiP, teljes képernyő, felvétel, képernyőképek, kedvencek és még sok más.
// @description:bg Чист интерфейс, PiP, цял екран, запис, скриншоти, любими и още много.
// @description:el Καθαρή διεπαφή, PiP, πλήρης οθόνη, εγγραφή, στιγμιότυπα, αγαπημένα και πολλά άλλα.
// @description:ja クリーンなインターフェース、PiP、全画面、録画、スクリーンショット、ブックマークなど。
// @description:zh-CN 简洁界面、PiP、全屏、录制、截图、收藏等多种功能。
// @description:ko 깔끔한 인터페이스, PiP, 전체 화면, 녹화, 스크린샷, 즐겨찾기 등.
// @description:he ממשק נקי, PiP, מסך מלא, הקלטה, צילומי מסך, מועדפים ועוד.
// @description:ar واجهة نظيفة، PiP، ملء الشاشة، تسجيل، لقطات شاشة، مفضلة والمزيد.
// @description:hi साफ़ इंटरफ़ेस, PiP, फुलस्क्रीन, रिकॉर्डिंग, स्क्रीनशॉट, पसंदीदा और बहुत कुछ।
// @description:id Antarmuka bersih, PiP, layar penuh, perekaman, tangkapan layar, favorit, dan lainnya.
// @description:vi Giao diện gọn gàng, PiP, toàn màn hình, ghi hình, chụp màn hình, yêu thích và nhiều hơn nữa.
// @description:th อินเทอร์เฟซสะอาด, PiP, เต็มจอ, อัดวิดีโอ, แคปหน้าจอ, รายการโปรด และอื่นๆ
// @author       DiaDiaBogDan
// @license      MIT
// @match        *://*.bongacams.com/*
// @match        *://*.bongacams2.com/*
// @match        *://*.bongocams.com/*
// @match        *://*.webcamsluts.ru/*
// @match        *://*.stripchat.com/*
// @match        *://stripchat.com/*
// @match        *://*.chaturbate.com/*
// @match        *://chaturbate.com/*
// @icon         https://i.bgicdn.com/favicon/bc/favicon.svg?20240227
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addValueChangeListener
// @grant        unsafeWindow
// @connect      bongacams.com
// @connect      bongacams2.com
// @connect      bongocams.com
// @connect      webcamsluts.ru
// @connect      stripchat.com
// @connect      chaturbate.com
// @connect      mmcdn.com
// @connect      doppiocdn.com
// @connect      doppiocdn.media
// @connect      doppiocdn.net
// @connect      doppiocdn.org
// @connect      bgicdn.com
// @connect      bestcam.tv
// @connect      camshowrecordings.com
// @connect      camshowrecord.net
// @connect      livecamsrip.com
// @connect      camdownload.net
// @connect      camshow.cc
// @connect      cdncontent.top
// @connect      pornotorrent.top
// @connect      pornolab.net
// @connect      simpcity.cr
// @connect      camsclips.com
// @noframes
// @run-at       document-start
// ==/UserScript==

(function () {
'use strict';

const realHidden = () => {
    try { return Object.getOwnPropertyDescriptor(Document.prototype, 'hidden').get.call(document); } catch { return document.hidden; }
};
const BG_SUBS = { visibilitychange: [], pagehide: [] };
const onPageEvent = (type, fn, target = document) => {
    target.addEventListener(type, fn, true);
    BG_SUBS[type].push(fn);
};

let streamUrl = null, streamPath = '';
window.addEventListener('bc_hls', e => { streamUrl = e.detail; streamPath = location.pathname; });
const getStreamUrl = () => (streamUrl && streamPath === location.pathname) ? streamUrl : null;

const blockLimits = () => {
    const s = document.createElement('script');
    s.textContent = `try{const bcHost=/bongacams|bongocams|webcamsluts/.test(location.hostname);if(bcHost){if('serviceWorker' in navigator)navigator.serviceWorker.register=()=>new Promise(()=>{});window.redirectOnLimit=()=>{}}const emit=u=>{try{u=String(u);if(u.includes('.m3u8')&&!u.includes('chunk'))window.dispatchEvent(new CustomEvent('bc_hls',{detail:new URL(u,location.href).href}))}catch{}};const o=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(m,u){emit(u);return o.apply(this,arguments)};const f=window.fetch;if(f)window.fetch=function(i){try{emit(i&&i.url?i.url:i)}catch{}return f.apply(this,arguments)};if(bcHost){const s=Storage.prototype.setItem,r=/guestTime|ls\\.tft|limit|freeTime|timeLimit/i;Storage.prototype.setItem=function(k,v){if(!r.test(k))s.apply(this,arguments)};const c=Object.getOwnPropertyDescriptor(Document.prototype,'cookie')||Object.getOwnPropertyDescriptor(HTMLDocument.prototype,'cookie');if(c?.set){const re=/^\\s*(limit\\w*|guest[_-]?time\\w*|free[_-]?time\\w*|time[_-]?limit\\w*)\\s*=/i;Object.defineProperty(document,'cookie',{get:()=>c.get.call(document),set:v=>{if(!re.test(v.trim()))c.set.call(document,v)},configurable:true})}}}catch{}`;
    (document.head || document.documentElement).appendChild(s);
    s.remove();
};
blockLimits();

const installMediaHook = () => {
    const s = document.createElement('script');
    s.textContent = `(()=>{try{if(window.__bcMH)return;window.__bcMH=1;
var refs=[],ctxs=[],dead=false;
var reg=function(e){if(e&&refs.length<300)refs.push(new WeakRef(e));return e};
var P=HTMLMediaElement.prototype,op=P.play;
P.play=function(){reg(this);if(dead){try{this.pause()}catch(x){}return Promise.resolve()}return op.apply(this,arguments)};
var kk=false;
['src','srcObject'].forEach(function(n){var d=Object.getOwnPropertyDescriptor(P,n);if(d&&d.set){var st=d.set;Object.defineProperty(P,n,{configurable:true,enumerable:d.enumerable,get:d.get,set:function(v){if(dead&&!kk)return;return st.call(this,v)}})}});
var sa=Element.prototype.setAttribute;
Element.prototype.setAttribute=function(n){if(dead&&this instanceof HTMLMediaElement&&String(n).toLowerCase()==='src')return;return sa.apply(this,arguments)};
var ce=Document.prototype.createElement;
Document.prototype.createElement=function(t){var e=ce.apply(this,arguments);if(/^(video|audio)$/i.test(String(t)))reg(e);return e};
var OA=window.Audio;if(OA){var NA=function(){var e=arguments.length?new OA(arguments[0]):new OA();reg(e);return e};NA.prototype=OA.prototype;window.Audio=NA}
var A=window.AudioContext||window.webkitAudioContext;
if(A){var R=A.prototype.resume;A.prototype.resume=function(){if(ctxs.indexOf(this)<0)ctxs.push(this);if(dead)return Promise.resolve();return R.apply(this,arguments)};
['createMediaElementSource','createMediaStreamSource','createBufferSource'].forEach(function(n){var f=A.prototype[n];if(f)A.prototype[n]=function(){if(ctxs.indexOf(this)<0)ctxs.push(this);return f.apply(this,arguments)}})}
var kill=function(){dead=true;kk=true;refs.forEach(function(r){var e=r.deref();if(!e)return;try{e.pause();var m=e.srcObject;if(m&&m.getTracks)m.getTracks().forEach(function(t){t.stop()});e.srcObject=null;e.removeAttribute('src');e.load();e.remove()}catch(x){}});ctxs.forEach(function(c){try{c.suspend()}catch(x){}});kk=false};
window.addEventListener('bc_sleep_kill',kill)
}catch(e){}})();`;
    (document.head || document.documentElement).appendChild(s);
    s.remove();
};
installMediaHook();

function parseCount(v) {
    const t = String(v == null ? '' : v).replace(/[\s\u00a0]/g, '').toLowerCase();
    const m = t.match(/(\d+(?:[.,]\d+)?)(k|к|тыс|m|м|млн)?/);
    if (!m) return NaN;
    let n = parseFloat(m[1].replace(',', '.'));
    const suf = m[2];
    if (suf) n *= /^(m|м|млн)$/.test(suf) ? 1e6 : 1e3;
    else if (/^\d{1,3}([.,]\d{3})+$/.test(m[1])) n = parseInt(m[1].replace(/\D/g, ''), 10);
    return Math.round(n);
}
const Store = {
    get: (k, def) => {
        try {
            const v = GM_getValue(k);
            if (v == null) return def;
            const p = JSON.parse(v);
            return (Array.isArray(def) && !Array.isArray(p)) || p === null ? def : p;
        } catch { return def; }
    },
    set: (k, v) => { try { GM_setValue(k, JSON.stringify(v)); return true; } catch { return false; } }
};

const clamp = (v, min, max) => Math.max(min, Math.min(v, max));
const isObj = o => !!o && typeof o === 'object';
const axisK = (grow, shrink, size, d) => (grow ? (size + d) / size : shrink ? (size - d) / size : null);
const isPlaying = v => !!v && !v.paused && !v.ended && v.readyState > 2;
const escHTML = s => String(s).replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
const safeDecode = s => { try { return decodeURIComponent(s); } catch { return s; } };

const MINI_SHIFT_X = 168, MINI_SHIFT_Y = 5;
const BM_HOST = /(^|\.)(bongacams2?\.com|bongocams\.com|webcamsluts\.ru|stripchat\.com|chaturbate\.com)$/;
const isSafeUrl = u => { try { const x = new URL(u); return x.protocol === 'https:' && BM_HOST.test(x.hostname); } catch { return false; } };
const BC_RE = /bongacams|bongocams|webcamsluts/;
const siteKey = h => BC_RE.test(h) ? 'bc' : /stripchat/.test(h) ? 'sc' : /chaturbate/.test(h) ? 'cb' : h;
const urlSite = u => { try { return siteKey(new URL(u).hostname); } catch { return ''; } };
const SITE = siteKey(location.hostname), IS_BC = SITE === 'bc';
const toHttps = u => {
    u = typeof u === 'string' ? u : '';
    if (u.startsWith('//')) u = `https:${u}`;
    return u.startsWith('https://') ? u : '';
};
const isStr = v => typeof v === 'string';
const clip = (v, n) => isStr(v) ? v.slice(0, n) : '';
const validBm = b => !!b && isStr(b.name) && isStr(b.url) && !!b.name.trim() && isSafeUrl(b.url);
const cleanBm = b => {
    if (!validBm(b)) return null;
    const out = {
        name: clip(b.name, 100),
        url: normUrl(b.url),
        avatar: toHttps(b.avatar),
        note: clip(b.note, 500),
        g: clip(isStr(b.g) && b.g.trim(), 40),
        seen: Number.isFinite(b.seen) && b.seen > 0 ? b.seen : 0
    };
    return Object.assign(out, cleanBmExtras(b));
};
const cleanBmExtras = b => {
    const x = {};
    if (b.pin === true) x.pin = true;
    if (Array.isArray(b.ptags)) {
        const keep = [];
        b.ptags.forEach((t, i) => { const c = clip(t, 40); if (c && keep.length < 30) keep.push([c, b.ptic?.[i]]); });
        x.ptags = keep.map(p => p[0]);
        if (keep.some(p => p[1])) x.ptic = keep.map(p => (isStr(p[1]) && /^[a-z0-9_\/-]{1,60}$/i.test(p[1]) ? p[1] : ''));
    }
    if (Array.isArray(b.sch) && b.sch.length === 7) x.sch = b.sch.map(s => clip(s, 60));
    return x;
};
const HASHTAG_RE = /#[\p{L}\p{M}\p{N}_]+/giu;
const noteHashTags = b => b.note?.match(HASHTAG_RE) || [];
const bmTagMatch = (b, tag) => !tag || (tag[0] === '#' ? noteHashTags(b).some(t => t.toLowerCase() === tag) : (b.ptags || []).some(t => t.toLowerCase() === tag));
const countInto = (m, x) => { const k = x.toLowerCase(); m.set(k, (m.get(k) || 0) + 1); };
const bmTbtn = (html, active, onClick, title = '') => {
    const btn = mk('button', `bm-tbtn${active ? ' on' : ''}`);
    btn.innerHTML = html;
    btn.title = title;
    btn.onclick = onClick;
    return btn;
};
const RESORT_SORTS = new Set(['online', 'last', 'viewers']);
const stripBm = ({ _updateItemDOM, _topicExp, _lastImg, _chk, _isUpdating, _avFix, _avK, _live, _mob, _pf, _sv, label, ...rest }) => rest;

const BC_CONTAINERS = ['#stream-container', '#ResizablePane', '#EmbedSWFHolder', '.player-container', '.performer-video-container', '.chat-video-container', '.video-panel', '#video-panel-wrap'];

const HIDE_DECL = 'display:none!important;opacity:0!important;pointer-events:none!important;height:0!important;margin:0!important;padding:0!important';

const HIDE_CATS = [
    { id: 'hdr_m', plat: 'm', def: true, sel: ['.bc-header', '.bc-header-main', '.h_container', '#mainbar_container', '.join_button_container', '.js-chat_join_button', '[data-role="header"]'] },
    { id: 'hdr_d', plat: 'd', def: false, sel: ['.js-page_header', '.js-header_bar'] },
    { id: 'tabs', plat: 'm', def: true, sel: ['.live_tabs', '#mls_filter_result_container', '.bc_alternate_header_live_tabs'] },
    { id: 'seotitle', plat: 'b', def: true, sel: ['.mls_title'] },
    { id: 'chat_tips', plat: 'b', def: false, sel: ['.history .system_msg.tip_success', '.system_msg.tip_success'] },
    { id: 'chat_topic', plat: 'b', def: false, sel: ['.history .system_msg:has(.bc_notice.__topic)', '.bc_notice.__topic'] },
    { id: 'chat_boost', plat: 'b', def: false, sel: ['.history [class*="boost"]', '.history [class*="Boost"]'] },
    { id: 'ftr', plat: 'b', def: true, sel: ['.bc-footer', '#footer_container', '.bcm_footer', '.bcm_socials', '.m_socials', 'footer.footer', '.footer_copy', '.footer_seo', '.footer_mobile_guide', '#jsx-ls_seo_custom_text', '#jsx-ls_footer_container'] },
    { id: 'promo', plat: 'b', def: true, sel: ['.get_app_banner', '.js-get_app_banner', '.gab_wrp', '.banner_wrp', '.js-index_banner', '.sb_topmodel', '.free_tokens_panel', '#top_banner_above_chat', '.banner_top_chat', '.hb_item.__promo', '.js-free_tokens', '.hb_contest_item', '.holiday_discount_alert', '.js-top_banner', 'a[rel="buy_tokens"].holiday_discount_alert', '.stream_join_btn', '.join_button_container', '.bc_popalert.__give_away', '.bc_popalert.__member_bonus', '.stream_social_links', '.fancybox-overlay', '.fp_outer', '.fp_outer_overlay', '[class*="promo-banner"]', '[class*="age-gate"]', '[class*="age_gate"]', '[class*="cookie-banner"]', '[class*="notification-bar"]'] },
    { id: 'lastview', plat: 'b', def: false, sel: ['.lst_bage.__last_viewed'] },
    { id: 'joinpop', plat: 'b', def: false, sel: ['#member_join_popup', '.member_join_popup', '.fp_outer', '.fp_outer_overlay', '.fp_inner_wrap', '*:has(> .fp_inner_wrap)'] },
    { id: 'tips', plat: 'b', def: true, sel: ['#firstChatTooltipContainer', '.chat_bar_alert_container', '.chat_alert_container', '#chat_prompt_container', '#alerts_above_chat', '.js-bottom_alerts_area', '#bFontSizeTipHolder'] },
    { id: 'modelchat', plat: 'b', def: true, sel: ['[data-bc-mpop]'] },
    { id: 'games', plat: 'm', def: true, sel: ['#games_button'] },
    { id: 'popups', plat: 'm', def: false, sel: ['#popupChatSelection', '#popupGroup', '#popupVoyeur', '#gamecontrol_popup_container', '.ui-popup-container', '.cam2cam_modal'] },
    { id: 'actions', plat: 'b', def: false, sel: ['#chat_actions_bar', '.bcm_chat_footer', '#private_btn_cell', '.cf_cell.__private', 'a.cf_item.__tip', 'button.cf_item.__tip_menu', '.private_btn_wrp', '#bPaidButtonTopRow', '#bPaidButtonGroup', '.paid_button_group', '#bGotoGroup', '#bGotoPrivate', '#bGotoVoyeur', '#bTip'] },
    { id: 'balance', plat: 'd', def: false, sel: ['.memberBalance', '.memberNavigation'] },
    { id: 'chathdr', plat: 'b', def: false, sel: ['#id-chat-header', '.bc_chat_header'] },
    { id: 'tipking', plat: 'b', def: false, sel: ['.tip_king_wrp', '.bc_new_tip_modal'] },
    { id: 'below', plat: 'd', def: false, sel: ['.stream-controls'] },
    { id: 'wm', plat: 'd', def: false, sel: ['#layover-logo', '.layover-logo'] },
    { id: 'age18', plat: 'b', def: true, sel: ['#popup_18_plus', '#popup_18_plus-screen', '#popup_18_plus-popup'] }
];
HIDE_CATS.forEach(c => { c.site = 'bc'; });
const SC_CATS = [
    { id: 'sc_hdr', def: true, sel: ['.header-top-wrapper'] },
    { id: 'sc_sub', def: false, sel: ['.view-cam-header-sub'] },
    { id: 'sc_promo', def: true, sel: ['[class*="SidebarBanners"]', '.tokens-giveaway-banner', '.tokens-giveaway-banner-container', '.player-join-button', '.player-controls-user__join-btn'] },
    { id: 'sc_cookie', def: true, sel: ['[class*="CookieReminder"]', '.cookies-banner', '[data-testid="CookiesReminder"]'] },
    { id: 'sc_footer', def: true, sel: ['#MAIN_FOOTER_ID', '[class*="footer-container"]', '[class*="Footer__inner"]'] },
    { id: 'sc_widgets', def: true, sel: ['.plugin-panel', '.viewcam-widget-panel'] },
    { id: 'sc_goal', def: false, sel: ['.view-cam-info-goal', '.epic-goal-progress__wrap'] },
    { id: 'sc_topic', def: false, sel: ['.view-cam-info-topic'] },
    { id: 'sc_king', def: false, sel: ['[data-testid="king-wrapper-is-king"]', '[data-testid="view-cam-info-king-content"]'] },
    { id: 'sc_wm', def: false, sel: ['[class*="Watermark"]', '.watermark'] },
    { id: 'sc_about', def: false, sel: ['[data-testid="viewcam-model-sections"]'] }
];
const CB_CATS = [
    { id: 'cb_hdr', def: false, sel: ['.MobileHeader', '#header-links'] },
    { id: 'cb_alerts', def: true, sel: ['.LanguageMismatchAlert', '.dismissible_notice', '.MobileDismissibleMessages', '#ie-support-notice'] },
    { id: 'cb_footer', def: true, sel: ['#footer', '#mobile-social-media-icons'] },
    { id: 'cb_sort', def: false, sel: ['.MobileSort', '#mobile-sort-container', '#mobile-sort-form-container'] },
    { id: 'cb_tags', def: false, sel: ['.TopTagsBanner'] },
    { id: 'cb_tips', def: false, sel: ['.roomNotice.isTip'] },
    { id: 'cb_status', def: false, sel: ['.roomStatusNotifier'] },
    { id: 'cb_actions', def: false, sel: ['.sendTipButton', '.tipForm'] },
    { id: 'cb_info', def: false, sel: ['.HeaderRoomInfo'] }
];
SC_CATS.forEach(c => HIDE_CATS.push({ ...c, site: 'sc', plat: 'b' }));
CB_CATS.forEach(c => HIDE_CATS.push({ ...c, site: 'cb', plat: 'b' }));

const HIDE_TEXT = {
    hdr_m:   ['Верх сайта',              'Логотип, меню, кнопки входа',                 'Site top bar',          'Logo, menu, login buttons'],
    hdr_d:   ['Шапка сайта (ПК)',        'Верхняя панель на компьютере',                'Site header (PC)',      'Top bar on desktop'],
    seotitle:['Заголовок-реклама',       'Строка «Безкоштовний секс в онлайн порно-чаті» над списком', 'Ad headline', 'The "Free sex in online porn chat" line above the list'],
    chat_tips:['Чаевые в чате',          'Сообщения «подарил токены», «Меню чаевых», тип-меню', 'Tips in chat', '\"Tipped N tokens\" and tip-menu messages'],
    chat_topic:['Тема комнаты',          'Длинное описание «Тема: …» в начале чата',     'Room topic',            'Long \"Topic: …\" block at the top of chat'],
    chat_boost:['Бусты в чате',          'Плашки «поднял модель на N секунд» (FAN BOOSTED)', 'Boosts in chat',   '\"Boosted the model\" cards'],
    tabs:    ['Вкладки и сортировка',    'Девушки/пары, фильтры, значок сортировки',    'Tabs & sorting',        'Category tabs, filters, sort icon'],
    ftr:     ['Низ страницы',            'Подвал, соцсети, SEO-текст',                  'Page bottom',           'Footer, socials, SEO text'],
    promo:   ['Реклама и баннеры',       'Баннеры, промо, плашка «Присоединяйся» на плеере, приложение',          'Ads & banners',         'Banners, promos, "Join me" strip on the player, get-the-app'],
    lastview:['Плашка «Продолжить просмотр»', 'Кнопка на превью последней модели',     '"Continue watching" badge', 'Button on the last viewed thumbnail'],
    joinpop: ['Окно регистрации',        'Всплывающая форма «Создайте аккаунт»',        'Sign-up popup',         '"Create an account" popup'],
    tips:    ['Подсказки в чате',        'Всплывающие подсказки и уведомления',         'Chat hints',            'Tooltips and alerts'],
    modelchat:['Всплывающий чат модели', 'Розовое окошко «Привет! Любишь виртуальный секс?» внизу', 'Model popup chat', 'Pink pop-up with the model\'s auto-greeting at the bottom'],
    games:   ['Кнопка «Игры»',           'Иконка геймпада в красной панели',            '"Games" button',        'Gamepad icon in the red bar'],
    popups:  ['Всплывающие окна',        'Выбор чата, группа, подглядывание',           'Popups',                'Chat choice, group, voyeur'],
    actions: ['Кнопки «Приват / Чаевые»','Синие (на ПК зелёные) кнопки под красной панелью',            '"Private / Tips" buttons','Blue (green on PC) buttons under the red bar'],
    balance: ['Баланс и меню (ПК)',      'Баланс и навигация на компьютере',            'Balance & menu (PC)',   'Balance and navigation on desktop'],
    chathdr: ['Плашка «Чат с …»',        'Строка «Бесплатный чат с …» и король чаевых', 'Title bar "Chat with …"','"Free chat with …" strip and tip king'],
    tipking: ['Король чаевых',           'Строка короля и окна чаевых',                 'Tip king',              'Tip king strip and tip popups'],
    below:   ['Панель под плеером (ПК)', 'Блок кнопок под видео',                       'Under-player bar (PC)', 'Button row under the video'],
    wm:      ['Водяной знак (ПК)',       'Логотип поверх видео',                        'Watermark (PC)',        'Logo over the video'],
    age18:   ['Окно «Старше 18»',        'Заставка «Заходи ТОЛЬКО если ты уже старше 18»', '18+ notice',          'The "18+ only" entry screen']
};
Object.assign(HIDE_TEXT, {
    sc_hdr:    ['Верх сайта',            'Шапка с логотипом, поиском и кнопками входа',   'Site top bar',     'Header with logo, search and login buttons'],
    sc_sub:    ['Строка модели',         'Аватар, подписка и меню над плеером',           'Model bar',        'Avatar, follow and menu row above the player'],
    sc_promo:  ['Реклама и баннеры',     'Розыгрыши токенов, кнопка «Присоединиться» на плеере', 'Ads & banners', 'Token giveaways, Join button on the player'],
    sc_cookie: ['Плашка cookies',        'Уведомление о cookie внизу',                    'Cookie notice',    'Cookie reminder at the bottom'],
    sc_footer: ['Низ страницы',          'Подвал и юридический текст',                    'Page bottom',      'Footer and legal text'],
    sc_widgets:['Виджеты на плеере',     'Опросы и реакции поверх видео',                 'Player widgets',   'Polls and reactions over the video'],
    sc_goal:   ['Цель (гол)',            'Полоса прогресса цели',                         'Goal bar',         'Goal progress bar'],
    sc_topic:  ['Тема комнаты',          'Текст темы над и внутри плеера',                'Room topic',       'Topic text over and inside the player'],
    sc_king:   ['Король чаевых',         'Плашка короля чаевых',                          'Tip king',         'Tip king strip'],
    sc_wm:     ['Водяной знак',          'Логотип поверх видео',                          'Watermark',        'Logo over the video'],
    sc_about:  ['Блоки под плеером',     'Обо мне, расписание, похожие модели',           'Below the player', 'About, schedule, similar models'],
    cb_hdr:    ['Верх сайта',            'Шапка с логотипом и меню',                      'Site top bar',     'Header with logo and menu'],
    cb_alerts: ['Уведомления',           'Предупреждение о языке и закрываемые заметки',   'Alerts',           'Language alert and dismissible notes'],
    cb_footer: ['Низ страницы',          'Подвал и соцсети',                              'Page bottom',      'Footer and socials'],
    cb_sort:   ['Сортировка',            'Панель сортировки в мобильной версии',          'Sorting',          'Mobile sorting panel'],
    cb_tags:   ['Полоса тегов',          'Популярные теги над списком',                   'Tag strip',        'Top tags above the list'],
    cb_tips:   ['Чаевые в чате',         'Сообщения о токенах и чаевых',                  'Tips in chat',     'Tip and token messages'],
    cb_status: ['Статус комнаты',        'Плашка про оффлайн и приват с подсказками',     'Room status',      'Offline and private notifier'],
    cb_actions:['Кнопка чаевых',         'Кнопка и форма отправки токенов',               'Tip button',       'Send-tip button and form'],
    cb_info:   ['Название комнаты',      'Имя и счётчик зрителей в шапке',                'Room info',        'Name and viewers in the header']
});
HIDE_CATS.forEach(c => { const t = HIDE_TEXT[c.id]; if (t) { c.ru = t[0]; c.dru = t[1]; c.en = t[2]; c.den = t[3]; } });

const HIDE_PRESETS = {
    min: ['promo', 'joinpop', 'tips', 'modelchat', 'popups', 'seotitle', 'sc_promo', 'sc_cookie', 'sc_widgets', 'cb_alerts'],
    clean: HIDE_CATS.filter(c => c.site === 'bc' ? !/^chat_/.test(c.id) : c.def).map(c => c.id)
};

const catOn = (c, cfg) => cfg[c.id] === undefined ? c.def : !!cfg[c.id];
const detectPlatform = () => document.body?.classList.contains('ui-mobile-viewport') ? 'm' : 'd';
const customAll = () => { const o = Store.get('bc_hide_custom', {}); return (o && typeof o === 'object' && !Array.isArray(o)) ? o : {}; };
const getCustom = () => { const a = customAll()[siteKey(location.hostname)]; return Array.isArray(a) ? a.filter(x => typeof x === 'string') : []; };
const setCustom = list => { const o = customAll(); o[siteKey(location.hostname)] = list; Store.set('bc_hide_custom', o); };
const addCustom = sel => { const l = getCustom(); if (!l.includes(sel)) { l.push(sel); setCustom(l); } };
const removeCustom = sel => setCustom(getCustom().filter(x => x !== sel));

const buildHideCSS = skipId => {
    const out = [];
    {
        const cfg = Store.get('bc_hide_cfg', {});
        const hdr = HIDE_CATS.find(x => x.id === 'hdr_m');
        if (IS_BC && hdr && !catOn(hdr, cfg)) out.push('.bc-header,.bc_header.bc-header-main,.bc-header__fixed,.bc-header.hidden,.bc-header__fixed.hidden{display:flex!important;visibility:visible!important;opacity:1!important;transform:none!important;pointer-events:auto!important;position:fixed!important;top:0!important;z-index:1000!important}.bc-header.hidden:before,.bc-header.hidden .ui-title,.bc-header.hidden .lbtn,.bc-header.hidden .rbtn,.bc-header.hidden .ui-title.logo{transform:none!important}');
        const scope = { m: 'body.ui-mobile-viewport ', d: 'body:not(.ui-mobile-viewport) ' };
        HIDE_CATS.forEach(c => {
            if (c.site !== SITE || c.id === skipId || !catOn(c, cfg)) return;
            const pre = c.site === 'bc' ? (scope[c.plat] || '') : '';
            out.push(`${c.sel.map(x => pre + x).join(',')}{${HIDE_DECL}}`);
        });
    }
    getCustom().forEach(x => out.push(`${x}{${HIDE_DECL}}`));
    return out.join('\n');
};
const applyHideCSS = skipId => {
    let el = document.getElementById('bc-unchained-hide-css');
    if (!el) {
        el = document.createElement('style');
        el.id = 'bc-unchained-hide-css';
        (document.head || document.documentElement).appendChild(el);
    }
    el.textContent = buildHideCSS(typeof skipId === 'string' ? skipId : undefined);
};
const ensureHideCSS = () => { if (!document.getElementById('bc-unchained-hide-css')) applyHideCSS(); };

const cssEsc = x => (window.CSS && CSS.escape) ? CSS.escape(x) : String(x).replace(/[^\w-]/g, '\\$&');
const stableCls = c => c.length < 40 && !/^(ui-|__|bcu-|bc-(?:theater|thtr|unlock))/.test(c) && !/\d{3,}/.test(c) && !/^(active|open|opened|hidden|visible|selected|current|hover|focus|loaded|loading|playing|disabled|on|off|hd)$/i.test(c);
const selUniq = x => { try { return document.querySelectorAll(x).length === 1; } catch { return false; } };
const pathSelector = el => {
    const parts = [];
    for (let cur = el; cur && cur.nodeType === 1 && cur !== document.documentElement; cur = cur.parentElement) {
        if (cur.id && selUniq(`#${cssEsc(cur.id)}`)) { parts.unshift(`#${cssEsc(cur.id)}`); break; }
        const par = cur.parentElement;
        const idx = par ? [...par.children].indexOf(cur) + 1 : 1;
        parts.unshift(`${cur.tagName.toLowerCase()}:nth-child(${idx})`);
        if (cur === document.body) break;
    }
    return parts.join(' > ');
};
const isPickable = n => n?.nodeType === 1 && n !== document.body && n !== document.documentElement;
const idSelector = c => {
    if (!c.id || /\d{3,}/.test(c.id)) return '';
    const s = `#${cssEsc(c.id)}`;
    return selUniq(s) ? s : '';
};
const classSelector = c => c.tagName.toLowerCase() + [...c.classList].filter(stableCls).slice(0, 2).map(x => `.${cssEsc(x)}`).join('');
const buildSelector = el => {
    const parts = [];
    let cur = el;
    for (let i = 0; i < 6 && isPickable(cur); i++, cur = cur.parentElement) {
        const id = idSelector(cur);
        if (id) {
            parts.unshift(id);
            const full = parts.join(' > ');
            return selUniq(full) ? full : pathSelector(el);
        }
        parts.unshift(classSelector(cur));
        const sel = parts.join(' > ');
        if (selUniq(sel)) return sel;
    }
    return pathSelector(el);
};

const BC_CSS = `a.htlp_icon_wrp.bg-head{display:none!important}#header_login{display:block!important;opacity:1!important;pointer-events:auto!important;visibility:visible!important}#header_login .join_btn,#header_login .jbt_inner{opacity:1!important;pointer-events:auto!important;visibility:visible!important}.performer-frame,.blurred-performer-frame{pointer-events:none!important}#video-panel-wrap,#stream-container,[class*="video-container"],[class*="player-wrap"]{pointer-events:auto!important;touch-action:manipulation}.chat_panel_wrap{height:100%!important;flex:1}body:not(.page_index):not(.__page_main),body:not(.page_index):not(.__page_main) .ui-page,body:not(.page_index):not(.__page_main) .js-page,body:not(.page_index):not(.__page_main) .bc-content{padding-top:0!important;margin-top:0!important}body:not(.__page_main) .bc_alternate_header_live_tabs,body:not(.__page_main) .mls_hash_tag,body:not(.__page_main) .__fixed_top{position:static!important;margin:0!important}.bc_sticky_bar{position:fixed!important;top:var(--bc-sticky-y,80px)!important;left:var(--bc-sticky-x,50%)!important;transform:var(--bc-sticky-tf,translateX(-50%))!important;margin:0!important;bottom:auto!important;z-index:9990!important;pointer-events:none!important}.js-filter_button{pointer-events:auto!important;display:flex;justify-content:center}#chat_bar_v2_container{display:block!important;opacity:1!important;pointer-events:auto!important;z-index:2147483605!important}#chat_bar_v2,#chatProfileButton,#chatBarChatButton,#switch_between_chat{display:flex!important;opacity:1!important;pointer-events:auto!important;z-index:2147483605!important}@media (min-width:1024px){*:fullscreen video,*:-webkit-full-screen video,video:fullscreen,video:-webkit-full-screen{object-fit:contain!important;width:100%!important;height:100%!important;max-width:100vw!important;max-height:100vh!important;margin:auto!important}}`;

const firstSegment = () => location.pathname.split('/').filter(Boolean)[0] || '';
const slugName = (reserved, valid) => () => {
    const f = firstSegment();
    return f && !reserved.test(f) && valid.test(f) ? f : '';
};
const BC_SYS = /^(?:ru|uk|ua|en|es|de|fr|pt|it|pl|tr|nl|cs|ro|hu|bg|el|ja|zh|ko|he|ar|hi|id|vi|th|tags?|categor(?:y|ies)|free-cams|all|search|girls|couples?|male|men|guys|female|trans|transsexual|new|top|models|favou?rites|live|cams|blog|help|support|settings|terms|privacy|faq|contacts|login|signup|register|apps|mobile|profile)$/i;
const bcDisplayName = () => {
    const d = Helpers.getModelSecretData();
    return d?.chatHost?.displayName
        || document.querySelector('#bChatRoomTitle, .chat-header-inner h1 a')?.textContent?.trim() || '';
};
const bcFallbackName = () => {
    const d = Helpers.getModelSecretData();
    return bcDisplayName() || d?.chatHost?.username || '';
};

const SC_SYS = /^(?:girls|men|guys|couples|trans|tags?|favorites|favourites|login|signup|search|blog|cams|explore|top|api|help|support|terms|privacy|models|profile|settings|videos|photos|pricing|studios|category|categories|new|vr|contest|announcement|user|guests|latest|about|contact|dmca|2257|tokens|messages|notifications|affiliates|shop|rewards|community)$/i;
const CB_SYS = /^(?:b|tags?|.+-cams|accounts|auth|tipping|supporter|affiliates|api|contest|apps|security|terms|privacy|dmca|support|billing|photo_videos|store|login|signup|register|search|explore|hosting|location|followed|follow|female|male|couple|trans|featured|2257|tokens|purchase|help|about|press|contact|sitemap|faq|studios|business|broadcast|messages|notifications|settings|cams|chatbot)$/i;
const FS_CSS = '@media (min-width:1024px){*:fullscreen video,*:-webkit-full-screen video,video:fullscreen,video:-webkit-full-screen{object-fit:contain!important;width:100%!important;height:100%!important;max-width:100vw!important;max-height:100vh!important;margin:auto!important}}';

const currentSite = (() => {
    const hostname = window.location.hostname;
    const configs = {
        bongacams: {
            match: BC_RE,
            videoSelectors: BC_CONTAINERS.map(s => `${s} video`).concat('video'),
            containerSelectors: BC_CONTAINERS,
            getName: () => {
                const [first = '', second = ''] = location.pathname.split('/').filter(Boolean);
                const raw = !BC_SYS.test(first) ? first : /^profile$/i.test(first) ? second : '';
                return bcDisplayName() || safeDecode(raw) || bcFallbackName();
            },
            css: BC_CSS
        },
        stripchat: {
            match: /stripchat|strpst/,
            videoSelectors: ['video.video-element', '.player video', '.web-rtc-player video', 'video'],
            containerSelectors: ['.player-wrapper', '[class*="ViewCamPlayer"]', '.web-rtc-player-wrapper', '.video-element-wrapper'],
            getName: slugName(SC_SYS, /^[\w.-]+$/),
            css: FS_CSS
        },
        chaturbate: {
            match: /chaturbate/,
            videoSelectors: ['#chat-player_html5_api', '#VideoPanel video', '.videoPlayerDiv video', '.video-js video', 'video'],
            containerSelectors: ['#VideoPanel', '.videoPlayerDiv', '#chat-player', '.video-js', '#video_container'],
            getName: slugName(CB_SYS, /^\w+$/),
            css: FS_CSS
        }
    };
    return Object.values(configs).find(c => c.match.test(hostname)) || configs.bongacams;
})();

const LANGS = ['RU', 'EN', 'UK', 'ES', 'DE', 'FR', 'PT', 'IT', 'PL', 'TR', 'NL', 'CS', 'RO', 'HU', 'BG', 'EL', 'JA', 'ZH', 'KO', 'HE', 'AR', 'HI', 'ID', 'VI', 'TH'];
const RTL_LANGS = ['HE', 'AR'];
const LANG_NAMES = { RU: 'Русский', EN: 'English', UK: 'Українська', ES: 'Español', DE: 'Deutsch', FR: 'Français', PT: 'Português', IT: 'Italiano', PL: 'Polski', TR: 'Türkçe', NL: 'Nederlands', CS: 'Čeština', RO: 'Română', HU: 'Magyar', BG: 'Български', EL: 'Ελληνικά', JA: '日本語', ZH: '中文', KO: '한국어', HE: 'עברית', AR: 'العربية', HI: 'हिन्दी', ID: 'Bahasa Indonesia', VI: 'Tiếng Việt', TH: 'ไทย' };
const detectLang = () => {
    let list = [];
    try { list = [...(navigator.languages?.length ? navigator.languages : [navigator.language]), document.documentElement?.lang]; } catch {}
    for (const c of list) {
        const k = String(c || '').slice(0, 2).toUpperCase().replace('IW', 'HE');
        if (LANGS.includes(k)) return k;
    }
    return 'EN';
};
const savedLang = Store.get('bc_lang', null);
const langAuto0 = Store.get('bc_lang_auto', savedLang == null) === true;

const AppState = {
    bgPlay: Store.get('bc_bg', true),
    isMinimized: Store.get('bc_min', false),
    isHidden: Store.get('bc_hid', false),
    scale: parseFloat(Store.get('bc_scale', 1)),
    posX: Store.get('bc_x', null),
    posY: Store.get('bc_y', null),
    hasPos: Store.get('bc_pos', false),
    theme: Store.get('bc_theme', 'rgba(220, 20, 60, 0.9)'),
    langAuto: langAuto0,
    lang: langAuto0 ? detectLang() : (LANGS.includes(savedLang) ? savedLang : 'RU'),
    gmute: Store.get('bc_gmute', false) === true,
    bookmarks: Store.get('bc_bookmarks', []).filter(isObj),
    dark: Store.get('bc_dark', false) === true
};
const FavNav = {
    get on() { return Store.get('bc_favnav', false) === true; },
    set(v) { Store.set('bc_favnav', !!v); this.apply(); },
    apply() { try { this.hook && this.hook(this.on); } catch {} }
};

const bmTomb = new Set();
let bmSaveFailed = false;
const bmRuntimeKey = k => k[0] === '_' || k === 'label';
const saveBookmarks = () => {
    try {
        const have = new Set(AppState.bookmarks.filter(b => isObj(b) && isStr(b.url)).map(b => bmKey(b.url)));
        const stored = Store.get('bc_bookmarks', []);
        if (Array.isArray(stored)) for (const r of stored) {
            if (!validBm(r)) continue;
            const k = bmKey(r.url);
            if (have.has(k) || bmTomb.has(k)) continue;
            have.add(k);
            AppState.bookmarks.push({ ...stripBm(r) });
        }
    } catch {}
    bmSaveFailed = !Store.set('bc_bookmarks', AppState.bookmarks.filter(isObj).map(stripBm));
    if (!bmSaveFailed) bmTomb.clear();
};
const incomingBookmarks = arr => {
    const m = new Map();
    for (const r of arr) if (validBm(r)) m.set(bmKey(r.url), r);
    return m;
};
const BM_LIVE = ['status', 'viewers', 'frame', 'topic'];
const mergeInto = (b, src, skip) => {
    for (const f of Object.keys(b)) if (!bmRuntimeKey(f) && !BM_LIVE.includes(f) && !(f in src) && !skip.includes(f)) delete b[f];
    for (const f of Object.keys(src)) if (!skip.includes(f)) b[f] = src[f];
};
const mergeRemoteBookmarks = (arr, skip = []) => {
    if (!Array.isArray(arr)) return false;
    const incoming = incomingBookmarks(arr), out = [], seen = new Set();
    for (const b of AppState.bookmarks) {
        if (!isObj(b)) continue;
        if (!isStr(b.url)) { out.push(b); continue; }
        const k = bmKey(b.url), r = incoming.get(k);
        if (seen.has(k) || (!r && !bmSaveFailed)) continue;
        seen.add(k);
        if (r) mergeInto(b, stripBm(r), skip);
        out.push(b);
    }
    incoming.forEach((r, k) => { if (!seen.has(k)) out.push({ ...stripBm(r) }); });
    AppState.bookmarks = out;
    return true;
};
const syncBookmarks = () => {
    try { const a = Store.get('bc_bookmarks', null); if (Array.isArray(a)) mergeRemoteBookmarks(a); } catch {}
};
const dropBookmark = b => {
    const k = isStr(b.url) ? bmKey(b.url) : null;
    if (k) bmTomb.add(k);
    AppState.bookmarks = AppState.bookmarks.filter(x => x !== b && !(k && isObj(x) && isStr(x.url) && bmKey(x.url) === k));
    saveBookmarks();
};
const setGMute = v => { AppState.gmute = !!v; Store.set('bc_gmute', !!v); };
const sameBm = (b, name) => String(b.name).toLowerCase() === String(name).toLowerCase() && urlSite(b.url) === SITE;

const mergeBookmarks = arr => {
    const seen = new Set(AppState.bookmarks.map(b => bmKey(b.url)));
    let added = 0;
    for (const raw of arr) {
        const b = cleanBm(raw);
        if (!b) continue;
        const k = bmKey(b.url);
        if (seen.has(k)) continue;
        seen.add(k);
        bmTomb.delete(k);
        AppState.bookmarks.push(b);
        added++;
    }
    saveBookmarks();
    return added;
};

const DARK_FB_CSS = `html.bc-dark-fb{filter:invert(1) hue-rotate(180deg)!important;background:#fff}
html.bc-dark-fb :is(video,img,picture,canvas,iframe,[style*="background-image"],#bc-unchained-host){filter:invert(1) hue-rotate(180deg)!important}
html.bc-dark-fb.bc-theater-html,html.bc-dark-fb.bc-theater-html :is(video,img,picture,canvas,iframe,[style*="background-image"],#bc-unchained-host){filter:none!important}`;
const DARK_M_CSS = () => `html.bc-dark-m{color-scheme:dark;background:#121216}
html^body,html^.ui-page,html^.ui-body-c,html^.ui-content,html^.ui-panel-content-wrap,html^.bc-content{background:#121216!important;color:#dedede;text-shadow:none}
html^#chat_bar_v2_container,html^.inputContainer,html^.video-panel-wrap{background:#18181c!important}
html^.history,html^.history p.msg_wrp,html^.history .msg,html^.history dfn:after{color:#dedede}
html^.history p:not(.model) .author_name{color:#e8e8ec}
html^.np_title,html^.nt_message_title,html^.bc_notice.__topic{color:#ee5b78}
^.cp_purchase_popup{--bc-thm-purchasePopup-bg:#121213;--bc-thm-purchasePopup-accent-color:#e17085;--bc-thm-purchasePopup-avatar-bg:#212124;--bc-thm-purchasePopup-desc-divider-bg:#212124;--bc-thm-purchasePopup-title-color:#bcbcbc;--bc-thm-purchasePopup-desc-color:#d4d4d4}
^.bc_confirm_popup_wrp{--bc-thm-confirmPopup_error-color:#f65a61;--bc-thm-confirmPopup_action_column-confirmBtn_decline-bg:#252527;--bc-thm-confirmPopup_action_column-confirmBtn_decline-bg-active:#323235;--bc-thm-confirmPopup_fanBoostWhat-bg:#121213;--bc-thm-confirmPopup_fanBoostWhat-color:#d8d8d8;--bc-thm-confirmPopup_fanBoostWhat-accent-color:#d67b87;--bc-thm-confirmPopup_fanBoostWhat-benefits-bg:#151517;--bc-thm-confirmPopup_fanBoostWhat-statuses-item-borderColor:#3b3b3f}
^.bc_confirm_popup.__confirmed_light{--bc-thm-confirmPopup_confirmLight-bg:#151516;--bc-thm-confirmPopup_confirmLight-color:#d8d8d8;--confirmPopup_profile_media-confirm-title-color:#e17085;--confirmPopup_profile_media-confirmBtn_decline-color:#cecece}
^.bc_confirm_popup_wrp.__vertical_orientation{--confirmPopup_vertical_orientation-color:#d8d8d8}
^.bc_confirm_popup.__qoq_contest{--bc-thm-confirmPopup_qoqContest-color:#f5f5f5}
^.bc_confirm_popup.__gift_preview{--confirmPopup_giftPreview-body-bg:#121213}
^.bc_confirm_popup.__private_close{--bcm-privateClose-title-color:#e17085}
^.mbc_btn{--bcm-btn-color:#cecece;--bcm-btn-bg:#252527;--bcm-btn-bg-active:#1d1d1f;--bcm-btn-bg-hover:#1b1b1d;--bcm-btn_secondary-color:#cecece;--bcm-btn_secondary-bg:#1c1c1e;--bcm-btn_secondary-bg-active:#323235;--bcm-btn_secondary-bg-hover:#1b1b1d;--bcm-btn_outline-borderColor:#3e3e43}
^.bc_static_page{--bcm-static-page-color:#d8d8d8;--bcm-static-page-striped-content-div-even-text-shadow-color:rgba(0,0,0,0);--bcm-static-page-striped-content-div-even-bg-color:#1a1a1c;--bcm-static-page-header-text-shadow-color:rgba(0,0,0,0);--bcm-static-page-header-bg-color:#1a1a1c}
^#mainbar{--bcm-mainbar-btn-color:#d8d8d8;--bcm-mainbar-btn-bg-active:#19191b;--bcm-mainbar-menuItemList-subItem-color:#e17085}
^#mainbar .holiday_discount{--bcm-sidebar-holidayDiscount-accent-color:#e17085}
^.bc_alternate_header_live_tabs{--alternateHeaderLiveTabs-base-color:#d8d8d8;--alternateHeaderLiveTabs-bg:#18181a;--alternateHeaderLiveTabs-scrollShadow-bg:linear-gradient(270deg, #18181a 0%, #f2f2f200 100%)}
^.bc_skeleton_item{--bcm-skeleton-item-bg-color:#18181a}
^.bc_skeleton_item:before{--bcm-skeleton-item-pseudo-bg-color:#121213}
^.bcm_alphabet_filter{--bcm-alphabetFilter-base-accent-color:#e17085;--bcm-alphabetFilter-base-borderColor:#404044;--bcm-alphabetFilter-dropdown-bg:#121213;--bcm-alphabetFilter-dropdown-item-color:#d8d8d8;--bcm-alphabetFilter-select-bg:#121213;--bcm-alphabetFilter-select-caption-color:#d8d8d8}
^.bcm_pagination{--bcm-pagination-item-color:#f3f3f3;--bcm-pagination-item-bg-color:#18181a;--bcm-pagination-item-bg-color-active:#1b1b1d;--bcm-pagination-item-border-color:#3e3e42}
^.bcm_fp_features{--bcm-filter-results-features-item-color:#f5f5f5;--bcm-filter-results-features-item-bg-color:#161618}
^.bcm_checkbox{--bcm-checkbox-mark-bg-color:#252527;--bcm-checkbox-mark-border-color:#4c4c52;--bcm-checkbox-mark-icon-fill:#bcbcbc;--bcm-checkbox-text-color:#bcbcbc;--bcm-checkbox-disabled-mark-bg-color:#1b1b1d;--bcm-checkbox-disabled-mark-border-color:#3c3c40;--bcm-checkbox-checked-text-color:#f5f5f5}
^.bcm_radio{--bcm-radio-icon-color:#e17085}
^.bcm_range{--bcm-range-values-color:#bcbcbc;--bcm-range-track-bg-color:#1a1a1c;--bcm-range-handle-bg-color:#121213;--bcm-range-handle-border-color:#45454a}
^.bcm_form_alert{--bcm-form-alert-error-color:#ff5252;--bcm-form-alert-error-bg-color:#19191b}
^.bcm_accordion{--bcm-accordion-title-color:#c1c1c1;--bcm-accordion-arrow-fill:#f5f5f5}
^.bc_nav_tabs_wrp{--navigationTabs-item-color:#d8d8d8;--navigationTabs-inner-bg:#18181a;--navigationTabs-item-borderColor:#38383c;--navigationTabs_tags-after-bg:linear-gradient(270deg, #18181a, #f2f2f200)}
^.bc_fade_scroll{--fadeScroll-fade-bg:linear-gradient(90deg, #18181a, rgba(24,24,26,0)}
^.bc_fade_scroll.__listing_tags{--fadeScroll-fade-bg:linear-gradient(90deg, #121213, rgba(18,18,19,0)}
^.smileysContainer{--mobile-smiles-panel-container-background-color:#121213;--mobile-smiles-panel-container-border-color:#4c4c52;--mobile-smiles-panel-close-wrapper-color:#e36e84;--mobile-smiles-panel-title-wrapper-color:#e2e2e2;--mobile-smiles-panel-title-shortcut-color:#c0c0c0;--mobile-smiles-panel-tab-color:#d2d2d2;--mobile-smiles-panel-tab-background-color:#151516;--mobile-smiles-panel-tab-background-color-hover:#121213;--mobile-smiles-panel-tab-border-color:#353539;--mobile-smiles-panel-tab-active-background-color:#121213}
^.bcm_socials{--bcm-thm-socials-counter-color:#bcbcbc;--bcm-thm-socials-counter-bg:#121213;--bcm-thm-socials-counter-borderColor:#45454a}
^.bcm_switcher{--bcm-switcher-bg:#222225}
^.bc_notice{--bcm-notice-color:#e6e6e6;--bcm-notice-bg:linear-gradient(#121213, #121213);--bcm-notice-close-iconColor-hover:#dedede;--bcm-notice_secondary-paragraph-color:#d8d8d8;--bcm-notice_membershipError-close-iconColor-hover:#a960f0;--bcm-notice_sexToy-avatar-boxShadowColor:rgba(0,0,0,0);--bc-thm-notice_attention-bg:#181819;--bc-thm-notice_attention-color:#a866eb;--bc-thm-notice_topic-bg:#161618;--bc-thm-notice_topic-color:#e17085}
^.bc_picture_stub{--bcm-thm-pictureStub-iconColor:linear-gradient(180deg, #e07184 0%, #e36d84 100%)}
^.bc_carousel_bar{--carouselBar-item_active-inner-bg:#121213}
^.mbc_header{--mob-header-menuBtn-shadow-color:rgba(0,0,0,0);--mob-header-menuBtn-bg:#121213}
^.mbc_header_menu{--mob-header-menu-border-color:#4c4c52;--mob-header-menu-item-bg:#141416;--mob-header-menu-action-color:#f5f5f5}
^.mbc_header_menu.__sorting{--mob-header-menu-item-border-color:#49494e}
^.bcm_footer{--bcm-thm-footer-bg:#18181a;--bcm-thm-footer-borderColor:#2b2b2e;--bcm-thm-footer-details-color:#d8d8d8;--bcm-thm-footer-details-nav-link-color:#d8d8d8;--bcm-thm-footer-details-nav-link-bg-active:#1d1d1f;--bcm-thm-copyright-color:#d8d8d8;--bcm-thm-copyright-link-color:#df7187}
^.mls_item{--bcm-thm-listingThumb-stub-bg:#161617;--bcm-thm-listingThumb-stub-img-bg:#1d1d1f}
^.mls_tag_badge{--bcm-listing-tagBadge-bg:#18181a;--bcm-listing-tagBadge-borderColor:#3e3e42;--bcm-listing-tagBadge-color:#f3f3f3}
^.lscl_item{--listing-category-item-color:#f3f3f3;--listing-category-item-bg-color:#1c1c1e;--listing-category-item-firstRow-color:#ececec;--listing-category-item-firstRow-bg:#18181a;--listing-category-item-firstRow-bg-active:#212124}
^.listing_age_verification_banner{--ageVerificationBanner-icon-color:linear-gradient(#e26e84, #e17084)}
^.mls_hash_tag{--mlsHashTag-tag-color:#ececec;--mlsHashTag-tag-bg:#18181a;--mlsHashTag-tag-bg-active:#212124;--mlsHashTag-tag_record-icon-color:#bdbdbd;--mlsHashTag-removeFilterLink-close-iconColor:#d4d4d4}
^.instant_buy{--bcm-instant-buy-bar-border-color:#4c4c52;--bcm-instant-buy-success-wrp-circle-border-color:#4c4c52;--bcm-instant-buy-success-wrp-block-bg:#121213;--bcm-instant-buy-menu-bg:#161617;--bcm-instant-buy-menu-block-bg-active:#1e1e20;--bcm-instant-buy-menu-item-color:#eeeeee;--bcm-instant-buy-menu-item-desc-color:#c5c5c5}
^.bc_chat_topic{--bcm-chatTopic-bg:#121213;--bcm-chatTopic-inner-bg:rgba(22,22,24,0.9);--bcm-chatTopic-content-color:#e6e6e6;--bcm-chatTopic-title-color:#e17085}
^.chat_notice{--bcm-chatNotice-color:#e6e6e6;--bcm-chatNotice-inner-bg:#121213;--bcm-chatNotice-link-color:#52a1ff;--bcm-chatNotice-author-name-color:#e6e6e6}
^.chat-panel .history .service_list{--sysMsg-serviceList-bg:#121213;--sysMsg-serviceList-authorName-color:#e6e6e6;--sysMsg-serviceList-title-color:#f5f5f5;--sysMsg-serviceList-services-item-bg-hover:#181819;--sysMsg-serviceList-item-title-color:#e6e6e6;--sysMsg-serviceList-showBtn-color:#d8d8d8;--sysMsg-serviceList-showBtn-bg:#121213;--sysMsg-serviceList-showBtn-borderColor:#38383c;--sysMsg-serviceList-showBtn-color-active:#f5f5f5;--sysMsg-serviceList-showBtn-borderColor-active:#49494e;--sysMsg-serviceList-showBtn-bg-active:#121213}
^.bcm_chat_footer{--bcm-chat-footer-item-border-color:#323235;--bcm-chat-footer-item_tipMenu_disabled-bg:#38383c}
^.bcm_history_scroll_up{--bcm-historyScrollUp-bg:#252527;--bcm-historyScrollUp-link-color:#e17085}
^.bcm_chat_auto_message{--bcm-chat-member-notification-borderColor:#45454a;--bcm-chat-member-notification-title-color:#e2e2e2}
^.video-panel-wrap{--videoPanelWrap-bg:#121213}
^.mbc_tabs{--bcm-tabs-item-color:#d8d8d8;--bcm-tabs-item-bg:#18181a;--bcm-tabs-item_selected-color:#d8d8d8;--bcm-tabs-item_selected-bg:#18181a}
^.bcm_nav_panel{--bcm-navPanel-bg:#18181a;--bcm-navPanel-item-color:#d8d8d8;--bcm-navPanel-item_active-color:#e36e84}
^.f_rptfmm .buy_tokens,^.f_rptsmm .buy_tokens{--bcm-base-buyTokens-color:#d8d8d8;--bcm-base-buyTokens-borderColor:#36363a;--bcm-base-buyTokens-error-color:#ff5272;--bcm-buyTokens-bg:#121213;--bcm-buyTokens-text_faded-color:#bcbcbc;--bcm-buyTokens-decline-text-bg:#161617;--bcm-buyTokens-paymentMethodCards-card-bankCounter-bg:#121213;--bcm-buyTokens-packages-checkbox_off-borderColor:#4a4a50;--bcm-buyTokens-packages-error-bg:#19191b;--bcm-buyTokens-confirmCode-title-accent-color:#e17085;--bcm-buyTokens-amountField-bg:#121213;--bcm-buyTokens-amountField_onlyLocalCurrenct-localCurrency-color:#d8d8d8;--bcm-buyTokens-choice-bg:#121213;--bcm-buyTokens-choice-iconRadioOff-bg:#313134;--bcm-buyTokens-select-iconWrp-bg:#131315;--bcm-buyTokens-stickyFooter-bg:#121213}
^.f_rptsmm .buy_tokens{--bcm-buyTokens-paymentMethodCards-moreBtn-iconWrp-bg:#161617;--bcm-buyTokens-morePaymentMethodsPopup-bg:#121213;--bcm-buyTokens-morePaymentMethodsPopup-listWrp-shadow-bg:linear-gradient(180deg, #161617 35%, rgba(22,22,23,0.8) 50%, #ebfff000 100%);--bcm-buyTokens-morePaymentMethodsPopup-item-bg:#161617;--bcm-buyTokens-morePaymentMethodsPopup-item_active-bg:#121213;--bcm-buyTokens-morePaymentMethodsPopup-item-bankCounter-bg:#121213}
^.bcm_popup{--bcm-popup-body-bg-color:#121213}
^.categories_popup{--bcm-popup-categories-main-bg-color:#121213;--bcm-popup-categories-list-wrp-border-color:#45454a;--bcm-popup-categories-item-icon-color:#e17085;--bcm-popup-categories-item-color:#d8d8d8;--bcm-popup-categories-item-bg-color-active:#1b1b1d;--bcm-popup-categories-item-counter-bg-active:#121213}
^.filter_popup{--bcm-popup-filter-main-bg:#121213;--bcm-popup-filter-features-title-color:#c1c1c1;--bcm-popup-filter-footer-borderColor:#45454a;--bcm-popup-filter-notice-color:#c1c1c1;--bcm-popup-filter-button-outline-bg:#2b2b2e;--bcm-popup-filter-button-outline-borderColor:#3f3f44}
^.search_popup{--bcm-popup-search-header-bg-color:#18181a}
^.mbc_search_block{--bcm-search-block-input-bg-color:#121213;--bcm-search-block-input-borderColor:#404044;--bcm-search-block-input-placeholder-color:#d8d8d8;--bcm-search-block-header-close-icon-color:#d8d8d8;--bcm-search-block-reset-button-bg-color:#1a1a1c;--bcm-search-block-reset-button-border-color:#45454a;--bcm-search-block-result-empty-color:#e17085;--bcm-search-block-result-recent-title-color:#e17085;--bcm-search-block-result-name-color:#f5f5f5;--bcm-search-block-result-border-color:#333337;--bcm-search-block-result-tag-color:#ececec;--bcm-search-block-result-tag-name-bg-color:#18181a;--bcm-search-block-result-tag-symbol-color:#e17085}
^#pop-sorting-popup{--bcm-thm-popSortingPopup-sortingItem-color:#f5f5f5}
^.categories{--bcm-categories-skeleton-bg:#151516}
^.contact_support_page{--bcm-contact-support-page-title-color:#e17085;--bcm-contact-support-page-text-color:#d4d4d4;--bcm-contact-support-page-form-label-color:#f5f5f5;--bcm-contact-support-page-item-border-color:#353539}
^.join{--bcm-join-base-color:#d8d8d8;--join-bg:#121213;--join_login-flashAlert-bg:#19191b;--join_login-redirect-bg:#212124;--join_login-redirect-borderColor:#45454a;--join_login-redirect-text-color:#d8d8d8;--join_login-redirect-text-shadowColor:rgba(0,0,0,0)}
^.join_form{--bcm-joinForm-color:#d8d8d8;--bcm-joinForm-termsOfUse-bg:#151516;--bcm-joinForm-termsOfUse-color:#cecece;--bcm-joinForm-termsOfUse-checkbox-borderColor:#45454a;--bcm-joinForm-termsOfUse-checkbox-bg:#121213;--bcm-joinForm-input-color:#f5f5f5;--bcm-joinForm-input-bg:#151516;--bcm-joinForm-input-borderColor:#4c4c52;--bcm-joinForm-formLink-color:#b6b6b6}
^.invisible_mode_overview{--bc-thm-invisibleModeOverview-content-color:#9099c1;--bc-thm-invisibleModeOverview-promoBlock-feature-bg:#151517;--bc-thm-invisibleModeOverview-switchBlock-box-bg:linear-gradient(180deg, #121213 0%, #141416 100%);--bc-thm-invisibleModeOverview-switchBlock-box-borderColor:#38383c;--bc-thm-invisibleModeOverview-switchBlock-title-color:#9099c1;--bc-thm-invisibleModeOverview-switcher-wrp-bg:linear-gradient(180deg, #b6bfd1 0%, #121213 100%)}
^.invisible_mode_overview_plank{--bc-thm-invisibleModeOverviewPlank-color:#cacaca;--bc-thm-invisibleModeOverviewPlank-bg:#151516}
^.im_conversations .imc_reply{--bcm-im-reply-bg:#121213;--bcm-im-reply-borderColor:#323235;--bcm-im-reply-quickSmiles-bg:#121213;--bcm-im-reply-quickSmiles-borderColor:#3d3d41}
^.im_conversations .imc_rf_textarea_wrapper{--bcm-im-replyForm-textareaWrapper-control-color:#c4c4c4;--bcm-im-replyForm-textareaWrapper-control-textShadowColor:rgba(0,0,0,0);--bcm-im-replyForm-textareaWrapper-placeholder-color:#c4c4c4}
^.im_conversations .imc_rf_textarea_error{--bcm-im-replyForm-textareaError-color:#ff5252}
^.im_conversations .imc_r_button{--bcm-im-replyButton_smilepicker-trigger-icon-stroke:#c4c4c4;--bcm-im-replyButton_smilepicker-trigger_active-icon-stroke:#f5f5f5}
^.im_conversations .imc_balance_restriction_alert{--im-balanceRestrictionAlert-color:#d4d4d4;--im-balanceRestrictionAlert-bg:#151516;--im-balanceRestrictionAlert-title-color:#e17085}
^.im_conversations .imc_kicked_alert{--im-kickedAlert-color:#d4d4d4;--im-kickedAlert-acent-color:#e17085;--im-kickedAlert-bg:#121213;--im-kickedAlert-borderColor:#45454a}
^.im_conversations .imc_notification{--im-notification-color:#e6e6e6;--im-notification_pink-accent-color:#ea67ce}
^.im_conversations .imch_contact_card{--im-contactCard-color:#d4d4d4;--im-contactCard-accent-color:#e17085;--im-contactCard-checkbox-color:#d8d8d8;--im-contactCard-bg-color:#121213;--im-contactCard-borderColor:#45454a}
^.imch_reactions{--im-reactions-item-bg:#121213;--im-reactions-item_own-bg:#161617;--im-reactions-item-focus-bg:#161617;--im-reactions-counter-color:#d2d2d2}
^.bc_switch_lang_popup{--bcm-thm-switchLangPopup-bg:#121213;--bcm-thm-switchLangPopup-close-color:#e17085;--bcm-thm-switchLangPopup-title-color:#e17085;--bcm-thm-switchLangPopup-noteText-color:#bdbdbd;--bcm-thm-switchLangPopup-note-bg:#141415;--bcm-thm-switchLangPopup-note-borderColor:#45454a;--bcm-thm-switchLangPopup-flagsGroup-itemCaption-color:#cecece}
^.mbc_alert{color:#d6d6d6;background:#121213}
^.mbc_alert.__info{color:#c9c9c9;background:#151516;border:1px solid #3f3f43}
^.mbc_alert.__warning{color:#ff5253;background:#171718}
^.bc_btn{color:#cecece;background:#252527}
^.bc_btn:active{background:#303033}
^.bc_btn.bc_btn_white{background:#121213;border:1px solid #3f3f44;color:#cecece !important}
^.bc_btn.bc_btn_white:active:not(.__disabled),^.bc_btn.bc_btn_white:hover:not(.__disabled){background:linear-gradient(#131315,#18181a)}
^.bc_btn.bc_btn_white.__disabled,^.bc_btn.bc_btn_blue.__disabled{background:#18181a;border-color:#36363a}
^.bc_btn.bc_btn_light{background:linear-gradient(#151516,#1a1a1c);border:1px solid #3f3f44;color:#cecece !important}
^.bc_btn.bc_btn_light:active:not(.__disabled),^.bc_btn.bc_btn_light:hover:not(.__disabled),^.bc_btn.bc_btn_light.__disabled{background:linear-gradient(#1a1a1c,#151516)}
^.bc_confirm_popup_wrp.__hint,^.bc_confirm_popup_wrp .bc_confirm_popup.__dialog .dlg_subTitle,^.bc_confirm_popup_wrp .account_deleted_popup,^.bc_confirm_popup_wrp .questions_popup,^.bc_confirm_popup_wrp .bc_confirm_popup.__paid_chat_hint .bc_cp_body,^.bc_confirm_popup_wrp .cancel_account_confirm,^.bc_confirm_popup_wrp .bc_confirm_popup.__auto_message_chat_hint .bc_cp_body,^.bcm_radio.__background .bcm_r_input:checked~.bcm_r_text,^.bcm_input_row,^.forward_to_remote,^.im_conversations .pm_confirm_email .pmc_body,^.im_conversations .pm_confirm_email .pmc_body .pmc_item,^.im_conversations .pm_offering .pmob_item,^.im_conversations .pm_offering .pmol_item{color:#d4d4d4}
^.bc_confirm_popup_wrp.__ask_again .bcc_header .bcc_title,^.bc_confirm_popup_wrp .bc_confirm_popup.__error .bcc_container_info,^.bc_confirm_popup_wrp .bcc_no_header_popup .nh_title,^.bc_confirm_popup_wrp .bc_confirm_popup.__dialog.__d_alert .dlg_title,^.bc_confirm_popup_wrp .account_deleted_popup .adp_title,^.bc_confirm_popup_wrp .questions_popup .qp_title,^.bc_confirm_popup_wrp .questions_popup .qp_accent,^.bc_confirm_popup_wrp .delete_msg .dm_accent,^.bc_confirm_popup_wrp .cancel_account_confirm .cac_title,^.bcm_input_row .bcm_i_label_required,^.mls_title .mlst_icon.__category,^.vip-payment .inner-vip .vip-blocks,^.suspect_login_page .slp_desc,^.bc_cmn_confirm_wrp.__danger .bc_confirm_popup .bcc_title,^.head_confirm_box .hcb_close_wrp .hcb_close,^.aChat .message.admin strong,^#admin_chat_popup .admin_info .details .label,^.buy_tokens h4 strong,^.verify_info_box p b,^.confirm_box .line b,^.confirm_box .note span,^.bt_first_step span,^.buy_tokens .discount_gift_card .new_price,^.loyalty_box.leaving .lb_blue,^.account_preview .acp_alert,^.forward_to_remote .ftr_highlight,^.imch_reply .imch_r_author,^.imc_footer_reply .imc_fr_username,^.imc_footer_reply .imc_fr_close_icon,^.im_conversations .pm_valentine_day_themed_gift .pmvdtgd_accent,^.cg_vibe_with_me .vwm_s_danger{color:#e17085}
^.bc_confirm_popup_wrp.__ask_again .cgr_label,^.bc_confirm_popup_wrp.__ask_again .cg_label,^.bc_confirm_popup_wrp.__ask_again .tknt_item,^.bc_confirmer .bcc_alert .ca_text,^.bcm_filter_result .fr_title,^.chat-panel .msg_chat_game .cg_msg_s_time,^.bc_cmn_confirm_wrp .bc_confirm_popup .bcc_title,^.confirm_box .example_box,^.cg_overlay .cg_options_list .ol_item .cgo_label,^.cg_overlay .cg_accordion .cga_item .ai_title,^.cg_overlay .cg_adj_empty_playlist .ep_message,^.cg_overlay .cg_adj_list .it_title,^.cg_overlay .cg_adj_notice,^.cg_overlay .cg_adj_title,^.cg_overlay .cg_select_subtitle .ss_chosen{color:#c1c1c1}
^.bc_confirm_popup_wrp.__ask_again .cgr_label .bc_capitalize,^.bc_confirm_popup_wrp.__ask_again .cg_label .bc_capitalize,^.bc_confirm_popup_wrp.__ask_again .tknt_item .bc_capitalize,^.bc_confirm_popup_wrp .bc_confirm_popup.__display_name,^.bc_confirm_popup_wrp .bcc_header .bcc_title,^.bc_confirm_popup_wrp .bc_confirm_popup.__change_displayname .bcm_input_row .bcm_form_input,^.mbc_menu .mbcm_item.__default,^.translator_settings .bcf_check,^#mainbar .mm_icon,^#mainbar.__lang_list_opened .change-lang>.change-lang-btn,^.bcm_radio .bcm_r_input:checked~.bcm_r_text,^.mls_container.is_history .mlshiw_icon,^.vip-payment .head-vip i,^.vip-payment .head-vip,^.buy-descr,^#bChat .member,^.history p.model,^.history dfn:after,^.bcm_chat_selection .bcm_cs_title,^.bcm_chat_selection .bcm_cs_arrow,^.chat-panel .history .system_msg.msg_activity .mat_accent.__member,^.chat-panel .msg_chat_game.__vibe_with_me .cg_vwm_text,^.chat-panel .msg_chat_game .gc_msg_label,^.ic_menu_wrp .iw_translator,^.ic_menu_wrp .iw_font_picker,^.bc_cmn_confirm_wrp .bc_confirm_popup .bcc_title .bc_capitalize,^.head_confirm_box .hcb_text,^.buy_tokens .buy_tokens_form p.form_notice,^.buy_tokens h4,^.processors .ui-btn-inner,^.buy_tokens .choice.discount_box .discount_sum,^.buy_tokens label.choice.discount_box .discount_sum,^.buy_tokens .bt_payment_title,^.buy_tokens .sp_current_package .spcp_local_currency,^.buy_invisible_package .choice_title,^.buy_invisible_package .choice_footer,^.bcm_popup .bcm_p_content,^.mbc_search_block .sb_input,^.mbc_search_block .sb_result .sbr_title,^.account_preview .acp_name,^.im_conversations .pm_confirm_email,^.smilePanelTabs .sm_t_label,^.cg_overlay .cg_options_list .ol_item .cgo_label .ol_accent,^.cg_overlay .cg_result .cgr_preview,^.cg_overlay .cg_accordion .cga_item .ai_arrow,^.cg_overlay .cg_adj_form .djf_title,^.cg_overlay .cg_adj_list .pll_item.__playing .it_title,^.cg_overlay .cg_select_subtitle,^.cg_overlay .cg_select_subtitle .ss_chosen .ssc_amount,^.cg_vibe_with_me.__vwm_success,^.cg_vibe_with_me.__vwm_success .vwm_s_desc,^.cg_vibe_with_me .vwm_text{color:#f5f5f5}
^.bc_confirm_popup_wrp .bc_confirm_popup,^.bc_confirm_popup_wrp .bc_confirm_popup.__dialog .bc_cp_body,^.mbc_fullscreen_popup,^.what_view .what_view_close:before,^.bongacams_popup_v2 .popup_close:before,^.mls .mls_pager_header .mls_header_content,^.footer .support_group li.ui-btn-up-c,^.padded.white,^.padded.stripe:nth-child(2n),^.vip-payment .inner-vip,^#conversations .notfound,^#bChatFullScreenHistory p,^#chat_bar_v2_container,^.chat_prompt_wrp .cp_msg .cp_msg_decline_close:after,^.chat_prompt_wrp .cp_msg .cp_msg_decline_close:before,^.tap_model_popup_container .tap_container_inner,^.fancybox-tip-popup-wrap .fancybox-inner,^.bc_cmn_confirm_wrp .bc_confirm_popup,^.promo_in_banner_popup .pibp_body,^#admin_chat_popup .admin_chat_popup_content,^.buy_tokens .section .box,^.buy_tokens .bt_anim_icon_success:after,^.profile_avatar_popup,^.ac_change_photo .ac_cp_inner,^.imc_footer,^.imc_footer_alerts,^.im_conversations .imc_avatar .imc_avatar_img_wrap.__moderator,^.cg_overlay .cg_body,^.cg_keno_cube.__selected,^.bc_token_keno_field.__win .tkf_cube:hover .fc_body,^.bc_token_keno_field .tkf_cube.__checked:hover .fc_body,^.bc_token_keno_field .tkf_cube.__checked .fc_body,^.cg_overlay .cg_prize_list.__keno .pl_item.__open{background-color:#121213}
^.bc_confirm_popup_wrp .bc_confirm_popup.__tip .bc_cp_body .bcf_check,^.bcm_radio.__background,^.bcm_checkbox_row .cr_label,^.cg_overlay .cg_input_wrp .cgi_label{background:#1c1c1e}
^.bc_confirm_popup_wrp .bc_confirm_popup.__tip .bc_cp_body .bcf_text,^.cg_overlay .cg_input_wrp .cgi_text{color:#cecece;text-shadow:0 1px transparent}
^.bc_confirm_popup_wrp .bc_confirm_popup.__tip .bc_cp_body .bcf_mark,^.cg_overlay .cg_input_wrp .cgi_mark{background:#2a2a2d}
^.bc_confirm_popup_wrp .bc_confirm_popup.__tip .bc_cp_body .bcf_mark:before,^.bc_confirm_popup_wrp .bc_confirm_popup.__buy_fb .bc_cp_close:before,^.bc_confirm_popup_wrp .bc_confirm_popup.__buy_fb .bc_cp_close:after,^.bc_confirm_popup_wrp .bc_confirm_popup.__thank .bc_cp_close:before,^.bc_confirm_popup_wrp .bc_confirm_popup.__thank .bc_cp_close:after,^.bc_confirm_popup_wrp .bc_confirm_popup.__feedback .bc_cp_close:before,^.bc_confirm_popup_wrp .bc_confirm_popup.__feedback .bc_cp_close:after,^.bc_confirm_popup_wrp .account_deleted_popup .bcc_content,^#mainbar .mm_icon.__free,^.bc_confirmer .bcc_alert,^.holiday_discount_alert .hda_perc,^.bcm_skeleton:before,^.bcm_toggle_switcher_holder .ts_switcher:before,^.bcm_switcher.__on .bcm_s_slider:before,^.bcm_switcher .bcm_s_slider:before,^.info_part .icon_membership.icon_free,^.close_icon_wr span:before,^.close_icon_wr span:after,^.chat_prompt_wrp .cp_msg,^.chat_tooltip .close-btn:before,^.chat_tooltip .close-btn:after,^.bcm_oops_popup_layover .opl_body,^.popup_c2c_no_access .c2c_na_content,^.popup_c2c_no_access .c2c_na_close:before,^.popup_c2c_no_access .c2c_na_close:after,^.head_confirm_box .hcb_links .input_wrapper .ui-input-text,^.head_confirm_box .hcb_links .input_wrapper .hcb_input.ui-input-text,^.phone_confirm_box,^.sp_dropdown,html.bc-dark-m,^.buy_tokens .packages_badge .pb_icon,^#page_loader_overlay,^.loyalty_box.__personal .lb_holder,^.buy_tokens_header_board,^.bt_select_modal .slm_item,^.fancybox-wrap.__shemale_gold_slider_wrap .fancybox-close:before,^.fancybox-wrap.__shemale_gold_slider_wrap .fancybox-close:after,^.mbc_search_block .sb_result,^.popHint,^.vip_overview_stock_page .spp_list .pl_item,^.invisible_mode_overview .imsw_switcher:before,^.page_im.__settings .im_conversations,^.im_conversations .imc_actions .mbc_btn,^.im_conversations .imc_empty .imce_icon_wrp,^.im_conversations .imci_wrap,^.im_conversations .imc_followers .imcf_item,^.im_conversations .imc_search.__active .search_input,^.im_conversations .imc_search .search_input:focus,^.imch_reply,^.pm_activation_2fa .pmaf_alert,^.im_conversations .pm_upgraded_membership.__diamond .pmuh_logo_plank,^.im_conversations .pm_downgrade_membership .dmh_logo_plank,^.notice_need_tokens.__alert,^.smilePanel.smilePanelMobile .smilePanelContent,^.cg_overlay .gc_btn.__white,^.cg_overlay .cg_input_wrp .cgi_mark:before,^.cg_overlay .cg_game_field.__dice:before,^.bc_token_keno_field.__win .tkf_cube .fc_body,^.cg_vibe_with_me.__vwm_app .vwm_ai_title:after{background:#121213}
^.bc_confirm_popup_wrp .bc_confirm_popup.__tip .bc_cp_body .bcf_control{color:#d8d8d8;border:1px solid #4c4c52}
^.bc_confirm_popup_wrp .bc_confirm_popup.__tip .bc_cp_body .form_error,^.bc_confirm_popup_wrp .bc_confirm_popup.__social_buy .bc_cp_body .form_error,^.form .form_errors_row .form_error,^#bChat .msg_wrp .ch_m_tr_error,^.confirm_code_form strong.hl,^.im_conversations .imc_history_box .imch_item.__translate.__error .imch_msg_translate,^.cg_overlay .cg_result .cgr_prize .rp_text{color:#ff5252}
^.bc_confirm_popup_wrp .bc_confirm_popup.__social_buy.__profile_lg .bc_cp_body .bcf_input_block{background-color:#151516;border-color:#4c4c52}
^.bc_confirm_popup_wrp .bc_confirm_popup.__social_buy .bc_cp_body .bcf_label_wrp,^.ui-btn-hover-c:visited,^.ui-btn-hover-c:hover,^.ui-btn-hover-c a.ui-link-inherit,^.ui-btn-down-c:visited,^.ui-btn-down-c:hover,^.ui-btn-down-c a.ui-link-inherit,^.ui-btn-active:visited,^.ui-btn-active:hover,^.ui-btn-active a.ui-link-inherit,^.what_view.__pin .what_view_inner,^.bcm_checkbox_row .cr_text,^.phone_confirm_box .hcb_text,^.password_changed_box,^.loyalty_box.speaker .lb_first,^.loyalty_box.leaving,^.mbc_search_block .sb_result .sbr_delete_icon,^.profile_avatar_popup .account_actions .mbc_btn.ac_a_btn_cancel,^.account_actions .mbc_btn.ac_a_btn_cancel{color:#cecece}
^.bc_confirm_popup_wrp .bc_confirm_popup.__social_buy .bc_cp_body .bcf_input_block,^.live_tabs .tabs_list .tabsl_item.ui-btn-active{background-color:#1c1c1e}
^.bc_confirm_popup_wrp .bc_confirm_popup.__error .bcc_button{color:#cecece;background-color:#1a1a1c}
^.bc_confirm_popup_wrp .bcc_actions{border-top:1px solid #49494e}
^.bc_confirm_popup_wrp .bcc_no_header_popup{color:#d4d4d4;background:#151516}
^.bc_confirm_popup .cp_signup_wrap{color:#d8d8d8;background-color:#212124;border-top:1px solid #45454a}
^.bc_confirm_popup .cp_signup_title,^.ui-bar-e,^.ui-body-e,^.ui-overlay-e,^.video-item .date,^.model_status .author,^.im_conversations .gift_card_promo_wrapper .gift_card_promo .gift_card_promo_code_wrapper .gift_card_promo_code_valid,^.im_conversations .gift_card_promo_wrapper .gift_card_promo .gift_card_promo_bonuses .gift_card_promo_bonus{text-shadow:0 1px transparent}
^.bc_confirm_popup_wrp .bc_confirm_popup.__dialog .dlg_title,^.bc_confirm_popup_wrp .bc_confirm_popup.__change_displayname .bcm_i_label_txt,^.ui-body-b .ui-link-inherit,^.ui-body-c .ui-link-inherit,^.ui-bar-e .ui-link-inherit,^#mainbar .menu_item .mi_list .ui-btn,^#mainbar .menu_item .mi_list .mil_item.__collapsed .mil_sub_item,^#mainbar .combobox-lang,^#mainbar .combobox-lang .mm_arrow,^#mainbar .home .mm_live,^.auto_purchase_form,^.input_wrapper.__field_password .fp_icon_wrp,^.mls_title,^.notfound p,^.chat-panel .history .system_msg.msg_activity,^.bc_cmn_confirm_wrp .bc_confirm_popup .bcc_content,^.bt_first_step,^.buy_tokens .buy_tokens_auto_purchase,^.loyalty_box.leaving .lb_second,^.f_rptfmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description .action_block,^.f_rptsmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description .action_block,^.f_rptfmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description .sdp_phone_title,^.f_rptsmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description .sdp_phone_title,^.buy_tokens .bt_decline .btd_desc,^.ac_change_photo,^.ac_change_photo .ac_cp_sub_title,^.im_conversations .imc_history_box .imch_item.__translate.__error,^.im_conversations .imc_history_box .imch_item.__tip .imch_msg_text,^.im_conversations .imc_history_box .imch_msg_translate,^.im_conversations .pm_valentine_day_themed_gift .pmvdtg_name,^.im_conversations .pm_valentine_day_themed_gift .pmvdtgd_text,^.cg_vibe_with_me.__vwm_app .vwm_a_qr_icon,^.cg_vibe_with_me.__vwm_app .vwm_a_qr_icon_wrp{color:#d8d8d8}
^.bc_confirm_popup_wrp .questions_popup .qp_title.__warn{color:#f06171}
^.bc_confirm_popup_wrp .questions_popup .qp_accent_info,^.mls_container.is_history .mls_history_icon_wrp,^.chat_user_menu .cum_content,^.buy_tokens_sms_dimoco_package .input_phone.__extended_description .description_block,^.buy_tokens .bt_extened_description_block,^.im_conversations .imc_history_box .imch_badge_unread,^.notice_need_tokens .nnt_icon_wrp{background:#161617}
^.bc_confirm_popup_wrp .questions_popup .qp_accent_info .ai_title{color:#5ff281}
^.bc_confirm_popup_wrp .questions_popup.__support .qp_title,^.ui-body-e .ui-link-inherit,^.what_view .what_view_inner .title,^.msg_style_panel .msp_subtitle,^.bcm_chat_invite.__decline .bcm_ci_badge_icon{color:#e2e2e2}
^.bc_confirm_popup_wrp .delete_msg .dm_text,^.seo_box h2,^.seo_box h3,^.mls_title .mlst_icon.__recordable,^.tap_model_popup_container .tip_after_private .tap_title_block{color:#bdbdbd}
^.bc_confirm_popup_wrp .bc_confirm_popup.__up_status .bc_cp_body,^.popup_c2c_no_access .c2c_na_text,^.buy_tokens_redirect .btr_text.__action,^.im_conversations .imc_actions,^.im_conversations .imc_actions .mbc_btn.__btn_msg.__active .imca_text.__new_msg,^.im_conversations .imc_actions .mbc_btn.__btn_msg:active .imca_text.__new_msg,^.im_conversations .imc_actions .imca_text.__online,^.empty_conversation .ec_inner,^.im_conversations .imc_search.__active .imcs_icon,^.im_conversations .imc_search .search_input:focus+.imcs_icon,^.notice_need_tokens .nnt_text{color:#d6d6d6}
^.bc_confirm_popup_wrp .bc_confirm_popup.__up_status .ups_desc{background-color:#141416}
^.bc_confirm_popup_wrp .bc_confirm_popup.__help .bcc_button{color:#cecece;background:linear-gradient(#151516,#1a1a1c);border:1px solid #3f3f44}
^.bc_confirm_popup_wrp .bc_confirm_popup.__pin_list .bc_cp_body,^.bc_online_notification .ont_avatar_wrp,^.bc_online_notification .ont_info_wrp,^.bc_context_menu_list .cml_item:active,^.bcm_skeleton .bcms_inner,^.bc_body.tablet.android .chat_panel_area:after,^.bcm_chat_selection .bcm_cs_link:hover,^.bcm_chat_selection .bcm_cs_link:active,^.cg_overlay .cg_footer{background:#18181a}
^.ui_floating_tooltip .ft_arrow{fill:rgba(245,245,245,0.8)}
^.mbc_menu{background-color:#121213;border:1px solid #38383c}
^.mbc_menu .mbcm_item{border-bottom:1px solid #38383c}
^.mbc_menu .mbcm_item:active,^.im_conversations .imc_history_box .imch_item.__selected,^.im_conversations .pm_upgraded_membership.__diamond .pmu_holder.__filled,^.im_conversations .pm_upgraded_membership.__diamond .pmu_footer{background:#1b1b1d}
^.ui-body-b,^.ui-overlay-b{color:#e2e2e2;text-shadow:0 1px transparent;background:#18181a;background-image:-moz-linear-gradient(#232325,#2b2b2e);background-image:-ms-linear-gradient(#232325, #2b2b2e);background-image:linear-gradient(#232325,#2b2b2e);border:1px solid #4c4c52}
^.ui-bar-c{color:#d2d2d2;text-shadow:0 1px transparent;background:#1a1a1c;background-image:-moz-linear-gradient(#19191b,#232325);background-image:-ms-linear-gradient(#19191b, #232325);background-image:linear-gradient(#19191b,#232325);border:1px solid #4c4c52}
^.ui-bar-c .ui-link-inherit{color:#d2d2d2}
^.ui-body-c,^.ui-overlay-c{color:#d8d8d8;text-shadow:0 1px transparent;background:#151516;background-image:-moz-linear-gradient(#151516,#1a1a1c);background-image:-ms-linear-gradient(#151516, #1a1a1c);background-image:linear-gradient(#151516,#1a1a1c);border:1px solid #4c4c52}
^.ui-btn-up-c{color:#cecece;background:#141416}
^.ui-btn-hover-c,^#mainbar .li_shadow.ui-btn-active,^.ui-btn-active,^#mainbar .ui-btn-up-c.ui-btn-active,^#mainbar .ui-btn-active.ui-btn-hover-c,^#mainbar .ui-btn-active:focus,^#mainbar .ui-btn-active:active,^#mainbar .ui-btn-active:hover,^#mainbar .ui-btn-active,^#mainbar a.join-btn.ui-btn-active,^#mainbar .ui-btn-up-c.ui-btn-active .btn_ico.ui-link-inherit,^.buy_tokens .processors_btn_disabled{color:#cecece;background:#1c1c1e}
^.ui-btn-down-c{text-shadow:0 1px transparent;color:#cecece;background:#303033}
^.ui-btn-up-c,^.ui-btn-hover-c,^.ui-btn-down-c{background-color:#1c1c1e;color:#cecece !important}
^.ui-btn-active.ui-btn-up-c span.ui-btn-up-c,^.ui-btn-active.ui-btn-up-c a.ui-link-inherit,^.ui-btn-active.ui-btn-up-c,^.ui-btn-active.ui-btn-up-c:visited,^.ui-btn-active.ui-btn-hover-c:hover,^.ui-btn-active.ui-btn-down-c a.ui-link-inherit{background:#1c1c1e;color:#cecece !important}
^.ui-checkbox .ui-btn-up-c,^.choice.ui-btn-up-c,^.ui-listview .ui-btn-up-c,^.ac_settings .ac_delete_link_wrp{color:#cecece;background:#141416;border:1px solid #45454a}
^.ui-collapsible-heading-toggle.ui-btn-up-c{color:#cecece;border:1px solid #45454a;background:#141416 !important}
^.ui-checkbox .ui-btn-hover-c,^.choice.ui-btn-hover-c,^.ui-listview .ui-btn-hover-c,^.ui-collapsible-heading-toggle.ui-btn-hover-c{color:#cecece;background-color:#1c1c1e;border:1px solid #45454a}
^.ui-body-d,^.ui-overlay-d,^#mainbar .bc_social_networks .sn_count,^.aChat,^#admin_chat_popup .admin_info .admin_avatar_wrp,^.loyalty_box,^.buy_tokens_sms_dimoco_package .input_phone,^.buy_tokens_sms_dimoco_package .input_phone.__extended_description .sdp_phone_input,^.buy_tokens .sp_input,^.im_conversations .pm_confirm_email .pmc_form,^.cg_overlay .cg_adj_list .djpl_list{border:1px solid #45454a}
^.ui-btn-up-e:visited,^.ui-btn-up-e a.ui-link-inherit,^.ui-btn-up-e,^.ui-btn-hover-e,^.ui-btn-down-e,^.ui-btn-active.ui-btn-up-e:visited,^.ui-btn-active.ui-btn-hover-e:hover,^.ui-btn-active.ui-btn-down-e a.ui-link-inherit{color:#feb953}
^.ui-icon-alt .ui-icon,^.ui-icon-alt .ui-icon-searchfield:after{background-color:rgba(18,18,19,0.3)}
^.buy_tokens label.selected,^.live_tabs .ui-btn-active.ui-btn-up-c .ui-btn-up-c,^.categories .ui-btn-active.ui-btn-up-c .ui-btn-up-c,^.footer .support_group li.ui-btn-up-c.support_message,^.im_conversations .imc_actions .bcf_selectbox:active,^.im_conversations .imc_actions .mbc_btn.__active,^.im_conversations .imc_actions .mbc_btn:active{background:#141416}
^.form div.ui-input-text input.ui-input-text,^.input_wrapper.__field_password .ui-input-text,^.bcm_input_row .bcm_form_input,^.bcm_input_row .bcm_form_textarea,^.tap_model_popup_container .tip_after_private .radio_list li .custom_price input,^.head_confirm_box .hcb_links .input_wrapper{border:1px solid #4c4c52}
^.what_view{color:#d4d4d4;background-color:#121213;border:1px solid #45454a}
^.what_view .what_view_inner{background-color:#151516}
^.what_view .what_view_corner{background:#121213;border-color:#0000 #0000 #45454a #45454a}
^.translator_settings .mbc_select{border:1px solid #3c3c40}
^.msg_style_panel .preview_content,^.mbc_search_block.__filter .sb_input,^.mbc_search_block.__filter .sb_result{border:1px solid #3f3f43}
^.msg_style_panel .msp_p_item.__selected,^.f_rptfmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description .sdp_phone_input,^.f_rptsmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description .sdp_phone_input{border-color:#3d3d41}
^.bongacams_popup_v2{background-color:#121213;border:1px solid #4c4c52}
^#mainbar,^#mainbar .ui-panel-inner,^body,^.ui-page,^.ui-content,^.ui-panel-content-wrap{background:#121213 !important}
^#mainbar .ui-listview .mc_followers .btn_icon .mc_icon_follower{fill:#d8d8d8;stroke:#d8d8d8}
^#mainbar .ui-li-divider,^.ic_menu_wrp .icm_item,^.buy_tokens_sms_form h3,^.buy_tokens_sms_sale_form h3,^.buy_tokens_wire_form h3,^.cg_overlay .cg_accordion .cga_item,^.cg_overlay .cg_adj_list.__no_btn .pll_item:last-child{border-bottom:1px solid #45454a}
^#mainbar .ui-li{border-color:#3e3e43}
^#mainbar .ui-btn-active,^#mainbar .mainbar-control.__end_position,^#bChat .historyContainer,^.buy_tokens_wire_first h4{border-top:1px solid #45454a}
^#mainbar .ui-btn-active.ui-btn-up-c .ui-link-inherit .mm_icon.__free{border-color:#47474c}
^#mainbar .btn_icon{border-top:1px solid #3e3e43}
^#mainbar .menu_item,^.footer_content .copy a{color:#f5f5f5 !important}
^#mainbar .menu_item.__collapsed,^.bc_header_live_tabs .hlt_link:visited,^.bc_header_live_tabs .hlt_link,^.im_conversations .pm_valentine_day_themed_gift .pmvdtg_text,^.im_conversations .pm_valentine_day_themed_gift .pmvdtg_signature{color:#d8d8d8 !important}
^#mainbar .menu_item .mi_list .mil_sub_item .mm_arrow,^.head_confirm_box .hcb_close_wrp.__bubble .hcb_close_icon{fill:#e17085}
^#mainbar .language-dropdown{background:#121213;border-top:1px solid #45454a}
^#mainbar .language-dropdown .change-lang-btn.__selected,^#mainbar .language-dropdown .change-lang-btn:active,^.im_conversations .pm_upgraded_membership.__sapphire .pmu_holder.__filled,^.im_conversations .pm_upgraded_membership.__sapphire .pmu_footer,^.im_conversations .pm_upgraded_membership.__titan .pmu_holder.__filled,^.im_conversations .pm_upgraded_membership.__titan .pmu_footer,^.im_conversations .pm_upgraded_membership .pmu_holder.__filled,^.im_conversations .pm_upgraded_membership .pmu_footer{background:#19191b}
^.bc_online_notification .ont_close_wrp .ont_close,^.bc_online_notification .ont_info .ont_i_text,^.chat-content .bcm_paid_show_countdown .bcm_psc_text,^.bcm_chat_footer .cf_item,^.bcm_chat_footer .cf_item:hover .cfi_inner,^.buy_tokens .bt_cashback_nft_wrp,^.buy_tokens_sms_dimoco_package .input_phone.__extended_description,^.buy_tokens_sms_dimoco_package .input_phone.__extended_description .sdp_phone_title,^#buy_tokens_sms_confirm_code_form_tele2 .cct_form,^.buy_tokens .sp_label{color:#c4c4c4}
^.bc_confirmer .bcc_alert .caa_button,^.bc_cmn_confirm_wrp .bc_confirm_popup .bcc_actions .bcc_button.__light{color:#cecece;background:#1a1a1c}
^.bc_header_live_tabs .hlt_inner,^.smileButton.ui-btn-hover-e,^.tap_model_popup_container .tip_after_private .form_actions,^.forward_to_remote .ftr_header{background-color:#18181a}
^.holiday_discount_alert.__world_sexual_health_day_2026 .hda_buy{color:#596ef8}
^.bc_ms_icon.__diamond{fill:#f65d5b}
^.bc_ms_icon.__exclusive{fill:#efefef}
^.bc_ms_icon.__sapphire{fill:#9452ff}
^.bc_ms_icon.__white_bg.__diamond{color:#f65d5b}
^.bc_ms_icon.__white_bg.__exclusive{color:#efefef}
^.bc_ms_icon.__white_bg.__sapphire{color:#9452ff}
^.bc_context_menu_list,^.im_conversations .imc_actions .bcf_selectbox .bcsb_dropdown,^.bcsb_dropdown.__in_portal,^.im_conversations .imc_history_box .imch_item.__action_btns .imch_msg_actions{background:#121213;border:1px solid #38383c}
^.bc_context_menu_list .cml_item,^.im_conversations .imc_actions .bcf_selectbox .bcsb_item,^.bcsb_dropdown.__in_portal .bcsb_item{color:#f5f5f5;border-bottom:1px solid #38383c}
^.auto_purchase_form .bcf_control{background:#151516;border:1px solid #4c4c52}
^.bc_dropdown.__reactions .mbcm_item+.mbcm_item{border-left:1px solid #38383c}
^.bcm_radio .bcm_r_input:disabled~.bcm_r_mark{background:#1b1b1d;border-color:#3c3c40}
^.bcm_radio .bcm_r_input:disabled~.bcm_r_mark:before,^.bcm_toggle_switcher_holder .ts_switcher{background:#222225}
^.bcm_radio .bcm_r_mark{background:#252527;border:1px solid #4c4c52}
^.bcm_radio .bcm_r_text,^.mls_item_online.actions a.chat,^.bcm_filter_result .fr_value,^.purchase_vip label.choice.discount .eur-vip s,^.history .service.__group .msgs_desc,^.chat_prompt_wrp .cp_msg.__group_join .cp_msg_s_text,^.chat_prompt_wrp .cp_msg.__group_join .cp_msg_arrow .cp_msg_arrow_icon,^.bcm_chat_selection .bcm_cs_desc,^.bcm_chat_selection .bcm_cs_price,^.buy_tokens_wire_form p,^.buy_tokens_sms_dimoco_form p,^.buy_tokens_digiseller_form p,^#buy_tokens_payment_type .ui-collapsible .package.__simple .brbw_input:disabled~.ui-btn .ui-btn-text,^#buy_tokens_payment_type .bt_radio_btn_wrp.__simple .brbw_input:disabled~.ui-btn .ui-btn-text,^.buy_tokens .choice .ui-btn-inner,^.buy_tokens .choice .foreign_currency,^.buy_tokens .bt_price_old,^.buy_tokens .pkg_cybersale .bt_strike_price,^.buy_tokens .bt_payment_description,^.buy_tokens_sms_dimoco_package .input_phone.__sending .status,^.buy_tokens_sms_dimoco_package .input_phone .sdp_phone_title,^.buy_tokens_sms_dimoco_package .form_note_btn,^.f_rptfmm .buy_tokens_sms_dimoco_package .package+p,^.f_rptsmm .buy_tokens_sms_dimoco_package .package+p,^.f_rptfmm .buy_tokens_sms_dimoco_package .package+p+p,^.f_rptsmm .buy_tokens_sms_dimoco_package .package+p+p,^.buy_tokens .sp_current_package .spcp_approx,^.buy_tokens .bt_custom_amount_field,^.buy_tokens .bt_custom_amount_field .caf_input_custom_field,^.buy_invisible_package .choice_description,^.im_conversations .imc_history_box .imch_item.__translate,^.im_conversations .imc_history_box .imch_item.__action_btns .imch_action_btn,^.cg_overlay .cg_options_list .ol_item.__checked .cgo_radio{color:#bcbcbc}
^.bcm_radio.__background .bcm_r_text{color:#d4d4d4;text-shadow:0 1px transparent}
^.bc_phone_select_box .bcsb_input_wrp{color:#c4c4c4;border:1px solid #444449;background:#161617}
^.bc_phone_select_box .bcsb_input{color:#c4c4c4;background:#121213;border:1px solid #444449}
^.bc_phone_select_box .bcsb_input::placeholder,^.bcm_input_row .bcm_form_input::placeholder,^.bcm_input_row .bcm_form_textarea::placeholder,^.purchase_vip label.choice.discount_gift_card .eur-vip s,^.purchase_vip label.choice.discount .eur-vip s,^.mbc_search_block .sb_input::placeholder,^.im_conversations .imc_search .imcs_icon,^.im_conversations .imc_search .search_input::placeholder,^.imch_reply .imch_r_msg,^.cg_vibe_with_me.__vwm_app .vwm_a_qr_code{color:#b3b3b3}
^.bcm_checkbox_row .cr_mark{background:linear-gradient(#2f2f33,#252528)}
^.bc_social_networks .sn_count{color:#bcbcbc;background:#121213}
^.range_slider .rs_track,^.im_conversations .imc_history_box .imch_date_wrp:before,^.im_conversations .imc_history_box .imch_date_wrp:after,^.cg_vibe_with_me.__vwm_app .vwm_a_qr_icon_wrp.__vwm_active{background:#252527}
^.range_slider .rs_progress.__zero:after{background:#121213;border:1px solid #404045}
^.mls .mls_pager_header{color:#bcbcbc;border-top:1px solid #45454a}
^.bcm_filter_btn_wrp .bcm_fbw_btn{color:#cecece;background:#121213;border:1px solid #3f3f44}
^.bcm_filter_btn_wrp .bcm_fbwb_icon{color:#dadada}
^.mls_tabs_container{background:linear-gradient(#121213,#1a1a1c);border-bottom:1px solid #38383c}
^ul.mls_tabs li{text-shadow:1px -1px transparent;background-color:#19191b;border:1px solid #45454a}
^ul.mls_tabs li:hover,^.phone_confirm_box .confirm_phone_form .bc_phone_select_box.__focused .bcsb_input,^.phone_confirm_box .confirm_phone_form .bc_phone_select_box.__focused .bcsb_input_wrp{border-color:#4c4c52}
^ul.mls_tabs li a,^.im_conversations .pm_offering p{color:#d4d4d4 !important}
^.pager>div{background-image:linear-gradient(#29292c,#222224)}
^.forget_info,^.history p.undefined,^.history p.undefined dfn,^.aChat .message .col1,^.buy_tokens .gray_desc,^.verification_failed p,^.credit_box_success .gray_desc{color:#b2b2b2}
^.live_tabs .tabs_list .tabsl_item.__new .tabsl_count:before{background:linear-gradient(#141416,#141416) padding-box padding-box,linear-gradient(270deg,#ff8201,#fca710) border-box}
^.form .form_errors_row{background-color:#19191b}
^.footer_content{background-color:#222225}
^.footer_content .separator{background-color:#343438;border-top:1px solid #333336}
^.center-wrapper .descr_block{border:1px dashed #4c4c52}
^.icon_membership.icon_free{background:#121213;border:2px solid #47474c}
^.mc_status_icon.__icon_free{background-color:#121213;border:2px solid #47474c}
^.padded.grey,^.padded.stripe,^.buy_tokens_wire_form .odd,^.page_im .im_conversations .imc_action_bar{background-color:#1a1a1c}
^.vip-payment .ui-btn-up-c{border:2px solid #45454a !important}
^.vip-payment .head-vip{background-color:#141415;border-bottom:1px solid #45454a}
^.vip-payment.pkg_cybersale .eur-vip,^.vip-payment.pkg_cybersale .inner-vip .vip-blocks,^.maroon_strong,^.buy_tokens .pkg_cybersale .bt_highlight,^.buy_tokens .pkg_cybersale .foreign_currency,^.buy_tokens .bt_custom_amount_alert .caa_cell.__accent,^.buy_tokens.__holiday .bt_highlight{color:#dd7488}
^.vip-payment .eur-vip{color:#e17085;border-left:1px solid #444449}
^.vip-payment .eur-vip b,^.fancybox-error,^.buy_tokens .mobile_pay_form .rich,^.loyalty_box.speaker,^.loyalty_box.speaker .lb_white,^a{color:#cfcfcf}
^.vip-payment .head-vip b,^.notfound .nt_des,^.notfound p.nf_bottom a,^.notfound p.nf_bottom{color:#b4b4b4}
^.vip-payment .foot-vip{color:#b4b4b4;background-color:#141415;border-top:1px solid #45454a}
^.vip-exist,^.buy_tokens_warning,^.f_rptfmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description,^.f_rptsmm .buy_tokens_sms_dimoco_package .input_phone.__extended_description{border:1px solid #36363a}
^.votes_percent_line,^#bChat .msg_wrp .ch_m_translator_link.__source,^#bChat .msg_wrp .ch_m_translator_link.__translate,^.cg_vibe_with_me.__vwm_app .vwm_a_qr_code_wrp{background:#121213;border:1px solid #45454a}
^.bitcoin_paypal_popup .close_button{color:#f5f5f5;background:#121213}
^.suspect_login_page form,^.vip_overview_page .vo_badge,^.im_conversations .imc_item.__selected .imci_wrap{background:#151516}
^.suspect_login_page .form_error{color:#ff5252;background-color:#19191b}
^#bChat .history p.deleted .msg{color:#b6b6b6 !important}
^#bChatFullScreenHistory p.groupChatWelcome,^.history p.groupChatWelcome{color:#5252ff !important}
^.history .service.__group{background:#141415;border:1px solid #38383c}
^.history p.topicChange{color:#e17085 !important}
^.history p.model .icon_avatar,^.imc_footer_reply .imc_fr_inner{background-color:#161618}
^.smileButton{background-color:#18181a;border:1px solid #3d3d41}
^.smileButton .smile_btn_icon,^.chat-content #bChatInputContainer .smile_btn_icon{stroke:#c4c4c4}
^.smileButton.__active .smile_btn_icon{stroke:#f5f5f5}
^#scroll-chat-btn .inner:after,^.popHint.topLeft:after,^.popHint.topRight:after,^.popHint.topCenter:after{border-top-color:#2b2b2e}
^.chat_prompt_wrp .cp_msg_after{background:linear-gradient(#202023 0%,#fff0 25%)}
^.chat-content .chat_panel_wrap>.bcm_ps_countdown_container .bcm_paid_show_countdown{border-top:1px solid #36363a}
^.chat-content .bcm_paid_show_countdown{background:#18181a;border-bottom:1px solid #36363a}
^.bcm_chat_selection{background:#121213;border:1px solid #3d3d41}
^.bcm_chat_selection .bcm_cs_list_item{border-bottom:1px solid #3d3d41}
^.chat-panel .history .system_msg.tip_success.__tip_menu .msg_clear_btn{border:1px solid #2b2b2e}
^.chat-panel .history .system_msg.follow_plank .fp_container{color:#e6e6e6;background:rgba(27,27,29,0.7)}
^.chat-panel .history .system_msg.msg_activity .ma_avatar_wrp:before{border:1px solid rgba(43,43,46,0.8)}
^.chat-panel .msg_chat_game,^#buy_tokens_payment_type .ui-collapsible .package .ui-btn.selected .ui-btn-inner,^#buy_tokens_payment_type .bt_radio_btn_wrp .ui-btn.selected .ui-btn-inner,^.bt_select_modal .slm_i_input:checked~.slm_i_label{background:#141415}
^.chat-content .cp_navigation .cpnl_item,^.im_conversations .imc_history_box .imch_item_wrp.__highlight:before{background-color:#212124}
^.chat-content #bChatInputContainer{background-color:#121213;border-top:1px solid #323235;border-bottom:1px solid #323235}
^.chat-content #bChatInputContainer .sendInput{color:#c4c4c4;background-color:#18181a}
^.chat-content #bChatInputContainer .sendInput::placeholder,^.chat-content #bChatInputContainer .sendInput.__placeholder:before{color:#c4c4c4 !important}
^.ic_menu_wrp .ic_menu{background:#151516;border:1px solid #45454a}
^#bChat .msg_wrp.__tr_enabled.__tr_show_tooltip{background:#171718}
^#bChat .msg_wrp .ch_m_translator_link.__empty_translate{color:#cecece;background:#171718}
^.chat_user_menu .cum_header{color:#d8d8d8;border-bottom:1px solid #38383c}
^.chat_user_menu .cum_info .mi_content,^.chat_user_menu .cum_action .ma_text{color:#b5b5b5}
^.bc_new_message_separator:before,^.bc_new_message_separator:after{background-color:#262628}
^.bcm_chat_footer{background:#18181a;border-top:1px solid #323235;border-bottom:1px solid #36363a}
^.bcm_chat_footer .cf_balance{color:#c4c4c4;background:#18181a}
^.bcm_chat_invite .bcm_ci_badge_icon,^.bcm_chat_invite .bcm_ci_toggle_icon{fill:rgba(245,245,245,0.2)}
^.video-panel .layover .layoverText .layoverIns,^.ru_buy_tokens_mobile_pay p.provider_attention{color:#c5c5c5}
^.video-panel .layover .layoverLimitText{color:#b2b2b2 !important}
^.layover_before_private .lbp_content{background-color:rgba(18,18,19,0.4)}
^.layover_before_private .lbp_item,^.bc_confirm_popup.fan_boosted_confirm .bcc_container_info{color:#d5d5d5}
^.bcm_oops_popup_layover .opl_message{color:#d8d8d8;background:#161618}
^.quality_settings_block .qsb_item.__active{background-color:rgba(18,18,19,0.2)}
^.cam2cam_modal{border:2px solid #444449}
^.tap_model_popup_container .tip_after_private .tap_title .tap_model_name{color:#dc748a}
^.tap_model_popup_container .tip_after_private .radio_list li{background-color:#121213;border:1px solid #45454a}
^.tap_model_popup_container .tip_after_private .radio_list li.selected{background:#131315}
^.tap_model_popup_container .tip_after_private .radio_list li .custom_price input:disabled{background-color:#121213;border-color:#3c3c41}
^.tap_model_popup_container .tip_after_private .radio_list li .radio_help{color:#a1a3b0}
^.tap_model_popup_container .tip_after_private .form_actions .tap_note{color:#e3e3e3}
^.tap_model_popup_container .tip_after_private .form_actions .tap_note .tap_red{color:#dc758a}
^.tap_model_popup_container .tip_after_private .form_error_list{color:#dc758a;background-color:#18181a}
^.fan_boosted_animation.__stopping .fba_timer{stroke:#ff527b}
^.bc_confirm_popup.fan_boosted_confirm .bcc_header .bcc_title{color:#f4f4f4}
^.fancybox-skin{color:#cfcfcf;background:#151516}
^.head_confirm_box{background-color:#131315}
^.head_confirm_box .hcb_close_wrp:hover .hcb_close{color:#e46d89}
^.head_confirm_box .hcb_close_wrp.__bubble:hover .hcb_close_icon{fill:#e46d89}
^.phone_confirm_box .fcb_not_show .ns_mark{border:2px solid #4c4c52}
^.phone_confirm_box .confirm_phone_form{color:#c9c9c9}
^.phone_confirm_box .confirm_phone_form .cpf_code .bcf_control{color:#cfcfcf;background:#121213;border:1px solid #4c4c52}
^.promo_in_banner_popup .pibp_name{color:#e17084 !important}
^#admin_chat_popup .admin_info .details h4{border-bottom:1px solid #4c4c52}
^.buy_tokens .bt_email_wrp,^.buy_tokens .sp_form{color:#c4c4c4;border:1px solid #414146}
^.buy_tokens .btc_input_warning{color:#f65a61}
^.buy_tokens .limit_alert,^.buy_tokens .buy_tokens_mbway_form .bt_input_wrp .err,^.buy_tokens .buy_tokens_wasabigate_form .bt_input_wrp .err,^.buy_tokens .buy_tokens_hkpay_form .bt_input_wrp .err,^.buy_tokens .coinpayments_form .bt_input_wrp .err.err_show,^.buy_tokens .mobile_pay_form .bt_input_wrp .err.err_show,^.buy_tokens .bt_custom_amount_field .caf_input_warning{color:#ff5272}
^.buy_vip_sms_form .price span,^.buy_vip_sms_form .price em,^.ru_buy_tokens_sms_pay .heading h4,^.ru_buy_tokens_mobile_pay .heading h4,^.ru_buy_tokens_sms_pay ul a{color:#db7688}
^.buy_tokens .mobile_pay_form input,^.confirm_code_form input{border:1px solid #45454a;border-color:#4c4c52 #45454a #45454a #4c4c52}
^.buy_tokens .mobile_pay_form input.disabled{color:#bcbcbc;background-color:#1a1a1c}
^.confirm_code_form{color:#bcbcbc;border:1px solid #45454a}
^table.wire-tab td{color:#f5f5f5;border:1px solid #45454a}
^.buy_tokens .foreign_currency span{color:#5297ff}
^.verify_info_box p,^.confirm_box{color:#d9d9d9}
^.confirm_box .example_box .ex{background-color:#121213;border:1px solid #3e3e43}
^.confirm_box .example_box .ex .amount span,^.confirm_box .example_box .info{color:#e86969}
^#buy_tokens_payment_type .ui-collapsible .package .ui-btn:after,^#buy_tokens_payment_type .bt_radio_btn_wrp .ui-btn:after,^.buy_tokens .bt_select_change:after{border:1px solid #414146}
^#buy_tokens_payment_type .payment_icon,^.bt_select_modal .payment_icon{background:#121213;border:1px solid #3e3e42}
^.buy_tokens .choice.discount_box,^.buy_tokens label.choice.discount_box,^.buy_tokens .sp_current_package{color:#bcbcbc;background:#131315;border:1px solid #45454a}
^.buy_tokens .sms_amount_error,^.buy_tokens .bitcoin_form .bitcoin_error,^.buy_tokens .bitcoin_form .info_text{color:#f25e5e}
^.buy_tokens .discount_box .original_sum,^.buy_tokens label.discount_box .original_sum,^.show_hide_packages{color:#b9b9b9}
^.gift_card_section .gift_card_box{background:#141416;border:1px solid #45454a}
^.buy_tokens .ui-radio label{background-color:#141416 !important}
^.buy_tokens .pkg_cybersale .ui-radio label,^.buy_tokens .bt_select_change{color:#bcbcbc !important}
^.buy_tokens_redirect .btr_text.__wait,^.buy_tokens_header_board .hbt_paragraph,^.im_conversations .imc_actions .imca_text.__new_msg,^.im_conversations .imc_empty .imce_text,^.im_conversations .imci_message,^.im_typing{color:#bababa}
^.loyalty_box.speaker:before{border-top:5px solid #2b2b2e}
^.loyalty_box.speaker:after{border-top:6px solid #45454a}
^.loyalty_box.bit{color:#cbcbcb;background:#141416}
^.loyalty_box.bit .lb_title{color:#eaeaea}
^.loyalty_box.bit .lb_green{color:#92ff52}
^.loyalty_box.bit .lb_warn:before{border-top:1px solid #3a3a3e}
^.loyalty_box.leaving .lb_warn:before,^.loyalty_box.leaving .lb_warn:after{background:#2b2b2e}
^.buy_tokens .confirm_code_form_resend{background:#131315;border:1px solid #45454a}
^.buy_tokens_header_board .hbt_headline_block,^.cg_service_list .cg_sub_header{border-bottom:1px solid #333336}
^.buy_tokens_header_board .hbt_headline{color:#e8e8e8}
^.buy_tokens .bt_custom_amount_alert{color:#bcbcbc;background:#131315;border:1px solid #414146}
^.buy_tokens .bt_custom_amount_field .caf_input_currency{color:#bcbcbc;background:#141415}
^.show_hide_packages .sh_label .sh_icon{color:#c5c5c5;background:#141416;border:1px solid #45454a}
^.buy_tokens .bt_anim_icon_success .ais_item:after{border:6px solid #2b2b2e}
^.bt_select_modal{background:#121213;border:1px solid #404044}
^.bt_select_modal .slm_i_label{background:#121213;color:#bcbcbc !important}
^#discount_green_purple .dgp_clock_hand{color:#c58bb5}
^.gc_popup{color:#9d78d8;background:#121213}
^.gc_popup .gc_title .gc_red{color:#e07185}
^#gc_popup_vip .gc_title .gc_red,^.ac_change_photo .ac_cp_desc.__error{color:#e36e84}
^.gc_popup.gc_popup_hor .gc_title{color:#9d78d8}
^.fancybox-item.fancybox-close.pl_un_default_close,^.fancybox-item.fancybox-close.di_ex_close{color:#f5f5f5;background:#121213 !important}
^.mbc_search_block.__filter .sb_result .sbr_head.__recent{border-bottom:1px solid #3f3f43}
^.mbc_search_block .sb_result .sbr_count{color:#c2c2c2}
^body{color:#cfcfcf;background:#242426}
^.popHint .popHintFooter{background:#141416;border-top:1px solid #3c3c41}
^.popHint.bottomLeft:after,^.popHint.bottomRight:after,^.popHint.bottomCenter:after{border-bottom-color:#2b2b2e}
^.popHint.leftTop:after,^.popHint.leftBottom:after,^.popHint.leftCenter:after{border-left-color:#2b2b2e}
^.popHint.rightTop:after,^.popHint.rightBottom:after,^.popHint.rightCenter:after{border-right-color:#2b2b2e}
^#bChat.bChatModel .popHint:after{border-top-color:#2f2f33}
^.profile_avatar_popup .account_actions,^.account_actions{background-color:#141415;border-top:1px solid #49494e}
^.profile_avatar_popup .account_actions .mbc_btn.ac_a_btn_cancel:active,^.account_actions .mbc_btn.ac_a_btn_cancel:active{background-color:#323235}
^.account_preview .acp_img_wrp{border:2px solid #2b2b2e}
^.account_preview .acp_btn{color:#cecece;text-shadow:0 1px transparent;background:#252527}
^.ac_change_photo .ac_cp_line{background-color:#2b2b2e}
^.vip_overview_page,^.vip_overview_page .vo_ttl{color:#c3c3c3}
^.page_content .cancel_subscription.__dashed{border:1px dashed #45454a}
^.vip_overview_page_badge{color:#c3c3c3;background:#151516}
^.vip_overview_stock_page{color:#e0e0e0;border:1px solid #313134}
^.vip_overview_stock_page .sp_privilege{border-top:1px solid #37373a}
^.invisible_mode_overview_plank{color:#9099c1;background:#151516}
^.page_im .im_conversations,^.smilePanelTabs{background:#1a1a1c}
^.im_conversations .imc_actions .bcf_selectbox,^.im_conversations .gift_card_promo_wrapper{background:#121213;border:1px solid #3e3e43}
^.im_conversations .imc_actions .mbc_btn.__btn_msg.__disabled{background:#2e2e31}
^.im_conversations .imc_actions .imca_icon{color:#d6d6d6;fill:#d6d6d6}
^.im_conversations .imc_item.__new .imci_wrap .imci_message,^.im_conversations .imci_user_name,^.im_conversations .imc_followers .imcf_name{color:#d7d7d7}
^.im_conversations .mbc_alert.__tip,^.im_conversations .imc_history_box .imch_group.__own .imch_item.__tip,^.im_conversations .pm_upgraded_membership.__unlimited .pmu_footer{background:#171719}
^.im_conversations .imc_history_box .imch_msg_check.__unsent .imch_mc_icon,^.im_conversations .imc_search .imcs_reset .imcs_r_icon{fill:#e36d84}
^.im_conversations .imc_history_box .imch_group.__own .imch_item,^.pm_activation_2fa .pmaf_body,^.im_conversations .pm_upgraded_membership.__exclusive .pmu_holder.__filled{background:#161618}
^.im_conversations .imc_history_box .imch_group.__own .imch_item:first-of-type:after{border-left:6px solid #303033}
^.im_conversations .imc_history_box .imch_group.__own .imch_item.__tip:first-of-type:after{border-left-color:#313134}
^.im_conversations .imc_history_box .imch_item{background:#151517}
^.im_conversations .imc_history_box .imch_item:first-of-type:after{border-right:6px solid #2f2f32}
^.im_conversations .imc_history_box .imch_item.__selected:first-of-type:after{border-right-color:#353538}
^.im_conversations .imc_history_box .imch_item.__sq .imc_question_link,^.im_conversations .imch_item.__default a{color:#52b0ff}
^.im_conversations .imc_history_box .imch_item.__sq_error{color:#e17085;background:#171719}
^.im_conversations .imc_history_box .imch_item.__sq_error:first-of-type:after{border-right-color:#313134}
^.im_conversations .imc_history_box .imch_item.__action_btns .imch_action_btn.__active{background:#202022}
^.im_conversations .imc_history_box .imch_context_menu,^.cg_service_list .cg_sl_price{border:1px solid #38383c}
^.im_conversations .imc_history_box .imch_context_menu .imch_cm_btn{color:#f5f5f5;background:#121213;border-bottom:1px solid #38383c}
^.im_conversations .imc_history_box .mbc_btn.__fab{background:#121213;border-color:#38383c}
^.im_conversations .imc_search .search_input{color:#d6d6d6;background:#1b1b1d;border:1px solid #47474c}
^.imc_footer_reply{color:#d8d8d8;background:#121213;border-top:1px solid #3d3d41}
^.imc_tip_before_start .tbs_content{background:#121213;border:2px dashed rgba(74,74,79,0.5)}
^.im_conversations .imch_contact_card{border:2px dashed #4a4a4f}
^.im_typing .imt_dots .imtd_item{background:#3d3d41}
^.pm_activation_2fa .pmaf_title{color:#cacaca}
^.pm_activation_2fa .pmaf_info_wrp{border-top:1px solid #37373b}
^.pm_activation_2fa .pmaf_info{color:#e7e7e7}
^.pm_activation_2fa .pmaf_a_text{color:#c6c6c6}
^.pm_activation_2fa .pmaf_footer{background:#1e1e20}
^.im_conversations .pm_upgraded_membership{color:#f5f5f5;background:#121213;border:2px solid #333336}
^.im_conversations .pm_upgraded_membership.__platinum{border-color:#37373b}
^.im_conversations .pm_upgraded_membership.__platinum .pmu_holder.__filled,^.im_conversations .pm_upgraded_membership.__platinum .pmu_footer,^.im_conversations .pm_upgraded_membership.__unlimited .pmu_holder.__filled,^.cg_overlay .gc_btn.__white:active{background:#1d1d1f}
^.im_conversations .pm_upgraded_membership.__unlimited{border-color:#313134}
^.im_conversations .pm_upgraded_membership.__sapphire,^.im_conversations .pm_upgraded_membership.__titan{border-color:#323236}
^.im_conversations .pm_upgraded_membership.__sapphire .pmu_highlight{color:#8b52ff}
^.im_conversations .pm_upgraded_membership.__diamond{border-color:#343438}
^.im_conversations .pm_upgraded_membership.__diamond .pmu_highlight{color:#ff527b}
^.im_conversations .pm_upgraded_membership.__exclusive{border-color:#303033}
^.im_conversations .pm_upgraded_membership .pmu_updated_status,^.im_conversations .pm_upgraded_membership .pmu_current_status{color:#94a2bc}
^.im_conversations .gift_card_promo_wrapper .gift_card_promo .gift_card_promo_code_wrapper{color:#a079d8}
^.im_conversations .gift_card_promo_wrapper .gift_card_promo .gift_card_promo_code_wrapper p span{color:#e17087}
^.im_conversations .gift_card_promo_wrapper .gift_card_promo .gift_card_promo_code_wrapper .gift_card_promo_code_ribbon_left:before{border-left:10px solid #2b2b2e}
^.im_conversations .gift_card_promo_wrapper .gift_card_promo .gift_card_promo_code_wrapper .gift_card_promo_code_ribbon_right:before{border-right:10px solid #2b2b2e}
^.im_conversations .pm_offering .pmo_bonus{color:#e26f85}
^.im_conversations .pm_downgrade_membership{border:2px solid #303033}
^.im_conversations .pm_downgrade_membership .dmh_content .hc_status{color:#91afbf;background-color:#121213}
^.im_conversations .pm_downgrade_membership .dm_title .dmt_username,^.im_conversations .pm_downgrade_membership .dm_title .dmt_desc{color:#949dbc}
^.im_conversations .pm_downgrade_membership .dm_title .dmt_desc .td_accent{color:#e76978}
^.im_conversations .pm_valentine_day_themed_gift .pmvdtg_card{background:#121213;border:1px solid #3c3c41}
^.smilePanelTabs:before{background:linear-gradient(#29292c,#efefef00)}
^.cg_overlay .cg_options_list .ol_item.__checked{border-color:#3f3f44}
^.cg_overlay .gc_btn{color:#cecece;border:1px solid #3f3f44}
^.cg_overlay .gc_btn.__gray{background:linear-gradient(#151516,#1a1a1c)}
^.cg_overlay .gc_btn.__gray:active{background:#323235}
^.cg_overlay .gc_btn.__disabled{background:#121213;border:1px solid #3f3f44}
^.cg_overlay .cg_prize_list .li_text,^.cg_overlay .cg_prize_list.__wheel .li_text,^.bc_token_keno_field .tkf_cube .fc_body .fc_number{color:#bd9494}
^.cg_overlay .cg_input_wrp .cgi_input_amount{color:#d8d8d8;background:#151516;border:1px solid #4c4c52}
^.cg_overlay .cg_accordion .cga_item:active{background-color:#1d1d1f}
^.cg_overlay .cg_adj_empty_playlist{background-color:#131315;border:1px solid #45454a}
^.cg_overlay .cg_adj_form .djf_link{color:#f5f5f5;border:1px solid #3c3c40}
^.cg_overlay .cg_adj_form .djf_premium.__checked{background-color:#141415}
^.cg_auto_dj_box .adjb_icon,^.cg_overlay .cg_prize_list.__slot .pli_icon_wrp .iw_icon,^.cg_slm_slot .slms_item.__active .slms_icon{fill:#bd9494}
^.cg_overlay .cg_adj_icon_premium .ip_icon{fill:#cfcfcf}
^.cg_overlay .cg_adj_list .pll_item{color:#c1c1c1;background-color:#131315;border-bottom:1px solid #45454a}
^.cg_overlay .cg_game_field .sm_body{background-image:linear-gradient(#1b1b1c 0%,#232326 100%)}
^.cg_overlay .cg_game_field .si_item:after{background:#212123}
^.cg_overlay .cg_game_field .si_item .sii_icon{fill:#f5f5f5}
^.cg_vibe_with_me.__vwm_app .vwm_a_list{color:#f5f5f5;background:#171719}
^.cg_vibe_with_me.__vwm_app .vwm_ai_container:before{background:rgba(43,43,46,0.5)}
^.cg_service_list .cg_sl_item{color:#d8d8d8;border-bottom:1px solid #2e2e31}
@media (any-hover:hover) and (pointer:fine){^.mbc_menu .mbcm_item:hover,^.cg_overlay .gc_btn.__white:hover,^.cg_overlay .gc_btn.__gray:hover{background:#1b1b1d}
^.profile_avatar_popup .account_actions .mbc_btn.ac_a_btn_cancel:hover,^.account_actions .mbc_btn.ac_a_btn_cancel:hover{background-color:#1b1b1d}
^.im_conversations .imc_actions .bcf_selectbox:hover{background:#141416}
^.im_conversations .imc_actions .mbc_btn.__btn_msg:hover .imca_text.__new_msg{color:#d6d6d6}}
@media screen and (max-width:480px){^.vip-payment .inner-vip .vip-blocks .cont-vip{border-bottom:1px solid #45454a}}
@media (max-width:40em){^.notfound p{color:#d8d8d8}}
@media (min-width:46em){^.aChat .message .col1{color:#b2b2b2}}
@media (max-width:780px){^.im_conversations .pm_upgraded_membership.__gold .pmup_icon,^.im_conversations .pm_upgraded_membership.__sapphire .pmup_icon,^.im_conversations .pm_upgraded_membership.__titan .pmup_icon{background-color:#19191b}
^.im_conversations .pm_upgraded_membership.__platinum .pmup_icon{background-color:#1d1d1f}
^.im_conversations .pm_upgraded_membership.__unlimited .pmup_icon{background-color:#171719}
^.im_conversations .pm_upgraded_membership.__diamond .pmup_icon{background-color:#1b1b1d}
^.im_conversations .pm_upgraded_membership.__exclusive .pmup_icon{background-color:#161618}}`.replaceAll('^', '.bc-dark-m ');
const DARK_FIX_CSS = () => `^.bc_fade_scroll:before,^.bc_fade_scroll:after,^.bc_fade_scroll.__listing_tags:before,^.bc_fade_scroll.__listing_tags:after{background:linear-gradient(90deg, #121216, rgba(18,18,22,0))!important}
^.mls_hash_tag{--bc-thm-hashTag-shadow-bg:#121216;--bc-thm-hashTag-shadow-bg-alpha0:rgba(18,18,22,0);--bc-thm-hashTag-viewAllLink-wrp-bg:#121216}
^.bc_notice{--bc-thm-notice-color:#e6e6e6;--bc-thm-notice-bg:linear-gradient(#121213, #121213);--bc-thm-notice-borderColor:linear-gradient(180deg, #3a3a3f, #3a3a3f);--bc-thm-notice-close-iconColor-hover:#dedede;--bc-thm-notice-link-color:#46c2ff;--bc-thm-notice_secondary-paragraph-color:#d8d8d8;--bc-thm-notice_countdownGoal-bg:#18181c;--bc-thm-notice_countdownGoal-borderColor:#8a28eb80;--bc-thm-notice_follow-borderColor:linear-gradient(90deg, #31c4ee, #20b8e3);--bc-thm-notice_pin-borderColor:linear-gradient(90deg, #e75ec9, #d331b0);--bc-thm-notice_love-borderColor:linear-gradient(90deg, #fe4668, #fe254d)}
^.bc_notice.__countdown_goal,^.bc_notice .nt_message{background-color:#18181c;color:#e6e6e6}
^.bc_notice .nt_message,^.bc_notice .nt_message p,^.bc_notice .nt_message span:not(.nt_accent){color:#e6e6e6}
^.chat-tab,^.chat-panel,^.history,^#bChat{--bc-thm-sysMsg_game-resultWrp-bg:#18181c;--bc-thm-sysMsg_game-label-color:#e6e6e6;--bc-thm-sysMsg_game-content-color:#ee5b78;--bc-thm-sysMsg_game-time-color:#a0a0a8;--bc-thm-sysMsg_topicChange-color:#ee5b78;--bc-thm-sysMsg_modelNote-color:#5fd97f;--bc-thm-sysMsg_serviceGroup-bg:#18181c;--bc-thm-sysMsg_serviceGroup-borderColor:#2b2b2e;--bc-thm-sysMsg_serviceGroup-boxShadowColor:#0000;--bc-thm-sysMsg_serviceGroup-boxShadowColor-inset:#2b2b2e;--bc-thm-sysMsg_serviceGroup-desc-color:#bcbcbc;--bc-thm-sysMsg_serviceGroup-title-color:#5fd97f;--bc-thm-sysMsg_friend-bg:#18181c;--bc-thm-sysMsg_friend-borderColor:#3a3a3f;--bc-thm-sysMsg_friend-color:#e6e6e6;--bc-thm-sysMsg_activity-color:#d8d8d8;--bc-thm-sysMsg_activity-matAccent_member-color:#f5f5f5;--bc-thm-sysMsg_service-bg:#2b2b2e;--bc-thm-sysMsg-serviceList-bg:#18181c;--bc-thm-sysMsg-serviceList-authorName-color:#e6e6e6;--bc-thm-sysMsg-serviceList-title-color:#f5f5f5;--bc-thm-sysMsg-serviceList-services-item-title-color:#e6e6e6;--bc-thm-sysMsg-serviceList-services-item-borderColor:#ffffff1f;--bc-thm-sysMsg-serviceList-services-item-bg-hover:#24242a;--bc-thm-sysMsg-serviceList-showBtn-bg-hover:#24242a;--bc-thm-sysMsg-serviceList-showBtn-color-hover:#fff;--bc-thm-game-autoDJ-title-color:#f5f5f5}
^.history .msg_chat_game .cg_msg_wrp,^.history .system_msg.msg_chat_game{background:#18181c!important}
^.history .msg_chat_game .cg_content,^.history .msg_chat_game .gc_msg_label,^.history .msg_chat_game .cg_msg_s_time{background:transparent}
^.history .msg_chat_game .gc_msg_label,^.history .msg_chat_game .gc_msg_label *{color:#e6e6e6}
^.history .msg_chat_game .cg_msg_s_time{color:#a0a0a8}
^.history .msg_chat_game .mbc_btn,^.history .msg_chat_game .bc_btn,^.history .msg_chat_game button,^.history .msg_chat_game a[class*="btn"]{color:#e6e6e6!important;background:transparent!important;border-color:#4c4c52!important}
^.chat_control_panel,^.send-input-container_wrap,^.ccp_inner,^#chat_control_panel{background-color:#121213!important;border-color:#2b2b2e!important;box-shadow:none!important}
^.chat_control_panel:before,^.chat_control_panel:after,^.ccp_inner:before,^.ccp_inner:after,^#bChatInputContainer:before,^#bChatInputContainer:after{border-color:#2b2b2e!important}
^.bc_fade_scroll{--fadeScroll-fade-bg:linear-gradient(90deg, #121216, rgba(18,18,22,0))}
^.bcm_nav_panel,^.bcm_nav_panel.ui-bar-c,^.bcm_nav_panel.ui-footer,^.bcm_nav_panel .np_inner,^.bcm_nav_panel .np_block{background:#18181a!important;background-image:none!important;border-color:#2b2b2e!important}
^.bcm_nav_panel .np_item{color:#d8d8d8!important;background:transparent!important}
^.bcm_nav_panel .np_item.__active,^.bcm_nav_panel .np_item:active{color:#e36e84!important}
^.bc_fade_scroll.__listing_tags{--fadeScroll-fade-bg:linear-gradient(90deg, #121216, rgba(18,18,22,0))}
^.profile_info_lg{--profileInfo-color:#e6e6e6;--profileInfo-base-accentTitle-color:#ee5b78;--profileInfo-section-bg:#1b1b1f;--profileInfo-detailsWrp-bg:#27272c;--profileInfo-detailsMore-color:#e6e6e6;--profileInfo-flag-borderColor:#3a3a3f;--profileInfo-shelf-broderColor:#3a3a3f;--profileInfo-shelf-badge-bg:#27272c;--profileInfo-section_shedule-text_highlight-color:#ee5b78;--profileInfo-qoqContests-chat-bg:#1b1b1f;--profileInfo-qoqContests-title-color:#ee5b78;--profileInfo-qoqContests-text-color:#e6e6e6;--profileInfo-gifts-emptyHead-imgWrp-bg:#27272c;--profileInfo-gifts-emptyHead-imgWrp-borderColor:#3a3a3f;--profileInfo-comments-content-bg:#27272c;--profileInfo-comments-content-text-color:#e6e6e6;--profileInfo-comments-btn-color:#e6e6e6;--profileInfo-comments-btn-bg:#27272c;--profileInfo-section_tags-stlItem-color:#e6e6e6;--profileInfo-section_tags-stlItem-bg:#27272c;--profileInfo_section_wish-listItem-bg:#27272c;--profileInfo-listWrp-bg:#27272c;--profileInfo-listItem-bg:#1b1b1f;--profileInfo-listItemCaption-color:#9a9aa2;--profileInfo-listItemHighlight-color:#e6e6e6}`.replaceAll('^', '.bc-dark-m ');

const DARK_ALL_CSS = () => `^.bc_notice,^.bc_notice.__countdown_goal,^.bc_notice.__primary,^.bc_notice.__secondary{--bcm-notice-color:#e6e6e6;--bcm-notice-bg:linear-gradient(#121213, #121213);--bcm-notice-borderColor:linear-gradient(#2e2e33, #2e2e33);--bcm-notice-link-color:#46c2ff;--bcm-notice-close-iconColor:#a0a0a8;--bcm-notice_countdownGoal-bg:linear-gradient(#121213, #121213);--bcm-notice_countdownGoal-borderColor:linear-gradient(#2e2e33, #2e2e33);--bcm-notice_membershipError-bg:linear-gradient(#121213, #121213);--bcm-notice_membershipError-borderColor:linear-gradient(#2e2e33, #2e2e33);--bcm-notice_notEnoughtTokens-bg:linear-gradient(#121213, #121213);--bc-thm-notice_topic-bg:#18181c;--bc-thm-notice_topic-color:#ee5b78;--bc-thm-notice_attention-bg:#1d1828;--bc-thm-notice_attention-color:#c291f2}
^.bc_notice.__countdown_goal,^.bc_notice.__primary{background:linear-gradient(#121213, #121213) padding-box, linear-gradient(#2e2e33, #2e2e33) border-box!important;border-color:transparent!important;box-shadow:none!important}
^.bc_notice.__countdown_goal .nt_message,^.bc_notice.__countdown_goal .nt_message *:not(.nt_accent):not(.nt_tip_btn){color:#e6e6e6}
^.mls_hash_tag{--mlsHashTag-tag-color:#e6e6e6;--mlsHashTag-tag-bg:#26262b;--mlsHashTag-tag-bg-active:#34343a;--mlsHashTag-tag_record-icon-color:#a0a0a8;--mlsHashTag-viewAllLink-color:#46c2ff;--mlsHashTag-removeFilterLink-close-iconColor:#c4c4c4}
^.mls_hash_tag .ht_item,^.mls_hash_tag .ht_item.ui-link{background:#26262b!important;color:#e6e6e6!important}
^.mls_tag_badge{--bcm-listing-tagBadge-bg:#26262b;--bcm-listing-tagBadge-borderColor:#3a3a3f;--bcm-listing-tagBadge-color:#e6e6e6;--bcm-listing-tagBadge-button-bg:#4c4c52;--bcm-listing-tagBadge-button-iconColor:#fff}
^.bcm_popup,^.filter_popup,^.search_popup,^.mbc_search_block{--bcm-popup-body-bg-color:#121213;--bcm-popup-filter-main-bg:#121213;--bcm-popup-filter-features-title-color:#c1c1c1;--bcm-popup-filter-footer-borderColor:#2e2e33;--bcm-popup-filter-notice-color:#c1c1c1;--bcm-popup-filter-button-outline-color:#d8d8d8;--bcm-popup-filter-button-outline-color-active:#fff;--bcm-popup-filter-button-outline-bg:#1b1b1f;--bcm-popup-filter-button-outline-borderColor:#3e3e43;--bcm-popup-search-header-bg-color:#18181a;--bcm-search-block-input-bg-color:#1b1b1f;--bcm-search-block-input-borderColor:#3e3e43;--bcm-search-block-input-placeholder-color:#8e8e96;--bcm-search-block-header-close-icon-color:#d8d8d8;--bcm-search-block-reset-button-bg-color:#26262b;--bcm-search-block-reset-button-border-color:#3e3e43;--bcm-search-block-result-name-color:#e6e6e6;--bcm-search-block-result-border-color:#2b2b2e;--bcm-search-block-result-tag-color:#e6e6e6;--bcm-search-block-result-tag-name-bg-color:#26262b}
^.bcm_popup .bcm_popup_body,^.bcm_popup .bp_body,^.filter_popup .fp_main,^.filter_popup .fp_body,^.filter_popup .fp_footer,^.filter_popup .fp_content,^.search_popup .sp_body,^.mbc_search_block{background-color:#121213!important;color:#d8d8d8}
^.bcm_range{--bcm-range-values-color:#bcbcbc;--bcm-range-track-bg-color:#2b2b2e;--bcm-range-handle-bg-color:#d8d8d8;--bcm-range-handle-border-color:#4c4c52}
^.bcm_accordion{--bcm-accordion-box-shadow-color:#2b2b2e;--bcm-accordion-title-color:#bcbcbc;--bcm-accordion-arrow-fill:#d8d8d8}
^.bcm_form_alert{--bcm-form-alert-error-bg-color:#2a1a1d;--bcm-form-alert-error-color:#ff7a85;--bcm-form-alert-success-bg-color:#173320;--bcm-form-alert-success-color:#b6f0c4}
^.bcm_switcher{--bcm-switcher-bg:#3a3a3f}
^.bcm_socials{--bcm-thm-socials-counter-color:#bcbcbc;--bcm-thm-socials-counter-bg:#18181c;--bcm-thm-socials-counter-borderColor:#3a3a3f}
^.bcm_footer{--bcm-thm-footer-bg:#18181a;--bcm-thm-footer-borderColor:#2b2b2e;--bcm-thm-footer-details-color:#d8d8d8;--bcm-thm-footer-details-nav-link-color:#d8d8d8;--bcm-thm-footer-details-nav-link-bg-active:#26262b;--bcm-thm-copyright-bg:#121213;--bcm-thm-copyright-color:#bcbcbc}
^.bcm_chat_footer{--bcm-chat-footer-item-border-color:#2b2b2e}
^.bcm_history_scroll_up{--bcm-historyScrollUp-bg:#26262b}
^.bcm_chat_auto_message{--bcm-chat-member-notification-borderColor:#3a3a3f;--bcm-chat-member-notification-title-color:#e6e6e6}
^input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=button]):not([type=submit]):not([type=reset]):not([type=file]):not([type=color]):not([type=image]):not([type=hidden]),^textarea,^.mbc_search_block .sb_input{color:#f0f0f0!important;-webkit-text-fill-color:#f0f0f0!important;caret-color:#f0f0f0!important}`.replaceAll('^', '.bc-dark-m ');
const DARK_OPAQUE_CSS = '.panel,.bm-modal{background:rgb(18,18,22)!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important}';
const syncOpaque = on => {
    const sr = document.getElementById('bc-unchained-host')?.shadowRoot;
    const st = sr?.getElementById('bc-dark-opaque');
    if (!sr || on === !!st) return;
    if (st) return st.remove();
    const e = document.createElement('style');
    e.id = 'bc-dark-opaque';
    e.textContent = DARK_OPAQUE_CSS;
    sr.appendChild(e);
};
const setCls = (el, c, on) => { if (el.classList.contains(c) !== on) el.classList.toggle(c, on); };
const addStyle = (id, css, root) => {
    if (document.getElementById(id)) return;
    const st = document.createElement('style');
    st.id = id;
    st.textContent = typeof css === 'function' ? css() : css;
    (document.head || root).appendChild(st);
};
const darkBcDesktop = (b, on) => {
    const cl = b.classList;
    if (on) {
        if (b.dataset.bcTheme === undefined && !cl.contains('theme_dark')) b.dataset.bcTheme = cl.contains('theme_light') ? '1' : '0';
        setCls(b, 'theme_light', false);
        setCls(b, 'theme_dark', true);
    } else if (b.dataset.bcTheme !== undefined) {
        const wasLight = b.dataset.bcTheme === '1';
        delete b.dataset.bcTheme;
        setCls(b, 'theme_dark', false);
        if (wasLight) setCls(b, 'theme_light', true);
    }
};
const isOwnNode = n => n.nodeType === 1 && (n.classList.contains('bcu-star') || n.classList.contains('bcu-ring'));
const onlyOwnNodes = recs => {
    for (const r of recs) {
        if (r.type !== 'childList') return false;
        for (const n of r.addedNodes) if (!isOwnNode(n)) return false;
        for (const n of r.removedNodes) if (!isOwnNode(n)) return false;
    }
    return true;
};
const DarkSweep = (() => {
    const SKIP = '.video-panel-wrap,video,canvas,svg,img,#bc-unchained-host';
    const INK = '#e6e6e6';
    const BORDERS = [['Top', 0.55], ['Bottom', 0.55], ['Left', 0.75], ['Right', 0.75]];
    let on = false, mo = null, tm = 0, seen = new WeakSet();
    const touched = [];
    let touchedCap = 4000;
    const pruneTouched = () => {
        const live = touched.filter(r => r.deref());
        touched.length = 0;
        for (const r of live) touched.push(r);
        touchedCap = Math.max(4000, live.length * 2);
    };
    const rgba = s => s.match(/[\d.]+/g)?.map(Number) ?? null;
    const solid = (c, a) => !!c && (c.length < 4 || c[3] > a);
    const lumOf = c => (0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]) / 255;
    const spread = c => Math.max(c[0], c[1], c[2]) - Math.min(c[0], c[1], c[2]);
    const darkInk = c => solid(c, 0.3) && lumOf(c) < 0.33;
    const styleOf = el => { try { return getComputedStyle(el); } catch { return null; } };
    const put = (el, prop, val) => {
        if (!el.__bcdm) {
            el.__bcdm = {};
            touched.push(new WeakRef(el));
            if (touched.length > touchedCap) pruneTouched();
        }
        if (!(prop in el.__bcdm)) el.__bcdm[prop] = el.style.getPropertyValue(prop);
        el.style.setProperty(prop, val, 'important');
    };
    const fixSvg = el => {
        const cs = styleOf(el);
        if (!cs) return;
        if (darkInk(rgba(cs.color))) put(el, 'color', INK);
        for (const k of ['fill', 'stroke']) {
            const v = cs[k];
            if (v && v !== 'none' && !v.startsWith('url') && darkInk(rgba(v))) put(el, k, INK);
        }
    };
    const hasText = el => Array.from(el.childNodes).some(n => n.nodeType === 3 && n.nodeValue.trim());
    const nestedBg = el => {
        for (let a = el.parentElement; a; a = a.parentElement) {
            if (a.__bcdm && 'background-color' in a.__bcdm) return true;
            if (a.id === 'bChatContent') break;
        }
        return false;
    };
    const fixBg = (el, cs) => {
        const bg = rgba(cs.backgroundColor);
        if (solid(bg, 0.6) && lumOf(bg) > 0.88) put(el, 'background-color', nestedBg(el) ? '#27272c' : '#1b1b1f');
    };
    const fixBorders = (el, cs) => {
        for (const [side, lim] of BORDERS) {
            const c = rgba(cs[`border${side}Color`]);
            if (parseFloat(cs[`border${side}Width`]) > 0 && solid(c, 0.3) && lumOf(c) > lim && spread(c) < 40) put(el, `border-${side.toLowerCase()}-color`, '#3a3a3f');
        }
    };
    const isRed = c => c[0] > 100 && c[1] < 90 && c[2] < 100 && c[0] > c[1] * 1.8;
    const textTone = c => {
        const L = lumOf(c), sat = spread(c);
        if (isRed(c)) return L < 0.33 ? '#ee5b78' : null;
        return (sat < 40 && L < 0.45) || (L < 0.33 && sat < 90) ? INK : null;
    };
    const fixText = (el, cs) => {
        const c = hasText(el) && rgba(cs.color);
        const tone = c && textTone(c);
        if (tone) put(el, 'color', tone);
    };
    const fix = el => {
        const cs = styleOf(el);
        if (!cs) return;
        fixBg(el, cs);
        fixBorders(el, cs);
        fixText(el, cs);
    };
    const inBox = el => !!el.closest && !el.closest('#bc-unchained-host');
    const visit = el => {
        if (el.nodeType !== 1 || seen.has(el)) return;
        seen.add(el);
        if (el.localName === 'svg') { if (!el.parentElement?.closest(SKIP)) fixSvg(el); }
        else if (!el.closest(SKIP)) fix(el);
    };
    const visitTree = el => {
        if (el.nodeType !== 1 || !inBox(el)) return;
        visit(el);
        for (const c of el.querySelectorAll('*')) visit(c);
    };
    const sweep = () => {
        tm = 0;
        const box = document.body;
        if (!on || !box) return;
        const all = Array.from(box.querySelectorAll('*')).filter(e => !seen.has(e));
        const vh = window.innerHeight + 80, vw = window.innerWidth, first = [], list = [];
        for (const e of all) {
            const r = e.getBoundingClientRect();
            (r.width > 0 && r.height > 0 && r.bottom > -80 && r.top < vh && r.right > 0 && r.left < vw ? first : list).push(e);
        }
        for (const e of first) visit(e);
        let i = 0;
        const step = () => {
            if (!on) return;
            const end = Math.min(i + 600, list.length);
            for (; i < end; i++) visit(list[i]);
            if (i < list.length) requestAnimationFrame(step);
        };
        step();
    };
    const pendAttr = new Set(), pendTree = new Set();
    let pendRaf = 0, pendTo = 0;
    const flushPend = () => {
        cancelAnimationFrame(pendRaf); clearTimeout(pendTo); pendRaf = pendTo = 0;
        const trees = [...pendTree], attrs = [...pendAttr];
        pendTree.clear(); pendAttr.clear();
        if (!on) return;
        for (const n of trees) if (n.isConnected) visitTree(n);
        for (const t of attrs) if (t.isConnected) fix(t);
    };
    const schedPend = () => {
        if (pendRaf || pendTo) return;
        pendRaf = requestAnimationFrame(flushPend);
        pendTo = setTimeout(flushPend, 250);
    };
    const onAttr = ({ target: t, attributeName }) => {
        if (t.nodeType !== 1 || !inBox(t) || t.closest(SKIP)) return;
        if (attributeName === 'style' && (t.__bcdm || !t.closest('#bChatContent'))) return;
        pendAttr.add(t);
    };
    const onMut = recs => {
        if (!on) return;
        for (const r of recs) {
            if (r.type === 'childList') r.addedNodes.forEach(n => { if (!isOwnNode(n)) pendTree.add(n); });
            else if (r.type === 'attributes') onAttr(r);
        }
        if (pendTree.size || pendAttr.size) schedPend();
    };
    const queue = () => { if (!tm) tm = requestAnimationFrame(sweep); };
    const revert = () => {
        for (const ref of touched) { const el = ref.deref(); if (!el || !el.__bcdm) continue; for (const k in el.__bcdm) { const v = el.__bcdm[k]; v ? el.style.setProperty(k, v) : el.style.removeProperty(k); } delete el.__bcdm; }
        touched.length = 0; seen = new WeakSet();
    };
    const start = () => {
        if (!mo && document.body) { mo = new MutationObserver(onMut); mo.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'hidden', 'style'] }); }
        queue();
    };
    const stop = () => { mo?.disconnect(); mo = null; pendTree.clear(); pendAttr.clear(); revert(); };
    return {
        set(v) {
            v = !!v;
            if (v === on) { if (on) queue(); return; }
            on = v;
            on ? start() : stop();
        }
    };
})();
const markHostDfb = on => {
    try { document.getElementById('bc-unchained-host')?.toggleAttribute('data-dfb', !!on); } catch {}
};
const DARK_M_SHEETS = [['bc-unchained-dark-m', DARK_M_CSS], ['bc-unchained-dark-fix', DARK_FIX_CSS], ['bc-unchained-dark-all', DARK_ALL_CSS]];
const darkBcMobile = (root, on) => {
    DarkSweep.set(on);
    markHostDfb(false);
    if (on) DARK_M_SHEETS.forEach(([id, css]) => addStyle(id, css, root));
    setCls(root, 'bc-dark-m', on);
    setCls(root, 'bc-dark-fb', false);
    syncOpaque(false);
};
const darkGeneric = (root, on) => {
    if (on) addStyle('bc-unchained-dark-css', DARK_FB_CSS, root);
    setCls(root, 'bc-dark-fb', on);
    markHostDfb(on);
    syncOpaque(on);
};
const PLAT_UA = /Android|iPhone|iPad|iPod|Mobile|Opera Mini|IEMobile/i;
let platFinal = false;
const platGuess = () => {
    const h = Store.get('bc_plat', null);
    return h === 'm' || h === 'd' ? h : (PLAT_UA.test(navigator.userAgent) ? 'm' : 'd');
};
const platNow = () => (document.body?.classList.contains('ui-mobile-viewport') ? 'm' : platFinal ? 'd' : platGuess());
const rememberPlat = p => { if (Store.get('bc_plat', null) !== p) Store.set('bc_plat', p); };
const applyDark = () => {
    const b = document.body, root = document.documentElement;
    if (!b || !root) return;
    const on = AppState.dark;
    if (!BC_RE.test(location.hostname)) return darkGeneric(root, on);
    const p = platNow();
    if (platFinal || b.classList.contains('ui-mobile-viewport')) rememberPlat(p);
    if (p === 'd') {
        if (root.classList.contains('bc-dark-m')) darkBcMobile(root, false);
        darkBcDesktop(b, on);
    } else darkBcMobile(root, on);
};
(() => {
    const start = () => {
        try { applyDark(); } catch {}
        const mo = new MutationObserver(() => { if (AppState.dark) try { applyDark(); } catch {} });
        mo.observe(document.body, { attributes: true, attributeFilter: ['class'] });
        mo.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
        const settle = () => { platFinal = true; try { applyDark(); } catch {} };
        if (document.readyState === 'complete') settle();
        else window.addEventListener('load', settle, { once: true });
    };
    if (document.body) return start();
    const mo = new MutationObserver(() => { if (document.body) { mo.disconnect(); start(); } });
    mo.observe(document.documentElement, { childList: true });
})();

const REC_RES = { hi: '1080p', mid: '720p', low: '480p', min: '360p' };
const REC_Q = { hi: [6000000, 128000], mid: [3500000, 128000], low: [2000000, 96000], min: [1000000, 64000] };
const REC_PART = [50, 100, 150, 300];
const REC_TOTAL = [0, 512, 1024, 2048, 4096];
const recNorm = c => {
    c = (c && typeof c === 'object' && !Array.isArray(c)) ? c : {};
    return { q: REC_Q[c.q] ? c.q : 'hi', part: REC_PART.includes(c.part) ? c.part : 150, total: REC_TOTAL.includes(c.total) ? c.total : 0 };
};
const recCfg = () => recNorm(Store.get('bc_rec', {}));
const fmtShort = b => { const m = b / 1048576; return m >= 1024 ? `${(m / 1024).toFixed(2)}G` : `${m.toFixed(1)}M`; };
const fmtBytes = b => { const m = b / 1048576, l = L(); return m >= 1024 ? `${(m / 1024).toFixed(2)} ${l.u_gb}` : `${m.toFixed(1)} ${l.u_mb}`; };

const BK_CHECK = {
    cols: v => Number.isInteger(v) && v >= 1 && v <= 2,
    b: v => typeof v === 'boolean',
    scale: v => typeof v === 'number' && v >= 0.6 && v <= 1.5,
    css: v => typeof v === 'string' && /^-?\d+(\.\d+)?(px|%)$/.test(v),
    color: v => typeof v === 'string' && v.length < 60 && /^(rgba?|hsla?)\([\d\s.,%]+\)$/.test(v),
    lang: v => LANGS.includes(v),
    sort: v => typeof v === 'string' && /^[a-z]{1,12}$/.test(v),
    spd: v => v === 500 || v === 1000,
    wf: v => v === -1 || v === 0 || v === 1,
    lay: v => Number.isInteger(v) && v >= 0 && v <= 3,
    ctext: v => typeof v === 'string' && v.length <= 80,
    keys: v => Array.isArray(v) && v.length <= 2000 && v.every(x => typeof x === 'string' && x.length <= 160),
    hsort: v => v === 'last' || v === 'time' || v === 'visits'
};
const BACKUP_SCHEMA = {
    bc_bg: 'b', bc_min: 'b', bc_hid: 'b', bc_pos: 'b', bc_gmute: 'b', bc_dark: 'b',
    bc_bm_gal: 'b', bc_bm_hide_topic: 'b', bc_bm_hide_grp: 'b', bc_bm_hide_ptags: 'b', bc_bm_hide_note: 'b', bc_bm_hide_priv: 'b', bc_bm_hide_group: 'b', bc_bm_hide_vip: 'b', bc_bm_hide_away: 'b', bc_bm_hide_off: 'b', bc_bm_sort_rev: 'b', bc_previews: 'b', bc_favnav: 'b',
    bc_scale: 'scale', bc_x: 'css', bc_y: 'css', bc_fx: 'css', bc_fy: 'css', bc_fb: 'css',
    bc_theme: 'color', bc_lang: 'lang', bc_bm_sort_type: 'sort', bc_prev_spd: 'spd',
    bc_hide_cfg: 'hcfg', bc_hide_custom: 'hcustom', bc_rec: 'rec', bc_lang_auto: 'b',
    bc_hist: 'hist', bc_hist_ch: 'b', bc_btnhide: 'btns', bc_star: 'b', bc_hist_on: 'b', bc_bm_cols_g: 'cols', bc_bm_cols_l: 'cols',
    bc_bm_wf: 'wf', bc_cal_wf: 'wf', bc_cal_lay: 'lay', bc_cal_grp: 'ctext', bc_cal_tag: 'ctext', bc_cal_models: 'keys', bc_hist_sort: 'hsort',
    bc_rad: 'b', bc_rad_x: 'css', bc_rad_y: 'css'
};
const safeSel = x => {
    if (typeof x !== 'string' || !x.trim() || x.length > 400 || /[{};@]|\/\*/.test(x)) return false;
    try { document.querySelector(x); return true; } catch { return false; }
};
const cleanHideCfg = o => {
    if (!o || typeof o !== 'object' || Array.isArray(o)) return null;
    const out = {};
    HIDE_CATS.forEach(c => { if (typeof o[c.id] === 'boolean') out[c.id] = o[c.id]; });
    return out;
};
const cleanHideCustom = o => {
    if (!o || typeof o !== 'object' || Array.isArray(o)) return null;
    const out = {};
    Object.keys(o).forEach(k => {
        if (!/^[a-z0-9.-]{1,40}$/i.test(k) || !Array.isArray(o[k])) return;
        out[k] = o[k].filter(safeSel).slice(0, 200);
    });
    return out;
};
const histNum = v => Number.isFinite(v) && v >= 0 ? v : 0;
const cleanHist = o => {
    if (!o || typeof o !== 'object' || Array.isArray(o)) return null;
    const m = {}, list = [];
    const src = o.m && typeof o.m === 'object' && !Array.isArray(o.m) ? o.m : {};
    Object.keys(src).slice(0, 2000).forEach(k => {
        const e = src[k];
        if (!/^[a-z0-9.-]{1,40}\|.{1,120}$/i.test(k) || !e || typeof e !== 'object' || !isStr(e.u) || !isSafeUrl(e.u)) return;
        m[k] = { n: clip(e.n, 100), u: normUrl(e.u), a: toHttps(e.a), s: histNum(e.s), v: histNum(e.v), f: histNum(e.f), l: histNum(e.l) };
    });
    (Array.isArray(o.s) ? o.s : []).slice(-1000).forEach(x => {
        if (x && typeof x === 'object' && isStr(x.k) && m[x.k]) list.push({ k: x.k, n: clip(x.n, 100), t: histNum(x.t), d: histNum(x.d) });
    });
    return { m, s: list };
};
const mergeHist = (a, b) => {
    const cur = cleanHist(a) || { m: {}, s: [] }, inc = cleanHist(b) || { m: {}, s: [] };
    Object.keys(inc.m).forEach(k => { if (!cur.m[k] || cur.m[k].s < inc.m[k].s) cur.m[k] = inc.m[k]; });
    const seen = new Set(cur.s.map(x => `${x.k}|${x.t}`));
    inc.s.forEach(x => { if (cur.m[x.k] && !seen.has(`${x.k}|${x.t}`)) cur.s.push(x); });
    cur.s.sort((x, y) => x.t - y.t);
    cur.s = cur.s.slice(-1000);
    return cur;
};
const cleanBtns = o => {
    if (!o || typeof o !== 'object' || Array.isArray(o)) return null;
    const out = {};
    Object.keys(o).forEach(k => { if (/^[A-Za-z]{2,12}$/.test(k) && o[k] === true) out[k] = true; });
    return out;
};
const BK_CLEAN = { hist: cleanHist, btns: cleanBtns, hcfg: cleanHideCfg, hcustom: cleanHideCustom, rec: o => (o && typeof o === 'object' && !Array.isArray(o)) ? recNorm(o) : null };
const bkValue = (kind, v) => BK_CLEAN[kind] ? BK_CLEAN[kind](v) : (BK_CHECK[kind](v) ? v : null);
const restoreSettings = src => Object.entries(BACKUP_SCHEMA).reduce((n, [k, kind]) => {
    if (!Object.prototype.hasOwnProperty.call(src, k)) return n;
    const v = bkValue(kind, src[k]);
    if (v == null) return n;
    Store.set(k, k === 'bc_hist' ? mergeHist(Store.get('bc_hist', {}), v) : v);
    return n + 1;
}, 0);
const Backup = {
    parts() {
        const p = Store.get('bc_bk_parts', {});
        const o = { s: p.s !== false, f: p.f !== false, h: p.h !== false };
        return o.s || o.f || o.h ? o : { s: true, f: true, h: true };
    },
    setPart(k, on) {
        const p = this.parts();
        p[k] = on;
        if (!p.s && !p.f && !p.h) return false;
        Store.set('bc_bk_parts', p);
        return true;
    },
    build() {
        const p = this.parts();
        const out = { app: 'BongaCams Unchained', ver: 2, date: new Date().toISOString() };
        if (p.s) {
            const settings = {};
            Object.keys(BACKUP_SCHEMA).forEach(k => { if (k === 'bc_hist') return; const v = Store.get(k, null); if (v !== null) settings[k] = v; });
            out.settings = settings;
        }
        if (p.f) out.bookmarks = AppState.bookmarks.map(stripBm);
        if (p.h) out.history = histLoad();
        return out;
    },
    export() {
        const blob = new Blob([JSON.stringify(this.build(), null, 2)], { type: 'application/json' });
        Helpers.download(blob, `BC_Backup_${new Date().toISOString().slice(0, 10)}.json`);
    },
    exportFavCsv() {
        const rows = [['name', 'url', 'group', 'note', 'pinned', 'last_seen'],
            ...AppState.bookmarks.map(b => [b.name, b.url, b.g || '', b.note || '', b.pin ? 1 : 0, b.seen ? fmtStamp(b.seen) : ''])];
        Helpers.download(new Blob([csvText(rows)], { type: 'text/csv;charset=utf-8' }), `BC_Favorites_${Helpers.getTimestamp().slice(0, 10)}.csv`);
    },
    apply(data) {
        const p = this.parts();
        const favs = list => (p.f && Array.isArray(list) ? mergeBookmarks(list) : 0);
        if (Array.isArray(data)) return { n: 0, added: favs(data) };
        if (data?.app !== 'BongaCams Unchained') throw new Error('bad backup');
        const n = p.s ? restoreSettings(isObj(data.settings) ? data.settings : {}) : 0;
        const added = favs(data.bookmarks);
        if (p.h && isObj(data.history)) { const hc = cleanHist(data.history); if (hc) histMerge(hc); }
        return { n, added };
    },
    import(onOk, onErr) {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';
        input.style.display = 'none';
        (document.body || document.documentElement).appendChild(input);
        input.oncancel = () => input.remove();
        input.onchange = async e => {
            try {
                const file = e.target.files?.[0];
                if (!file) return;
                if (file.size > 5e6) throw new Error('too big');
                onOk(this.apply(JSON.parse(await file.text())));
            } catch { onErr(); } finally { input.remove(); }
        };
        input.click();
    }
};
const LANG_SEG = /^(?:ru|uk|ua|en|es|de|fr|pt|it|pl|tr|nl|cs|ro|hu|bg|el|ja|zh|ko|he|ar|hi|id|vi|th)$/i;
const bcSlug = seg => {
    while (seg.length > 1 && LANG_SEG.test(seg[0])) seg.shift();
    if (/^profile$/i.test(seg[0] || '')) seg.shift();
    const s = seg[0] || '';
    return BC_SYS.test(s) ? '' : s.toLowerCase();
};
const plainSlug = (sys, valid) => seg => {
    const s = seg[0] || '';
    return sys.test(s) || !valid.test(s) ? '' : s;
};
const SLUG_BY_SITE = new Map([['bc', bcSlug], ['sc', plainSlug(SC_SYS, /^[\w.-]+$/)], ['cb', plainSlug(CB_SYS, /^\w+$/)]]);
const firstSeg = seg => seg[0] || '';
const modelSlug = u => {
    try {
        const x = new URL(u);
        const seg = x.pathname.split('/').filter(Boolean).map(safeDecode);
        return (SLUG_BY_SITE.get(siteKey(x.hostname)) || firstSeg)(seg);
    } catch { return ''; }
};
const bmKey = u => { const s = modelSlug(u); return s ? `${urlSite(u)}|${s.toLowerCase()}` : String(u); };
const pageKey = () => { const s = modelSlug(location.href); return s ? `${SITE}|${s.toLowerCase()}` : ''; };
const normUrl = (u, host) => {
    try {
        if (!isSafeUrl(u)) return u;
        const x = new URL(u), s = modelSlug(u);
        return s ? `https://${host || x.host}/${encodeURIComponent(s)}` : x.href;
    } catch { return u; }
};
const linkFor = u => {
    try {
        const host = urlSite(u) === siteKey(location.hostname) ? location.host : new URL(u).host;
        return normUrl(u, host);
    } catch { return u; }
};
const isFavKey = k => !!k && AppState.bookmarks.some(b => bmKey(b.url) === k);
const isFavName = name => !!name && (AppState.bookmarks.some(b => sameBm(b, name)) || isFavKey(pageKey()));
const BM_FILL_KEYS = ['note', 'g', 'avatar'];
const absorbBm = (prev, b) => {
    BM_FILL_KEYS.forEach(k => { if (!prev[k] && b[k]) prev[k] = b[k]; });
    if (b.pin) prev.pin = true;
    prev.seen = Math.max(prev.seen || 0, b.seen || 0);
};
const migrateBookmarks = () => {
    const map = new Map();
    const before = AppState.bookmarks.length;
    let changed = false;
    AppState.bookmarks.forEach((b, i) => {
        if (!b || !isStr(b.url)) { map.set(`#${i}`, b); return; }
        const nu = normUrl(b.url);
        if (nu !== b.url) { b.url = nu; changed = true; }
        const k = bmKey(b.url), prev = map.get(k);
        if (!prev) { map.set(k, b); return; }
        changed = true;
        absorbBm(prev, b);
    });
    if (changed) {
        AppState.bookmarks = [...map.values()].filter(Boolean);
        saveBookmarks();
    }
    return before - AppState.bookmarks.length;
};
migrateBookmarks();

const readFb = () => {
    const fb = Store.get('bc_fb', null);
    if (fb) return fb;
    const fy = Store.get('bc_fy', null);
    if (!fy || window.innerHeight < 200) return null;
    const v = `${Math.max(0, Math.round(window.innerHeight - parseFloat(fy) - 50))}px`;
    Store.set('bc_fb', v);
    return v;
};
const injectSiteCSS = () => {
    if (document.getElementById('bc-unchained-site-css')) return;
    const fx = Store.get('bc_fx', null), fb = readFb();
    let css = `${currentSite.css || ''} .js-filter_button, .bc_sticky_bar { touch-action: none !important; user-select: none !important; -webkit-user-drag: none !important; }
.bc_sticky_bar .bc_filter_button,.bc_sticky_bar .js-filter_button{animation:none!important;transition:none!important;transform:none!important;translate:none!important;opacity:1!important;top:auto!important;bottom:auto!important;inset-block:auto!important}
html.bc-theater-html{background:#000!important;overflow:hidden!important}
body.bc-theater-mode{overflow:hidden!important;background:#000!important;margin:0!important;padding:0!important}
body.bc-theater-mode :is(.chat_panel_wrap,.player_footer,[class*="chat-panel"],[class*="chat_panel"],[class*="player-footer"],#chat_bar_v2_container,#chat_bar_v2,#switch_between_chat,.chat-tabs,[class*="chat_nav"],[class*="chat_bar"],#games_button,.mls_title,.live_tabs,.page_header,.header_bar,.chat-wrapper,.bc_chat_header,.memberBalance,.memberNavigation,.private_btn_wrp,#bPaidButtonTopRow,#profile-content,.stream-controls,#top_banner_above_chat,[class*="footer"]:not(#bc-unchained-host *)){display:none!important}
body.bc-theater-mode .bc-thtr-anc{transform:none!important;translate:none!important;scale:none!important;rotate:none!important;filter:none!important;backdrop-filter:none!important;perspective:none!important;contain:none!important;overflow:visible!important;clip-path:none!important;mask:none!important;will-change:auto!important}
body.bc-theater-mode .bc-thtr-wrap{position:fixed!important;inset:0!important;width:100vw!important;height:100vh!important;width:100dvw!important;height:100dvh!important;max-width:none!important;max-height:none!important;z-index:2147483644!important;background:#000!important;margin:0!important;padding:0!important;transform:none!important;display:block!important}
body.bc-theater-mode video.bc-thtr-video{position:fixed!important;inset:0!important;width:100vw!important;height:100vh!important;width:100dvw!important;height:100dvh!important;max-width:none!important;max-height:none!important;aspect-ratio:auto!important;z-index:2147483646!important;object-fit:contain!important;background:#000!important;margin:0!important;padding:0!important;transform:none!important;translate:none!important;rotate:none!important;scale:none!important}`;
    if (fx && fb) {
        css += `.bc_sticky_bar:not([data-bcu]){visibility:hidden!important}.bc_sticky_bar{left:${fx}!important;top:auto!important;bottom:${fb}!important;transform:none!important;margin:0!important;right:auto!important;width:max-content!important;transition:none!important;animation:none!important}`;
    }
    addStyle('bc-unchained-site-css', css, document.documentElement);
};
injectSiteCSS();
applyHideCSS();

const LOCK_SEL = '.fp_outer,.fp_outer_overlay,.fp_inner_wrap';
const unlockScroll = () => {
    if (!BC_RE.test(location.hostname) || !document.documentElement) return;
    const root = document.documentElement;
    const locked = !!document.querySelector(LOCK_SEL);
    if (!locked) { root.classList.remove('bc-unlock'); return; }
    addStyle('bc-unchained-unlock-css', 'html.bc-unlock,html.bc-unlock body{overflow-y:auto!important;overflow-x:hidden!important;position:relative!important;top:auto!important;height:auto!important;touch-action:pan-y pinch-zoom!important;overscroll-behavior:auto!important}', root);
    root.classList.add('bc-unlock');
    [root, document.body].forEach(el => {
        if (!el) return;
        [...el.classList].forEach(c => { if (/^(fp_|__fp|noscroll|no_scroll|no-scroll|scroll_lock|scroll-lock|modal_open|modal-open|popup_open|has_popup)/i.test(c)) el.classList.remove(c); });
    });
};
if (!window.__bcUnlockBound) {
    window.__bcUnlockBound = true;
    const guard = e => {
        if (!document.documentElement.classList.contains('bc-unlock')) return;
        const path = e.composedPath ? e.composedPath() : [];
        if (path.some(n => n && n.id === 'bc-unchained-host')) return;
        e.stopImmediatePropagation();
    };
    ['touchmove', 'wheel', 'scroll'].forEach(ev => window.addEventListener(ev, guard, { capture: true, passive: true }));
}
const MPOP_ATTR = 'data-bc-mpop';
const MPOP_INPUTS = 'input.sendInput,textarea.sendInput,input.js-chat_msg_input,input.ccp_input';
const MPOP_SKIP = '#bChat,#bChatInputContainer,.ccp_wrapper,.chat_panel_wrap,#chat_bar_v2_container,[' + MPOP_ATTR + ']';
const isRootEl = p => p === document.body || p === document.documentElement;
const findFixedAncestor = inp => {
    for (let p = inp.parentElement; p && !isRootEl(p); p = p.parentElement) {
        if (getComputedStyle(p).position === 'fixed') return p;
    }
    return null;
};
const findBodyChild = inp => {
    let p = inp;
    while (p.parentElement && p.parentElement !== document.body) p = p.parentElement;
    return p.parentElement === document.body ? p : null;
};
const popupTarget = inp => {
    if (inp.id === 'send-input-container' || inp.closest(MPOP_SKIP)) return null;
    return findFixedAncestor(inp) || findBodyChild(inp);
};
const isModelPopup = (target, vw, vh) => {
    if (!target || target === document.body) return false;
    if (target.querySelector('video,#bChat,.chat_panel_wrap,#stream-container')) return false;
    const r = target.getBoundingClientRect();
    return !(r.width > vw * 0.9 && r.height > vh * 0.9);
};
const tagModelPopups = () => {
    if (!BC_RE.test(location.hostname) || !document.body) return;
    const inputs = document.querySelectorAll(MPOP_INPUTS);
    if (!inputs.length) return;
    const vw = window.innerWidth, vh = window.innerHeight;
    const found = new Set();
    inputs.forEach(inp => { const t = popupTarget(inp); if (isModelPopup(t, vw, vh)) found.add(t); });
    if (found.size) requestAnimationFrame(() => found.forEach(t => t.setAttribute(MPOP_ATTR, '1')));
};
(() => {
    let t = 0;
    const run = () => {
        clearTimeout(t); t = 0;
        if (document.hidden) return;
        try { tagModelPopups(); } catch {}
        try { unlockScroll(); } catch {}
    };
    const sched = () => { if (!t) t = setTimeout(run, 150); };
    new MutationObserver(recs => { if (!onlyOwnNodes(recs)) sched(); }).observe(document.documentElement, { childList: true, subtree: true });
    onPageEvent('visibilitychange', () => { if (!realHidden()) sched(); });
    setInterval(run, 1500);
    sched();
})();

const pSvg = (d, s = 20, fill = 'none', stroke = 'currentColor') => `<svg viewBox="0 0 24 24" width="${s}" height="${s}" stroke="${stroke}" fill="${fill}" stroke-width="2">${d}</svg>`;
const icons = {
    coffee: pSvg('<g stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 10h13v5.5a4.5 4.5 0 0 1-4.5 4.5h-4A4.5 4.5 0 0 1 4 15.5z\"/><path d=\"M17 12h1.5a2.5 2.5 0 0 1 0 5H17\"/><path d=\"M7 8c-1-1.2-1-2.3 0-3.5s1-2.3 0-3.5\"/><path d=\"M11 8c-1-1.2-1-2.3 0-3.5s1-2.3 0-3.5\"/><path d=\"M15 8c-1-1.2-1-2.3 0-3.5s1-2.3 0-3.5\"/></g>', 16),
    color: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a9 9 0 0 0 0 18c1.2 0 2-.9 2-2 0-.6-.3-1-.6-1.4-.3-.4-.4-.8-.4-1.2 0-1.1.9-2 2-2H17a4 4 0 0 0 4-4c0-4.5-4-7.4-9-7.4z"/><circle cx="7.5" cy="11" r="1" fill="currentColor"/><circle cx="10" cy="7" r="1" fill="currentColor"/><circle cx="15" cy="7" r="1" fill="currentColor"/></g>', 14),
    menu: pSvg('<circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/>', 24),
    eye: pSvg('<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>', 14),
    close: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9 9l6 6M15 9l-6 6"/></g>', 16),
    home: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M4 10.5V19a1.5 1.5 0 0 0 1.5 1.5H9v-5.5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v5.5h3.5A1.5 1.5 0 0 0 20 19v-8.5"/><path d="M2.5 11.5L12 3.5l9.5 8"/></g>', 16),
    rel: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 4.5V9h-4.5"/></g>', 16),
    min: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M6 9.5l6 6 6-6"/></g>', 16),
    bgOn: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9.5"/><polygon points="10 8.5 10 15.5 16 12" fill="currentColor"/></g>'),
    bgOff: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9.5"/><polygon points="10 8.5 10 15.5 16 12" fill="currentColor"/><line x1="3" y1="3" x2="21" y2="21"/></g>'),
    vol: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5h3.2L11 6v12l-4.8-3.5H3z"/><path d="M15 9.5v5M18.5 7v10M22 10.5v3"/></g>'),
    mute: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5h3.2L11 6v12l-4.8-3.5H3z"/><path d="M16 9.5l5 5M21 9.5l-5 5"/></g>'),
    volLow: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5h3.2L11 6v12l-4.8-3.5H3z"/><path d="M15 9.5v5"/></g>'),
    volMed: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5h3.2L11 6v12l-4.8-3.5H3z"/><path d="M15 9.5v5M18.5 7v10"/></g>'),
    snap: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M3 8V5a2 2 0 0 1 2-2h3M16 3h3a2 2 0 0 1 2 2v3M21 16v3a2 2 0 0 1-2 2h-3M8 21H5a2 2 0 0 1-2-2v-3"/><circle cx="12" cy="12" r="3.5"/></g>'),
    rec: pSvg('<g><rect x="2" y="6" width="20" height="12" rx="6"/><circle cx="12" cy="12" r="3.5" fill="currentColor" stroke="none"/></g>'),
    qual: pSvg('<rect x="2" y="5" width="20" height="14" rx="3"/><path d="M6.5 9v6M11 9v6M6.5 12H11M14.5 9v6h1.8a2.7 2.7 0 0 0 2.7-2.7v-.6A2.7 2.7 0 0 0 16.3 9z"/>'),
    pip: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3.5" width="20" height="14" rx="2.5"/><rect x="12" y="10" width="7" height="5" rx="1.5" fill="currentColor"/></g>'),
    fs: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3"/></g>'),
    thtr: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><rect x="5" y="9" width="14" height="6" rx="1" fill="currentColor"/></g>'),
    search: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><circle cx="10.5" cy="10.5" r="7"/><path d="M16 16l5 5M10.5 7.5v6M7.5 10.5h6"/></g>'),
    copy: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></g>'),
    fav: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h12a1 1 0 0 1 1 1v17l-7-4.5L5 21V4a1 1 0 0 1 1-1z"/><polygon points="12.00 7.30 13.00 9.82 15.71 9.99 13.62 11.73 14.29 14.36 12.00 12.90 9.71 14.36 10.38 11.73 8.29 9.99 11.00 9.82" fill="currentColor" stroke="currentColor" stroke-width="0.8"/></g>'),
    favPrev: pSvg('<polygon points="19 20 9 12 19 4 19 20"/><line x1="5" y1="19" x2="5" y2="5"/>'),
    favNext: pSvg('<polygon points="5 4 15 12 5 20 5 4"/><line x1="19" y1="5" x2="19" y2="19"/>'),
    del: pSvg('<polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/>', 16),
    hls: pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M2 12h4.5l2.5-6 4 12 3-8 2 2H22"/></g>'),
    ok: pSvg('<polyline points="20 6 9 17 4 12"/>', 16, 'none', '#2ecc71'),
    arrowUp: pSvg('<line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/>', 12),
    arrowDown: pSvg('<line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/>', 12),
    back: pSvg('<polyline points="15 18 9 12 15 6"/>', 18),
    cam: pSvg('<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/>', 12),
    clock: pSvg('<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>', 12),
    name: pSvg('<path d="M4 20l5-12 5 12"/><path d="M6 15h6"/>', 12),
    dot: pSvg('<circle cx="12" cy="12" r="7"/>', 12, '#2ecc71', '#2ecc71'),
    list: pSvg('<line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/>', 12),
    grid: pSvg('<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>', 12)
};
icons.sleep = pSvg('<circle cx="12" cy="13" r="8"/><polyline points="12 9 12 13 15 15"/><line x1="9" y1="2" x2="15" y2="2"/>');
icons.cal = pSvg('<rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>', 15);
icons.circle = pSvg('<circle cx="12" cy="12" r="9"/>', 16);
icons.check = pSvg('<polyline points="20 6 9 17 4 12"/>', 16);
icons.eyeNo = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><path d="M9 9l6 6M15 9l-6 6"/></g>', 16);
icons.eyeOk = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><path d="M8.3 12.2l2.7 2.7 4.8-5.4"/></g>', 16);
icons.tag = pSvg('<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><circle cx="7" cy="7" r="1"/>', 12);
icons.folder = pSvg('<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>', 12);
icons.chevL = pSvg('<polyline points="15 18 9 12 15 6"/>', 18);
icons.chevR = pSvg('<polyline points="9 18 15 12 9 6"/>', 18);
icons.boxOn = pSvg('<rect x="3" y="3" width="18" height="18" rx="4"/><polyline points="8 12 11 15 16 9"/>', 16);
icons.boxOff = pSvg('<rect x="3" y="3" width="18" height="18" rx="4"/>', 16);
icons.undo = pSvg('<polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>', 14);

icons.eyeOff = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/><line x1="4" y1="20" x2="20" y2="4"/></g>', 14);
icons.sun = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.5"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></g>', 14);
icons.moon = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/><path d="M18 1.5v3M16.5 3h3"/></g>', 14);
icons.dl = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9.5"/><path d="M12 7.5v8M8.5 12.5l3.5 3.5 3.5-3.5"/></g>', 14);
icons.ul = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="2.5" width="19" height="19" rx="5"/><path d="M12 16.5v-8M8.5 12l3.5-3.5 3.5 3.5"/></g>', 14);
icons.target = pSvg('<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/>', 14);
icons.globe = pSvg('<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>', 15);
icons.dice = pSvg('<rect x="3" y="3" width="18" height="18" rx="3"/><circle cx="8.5" cy="8.5" r="1"/><circle cx="15.5" cy="8.5" r="1"/><circle cx="8.5" cy="15.5" r="1"/><circle cx="15.5" cy="15.5" r="1"/>', 15);
icons.gear = pSvg('<g stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M3 12h18M3 18h18"/><circle cx="15" cy="6" r="2.2" fill="currentColor"/><circle cx="8" cy="12" r="2.2" fill="currentColor"/><circle cx="17" cy="18" r="2.2" fill="currentColor"/></g>', 15);
icons.star = pSvg('<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>', 16);
icons.history = pSvg('<path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><polyline points="3 3 3 8 8 8"/><polyline points="12 7 12 12 15 14"/>', 15);
icons.bookmark = pSvg('<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/>', 15);
icons.table = pSvg('<rect x="3" y="4" width="18" height="16" rx="2"/><line x1="3" y1="10" x2="21" y2="10"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="4" x2="9" y2="20"/>', 15);

const i18n = {
    RU: { drag: '⁞⁞', bg: 'ФОН', sound: 'ЗВУК', snap: 'СКРИН', rec: 'ЗАПИСЬ', err: 'ОШИБКА', no_vid: 'НЕТ ВИДЕО', qual: 'КАЧ-ВО', pip: 'PIP', fs: 'ЭКРАН', thtr: 'ТЕАТР', search: 'ПОИСК', copy: 'ССЫЛКА', home: 'Домой', rel: 'Рестарт', min: 'Свернуть', hide: 'Скрыть (H)', hints: 'M=ЗВУК F=ЭКРАН T=ТЕАТР H=СКРЫТЬ', favs: 'ИЗБРАННОЕ', no_model: 'Модель не найдена', bm_title: 'Избранное', bm_add: 'В избранное', bm_empty: 'Список пуст.', bm_dup: 'Уже добавлено!', note_ph: 'Заметка...', hd_title: 'Скрытие', hd_cats: 'Категории', hd_rules: 'Мои правила', hd_none: 'Правил пока нет.', hd_pick: 'Выбрать элемент', hd_reset: 'Сбросить для этого сайта', hd_all: 'Скрыть всё', hd_peek: 'Удерживайте пункт, чтобы увидеть, что он скрывает', hd_na: 'пока не найдено', hd_off: 'Показать всё', hd_clear: 'Удалить все мои правила', pk_hint: 'Коснитесь элемента на странице', pk_up: 'Выше', pk_ok: 'Скрыть', pk_cancel: 'Отмена', pk_found: 'совп.', hd_p_min: 'Минимум', hd_p_clean: 'Чистый плеер', dark: 'Тёмная / светлая тема', bk_exp: 'Экспорт резервной копии', bk_imp: 'Импорт резервной копии' },
    EN: { drag: '⁞⁞', bg: 'BG', sound: 'VOL', snap: 'SNAP', rec: 'REC', err: 'ERROR', no_vid: 'NO VIDEO', qual: 'QUAL', pip: 'PIP', fs: 'FULL', thtr: 'THTR', search: 'SEARCH', copy: 'LINK', home: 'Home', rel: 'Reload', min: 'Minimize', hide: 'Hide (H)', hints: 'M=MUTE F=FULL T=THTR H=HIDE', favs: 'FAVS', no_model: 'Model not found', bm_title: 'Favorites', bm_add: 'Add current', bm_empty: 'List is empty.', bm_dup: 'Already added!', note_ph: 'Note...', hd_title: 'Hiding', hd_cats: 'Categories', hd_rules: 'My rules', hd_none: 'No rules yet.', hd_pick: 'Pick element', hd_reset: 'Reset for this site', hd_all: 'Hide all', hd_peek: 'Hold an item to see what it hides', hd_na: 'not found yet', hd_off: 'Show all', hd_clear: 'Delete all my rules', pk_hint: 'Tap an element on the page', pk_up: 'Up', pk_ok: 'Hide', pk_cancel: 'Cancel', pk_found: 'matches', hd_p_min: 'Minimal', hd_p_clean: 'Clean player', dark: 'Dark / light theme', bk_exp: 'Export backup', bk_imp: 'Import backup' }
};
const unpackI18N = ({ k, v }) => Object.fromEntries(Object.entries(v).map(([lang, a]) => [lang, Object.fromEntries(k.map((key, i) => [key, a[i]]))]));
const I18N_X = Object.fromEntries(Object.entries({"NEW":{"k":["note_ph","sort_date","sort_name","sort_live","sort_last","bm_online","bm_online_t","bm_priv","bm_all","bm_gal","bm_list","bm_nomatch","bm_del","tp_more","tp_less","don_tip","don_title","don_sub","don_copied","don_fail","don_tap","st_private","st_group","st_vip","st_away","grp_none","grp_new","grp_all","seen_tip","seen_now","ago","u_m","u_h","u_d","u_mb","u_gb","lang_title","lang_auto","rec_tip","rs_title","rs_quality","rs_q_hi","rs_q_mid","rs_q_low","rs_q_min","rs_part","rs_total","rs_off","rs_upto","rs_mbmin","rs_gbh","rs_now","rs_p","rs_t","rs_hint","rs_next","bm_find","bm_pin","bm_unpin"],"v":{"RU":["Заметка... (#теги)","Дата","Имя","Лайв","Был(а)","Онлайн","Показывать только Онлайн","Приват","Все","Галерея","Список","Нет моделей по выбранному фильтру","Удалить","[Ещё]","[Свернуть]","Поддержать автора","Угостить автора кофе","Спасибо, что пользуешься.","Адрес скопирован","Не удалось скопировать","нажми на адрес, чтобы показать полностью","Приват","Группа","VIP","AFK","Без группы","+ Новая группа…","Все группы","Последний раз онлайн","только что","{n} назад","мин","ч","д","МБ","ГБ","Язык","Авто","Нажатие — запись, удержание — настройки","Настройки записи","Качество (битрейт)","Высокое","Среднее","Низкое","Экономия","Размер части (файл делится)","Остановить при общем размере","Выкл.","до","МБ/мин","ГБ/ч","Сейчас","часть","всего","Часть хранится в памяти телефона, пока не сохранится, поэтому меньшие части меньше грузят память.","Качество применяется со следующей части или записи.","Поиск по имени…","Закрепить наверху","Открепить"],"EN":["Note... (#tags)","Date","Name","Live","Seen","Online","Show only Online","Priv","All","Gallery","List","No models match filter","Delete","[More]","[Less]","Support the author","Buy the author a coffee","Thanks for using it.","Address copied","Copy failed","tap the address to show it in full","Private","Group","VIP","AFK","No group","+ New group…","All groups","Last seen online","just now","{n} ago","min","h","d","MB","GB","Language","Auto","Tap: record · Hold: settings","Recording settings","Quality (bitrate)","High","Medium","Low","Saver","Part size (file is split)","Stop at total size","Off","up to","MB/min","GB/h","Now","part","total","A part stays in phone memory until it is saved, so smaller parts use less RAM.","Quality applies from the next part or recording.","Search by name…","Pin to top","Unpin"]}},"LANG":{"k":["drag","bg","sound","snap","rec","err","no_vid","qual","pip","fs","thtr","search","copy","home","rel","min","hide","hints","favs","no_model","bm_title","bm_add","bm_empty","bm_dup","note_ph","hd_title","hd_cats","hd_rules","hd_none","hd_pick","hd_reset","hd_all","hd_peek","hd_na","hd_off","hd_clear","pk_hint","pk_up","pk_ok","pk_cancel","pk_found","hd_p_min","hd_p_clean","dark","sort_date","sort_name","sort_live","sort_last","bm_online","bm_online_t","bm_priv","bm_all","bm_gal","bm_list","bm_nomatch","bm_del","tp_more","tp_less","don_tip","don_title","don_sub","don_copied","don_fail","don_tap","st_private","st_group","st_vip","st_away","grp_none","grp_new","grp_all","seen_tip","seen_now","ago","u_m","u_h","u_d","u_mb","u_gb","lang_title","lang_auto","rec_tip","rs_title","rs_quality","rs_q_hi","rs_q_mid","rs_q_low","rs_q_min","rs_part","rs_total","rs_off","rs_upto","rs_mbmin","rs_gbh","rs_now","rs_p","rs_t","rs_hint","rs_next","bm_find","bm_pin","bm_unpin"],"v":{"UK":["⁞⁞ ПУЛЬТ","ФОН","ЗВУК","СКРІН","ЗАПИС","ПОМИЛКА","НЕМАЄ ВІДЕО","ЯКІСТЬ","PIP","ЕКРАН","ТЕАТР","ПОШУК","ЛІНК","Додому","Перезапуск","Згорнути","Сховати (H)","M=ЗВУК F=ЕКРАН T=ТЕАТР H=СХОВАТИ","ОБРАНЕ","Модель не знайдено","Обране","В обране","Список порожній.","Вже додано!","Нотатка... (#теги)","Приховування","Категорії","Мої правила","Правил поки немає.","Обрати елемент","Скинути для цього сайту","Сховати все","Утримуйте пункт, щоб побачити, що він ховає","поки не знайдено","Показати все","Видалити всі мої правила","Торкніться елемента на сторінці","Вище","Сховати","Скасувати","збіг.","Мінімум","Чистий плеєр","Темна / світла тема","Дата","Імʼя","Лайв","Був(ла)","Онлайн","Показувати лише Онлайн","Приват","Усі","Галерея","Список","Немає моделей за вибраним фільтром","Видалити","[Ще]","[Згорнути]","Підтримати автора","Пригостити автора кавою","Дякую, що користуєшся.","Адресу скопійовано","Не вдалося скопіювати","натисни на адресу, щоб показати повністю","Приват","Група","VIP","AFK","Без групи","+ Нова група…","Усі групи","Востаннє онлайн","щойно","{n} тому","хв","год","д","МБ","ГБ","Мова","Авто","Дотик — запис, утримання — налаштування","Налаштування запису","Якість (бітрейт)","Висока","Середня","Низька","Економія","Розмір частини (файл ділиться)","Зупинити при загальному розмірі","Вимк.","до","МБ/хв","ГБ/год","Зараз","частина","всього","Частина тримається в памʼяті телефона, доки не збережеться, тому менші частини менше навантажують пам'ять.","Якість діє з наступної частини або запису.","Пошук за іменем…","Закріпити нагорі","Відкріпити"],"ES":["⁞⁞ MANDO","BG","SONIDO","CAPT.","GRABAR","ERROR","SIN VÍDEO","CALID.","PIP","PANT.","CINE","BUSCAR","ENLACE","Inicio","Recargar","Minimizar","Ocultar (H)","M=SONIDO F=PANT T=CINE H=OCULTAR","FAVS","Modelo no encontrada","Favoritos","Añadir actual","La lista está vacía.","¡Ya añadida!","Nota... (#etiquetas)","Ocultar","Categorías","Mis reglas","Aún no hay reglas.","Elegir elemento","Restablecer para este sitio","Ocultar todo","Mantén pulsado un elemento para ver qué oculta","aún no encontrado","Mostrar todo","Borrar todas mis reglas","Toca un elemento de la página","Subir","Ocultar","Cancelar","coinc.","Mínimo","Reproductor limpio","Tema oscuro / claro","Fecha","Nombre","En vivo","Visto","Online","Mostrar solo online","Priv","Todos","Galería","Lista","Ninguna modelo coincide con el filtro","Eliminar","[Más]","[Menos]","Apoyar al autor","Invita al autor a un café","Gracias por usarlo.","Dirección copiada","No se pudo copiar","toca la dirección para verla completa","Privado","Grupo","VIP","AFK","Sin grupo","+ Nuevo grupo…","Todos los grupos","Última vez online","ahora mismo","hace {n}","min","h","d","MB","GB","Idioma","Automático","Toque: grabar · Mantener: ajustes","Ajustes de grabación","Calidad (bitrate)","Alta","Media","Baja","Ahorro","Tamaño de parte (divide el archivo)","Detener al llegar a","No","hasta","MB/min","GB/h","Ahora","parte","total","Cada parte se guarda en la memoria del teléfono hasta que se descarga; partes más pequeñas usan menos RAM.","La calidad se aplica desde la próxima parte o grabación.","Buscar por nombre…","Fijar arriba","Desfijar"],"DE":["⁞⁞ STEUERUNG","BG","TON","FOTO","AUFN.","FEHLER","KEIN VIDEO","QUAL.","PIP","VOLL","KINO","SUCHE","LINK","Start","Neu laden","Minimieren","Ausblenden (H)","M=TON F=VOLL T=KINO H=AUS","FAVS","Model nicht gefunden","Favoriten","Aktuelles hinzufügen","Die Liste ist leer.","Schon hinzugefügt!","Notiz... (#Tags)","Ausblenden","Kategorien","Meine Regeln","Noch keine Regeln.","Element wählen","Für diese Seite zurücksetzen","Alles ausblenden","Eintrag gedrückt halten, um zu sehen, was er ausblendet","noch nicht gefunden","Alles zeigen","Alle meine Regeln löschen","Tippe auf ein Element der Seite","Höher","Ausblenden","Abbrechen","Treffer","Minimal","Sauberer Player","Dunkles / helles Design","Datum","Name","Live","Zuletzt","Online","Nur Online anzeigen","Priv","Alle","Galerie","Liste","Keine Models passen zum Filter","Löschen","[Mehr]","[Weniger]","Autor unterstützen","Spendiere dem Autor einen Kaffee","Danke fürs Benutzen.","Adresse kopiert","Kopieren fehlgeschlagen","tippe auf die Adresse, um sie komplett zu sehen","Privat","Gruppe","VIP","AFK","Keine Gruppe","+ Neue Gruppe…","Alle Gruppen","Zuletzt online","gerade eben","vor {n}","Min","Std","T","MB","GB","Sprache","Automatisch","Tippen: aufnehmen · Halten: Einstellungen","Aufnahme-Einstellungen","Qualität (Bitrate)","Hoch","Mittel","Niedrig","Sparen","Teilgröße (Datei wird geteilt)","Stopp bei Gesamtgröße","Aus","bis zu","MB/Min","GB/Std","Jetzt","Teil","gesamt","Jeder Teil liegt im Speicher des Handys, bis er gespeichert wird; kleinere Teile brauchen weniger RAM.","Die Qualität gilt ab dem nächsten Teil oder der nächsten Aufnahme.","Nach Namen suchen…","Oben anheften","Anheften aufheben"],"FR":["⁞⁞ COMMANDE","BG","SON","PHOTO","REC","ERREUR","PAS DE VIDÉO","QUAL.","PIP","PLEIN","CINÉMA","RECH.","LIEN","Accueil","Recharger","Réduire","Masquer (H)","M=SON F=PLEIN T=CINÉ H=MASQUER","FAVORIS","Modèle introuvable","Favoris","Ajouter l’actuel","La liste est vide.","Déjà ajouté !","Note... (#tags)","Masquage","Catégories","Mes règles","Aucune règle pour l’instant.","Choisir un élément","Réinitialiser pour ce site","Tout masquer","Maintenez un élément pour voir ce qu’il masque","pas encore trouvé","Tout afficher","Supprimer toutes mes règles","Touchez un élément de la page","Plus haut","Masquer","Annuler","corresp.","Minimal","Lecteur épuré","Thème sombre / clair","Date","Nom","En direct","Vu","En ligne","Afficher seulement en ligne","Privé","Tous","Galerie","Liste","Aucun modèle ne correspond au filtre","Supprimer","[Plus]","[Moins]","Soutenir l’auteur","Offrir un café à l’auteur","Merci de l’utiliser.","Adresse copiée","Échec de la copie","touchez l’adresse pour l’afficher en entier","Privé","Groupe","VIP","AFK","Sans groupe","+ Nouveau groupe…","Tous les groupes","Dernière connexion","à l’instant","il y a {n}","min","h","j","Mo","Go","Langue","Auto","Toucher : enregistrer · Maintenir : réglages","Réglages d’enregistrement","Qualité (débit)","Haute","Moyenne","Basse","Éco","Taille d’une partie (fichier découpé)","Arrêter à la taille totale","Non","jusqu’à","Mo/min","Go/h","Maintenant","partie","total","Chaque partie reste dans la mémoire du téléphone jusqu’à son enregistrement ; des parties plus petites utilisent moins de RAM.","La qualité s’applique dès la prochaine partie ou le prochain enregistrement.","Rechercher par nom…","Épingler en haut","Désépingler"],"PT":["⁞⁞ CONTROLE","BG","SOM","FOTO","GRAVAR","ERRO","SEM VÍDEO","QUAL.","PIP","TELA","CINEMA","BUSCAR","LINK","Início","Recarregar","Minimizar","Ocultar (H)","M=SOM F=TELA T=CINEMA H=OCULTAR","FAVS","Modelo não encontrada","Favoritos","Adicionar atual","A lista está vazia.","Já adicionada!","Nota... (#tags)","Ocultar","Categorias","Minhas regras","Ainda sem regras.","Escolher elemento","Redefinir para este site","Ocultar tudo","Segure um item para ver o que ele oculta","ainda não encontrado","Mostrar tudo","Apagar todas as minhas regras","Toque em um elemento da página","Acima","Ocultar","Cancelar","result.","Mínimo","Player limpo","Tema escuro / claro","Data","Nome","Ao vivo","Visto","Online","Mostrar só online","Priv","Todos","Galeria","Lista","Nenhuma modelo corresponde ao filtro","Excluir","[Mais]","[Menos]","Apoiar o autor","Pague um café ao autor","Obrigado por usar.","Endereço copiado","Falha ao copiar","toque no endereço para ver completo","Privado","Grupo","VIP","AFK","Sem grupo","+ Novo grupo…","Todos os grupos","Última vez online","agora mesmo","há {n}","min","h","d","MB","GB","Idioma","Automático","Toque: gravar · Segurar: ajustes","Ajustes de gravação","Qualidade (bitrate)","Alta","Média","Baixa","Economia","Tamanho da parte (divide o arquivo)","Parar ao atingir","Não","até","MB/min","GB/h","Agora","parte","total","Cada parte fica na memória do celular até ser salva; partes menores usam menos RAM.","A qualidade vale a partir da próxima parte ou gravação.","Buscar por nome…","Fixar no topo","Desafixar"],"IT":["⁞⁞ TELECOMANDO","BG","AUDIO","FOTO","REC","ERRORE","NO VIDEO","QUAL.","PIP","SCHERMO","CINEMA","CERCA","LINK","Home","Ricarica","Riduci","Nascondi (H)","M=AUDIO F=SCHERMO T=CINEMA H=NASCONDI","PREF.","Modella non trovata","Preferiti","Aggiungi attuale","L’elenco è vuoto.","Già aggiunta!","Nota... (#tag)","Nascondi","Categorie","Le mie regole","Ancora nessuna regola.","Scegli elemento","Ripristina per questo sito","Nascondi tutto","Tieni premuto un elemento per vedere cosa nasconde","non ancora trovato","Mostra tutto","Elimina tutte le mie regole","Tocca un elemento della pagina","Su","Nascondi","Annulla","corrisp.","Minimo","Player pulito","Tema scuro / chiaro","Data","Nome","Live","Visto","Online","Mostra solo online","Priv","Tutti","Galleria","Elenco","Nessuna modella corrisponde al filtro","Elimina","[Altro]","[Meno]","Sostieni l’autore","Offri un caffè all’autore","Grazie per l’uso.","Indirizzo copiato","Copia non riuscita","tocca l’indirizzo per vederlo per intero","Privato","Gruppo","VIP","AFK","Nessun gruppo","+ Nuovo gruppo…","Tutti i gruppi","Ultimo accesso","proprio ora","{n} fa","min","h","g","MB","GB","Lingua","Automatica","Tocco: registra · Tieni premuto: impostazioni","Impostazioni di registrazione","Qualità (bitrate)","Alta","Media","Bassa","Risparmio","Dimensione parte (file diviso)","Ferma alla dimensione totale","No","fino a","MB/min","GB/h","Ora","parte","totale","Ogni parte resta nella memoria del telefono finché non viene salvata; parti più piccole usano meno RAM.","La qualità vale dalla prossima parte o registrazione.","Cerca per nome…","Fissa in alto","Sblocca"],"PL":["⁞⁞ PILOT","TŁO","DŹWIĘK","FOTO","NAGR.","BŁĄD","BRAK WIDEO","JAKOŚĆ","PIP","PEŁNY","KINO","SZUKAJ","LINK","Strona główna","Odśwież","Minimalizuj","Ukryj (H)","M=DŹWIĘK F=PEŁNY T=KINO H=UKRYJ","ULUB.","Nie znaleziono modelki","Ulubione","Dodaj bieżącą","Lista jest pusta.","Już dodano!","Notatka... (#tagi)","Ukrywanie","Kategorie","Moje reguły","Na razie brak reguł.","Wybierz element","Resetuj dla tej strony","Ukryj wszystko","Przytrzymaj pozycję, aby zobaczyć, co ukrywa","jeszcze nie znaleziono","Pokaż wszystko","Usuń wszystkie moje reguły","Dotknij elementu na stronie","Wyżej","Ukryj","Anuluj","dopas.","Minimum","Czysty odtwarzacz","Motyw ciemny / jasny","Data","Nazwa","Live","Widz.","Online","Pokaż tylko online","Priv","Wszystkie","Galeria","Lista","Brak modelek pasujących do filtra","Usuń","[Więcej]","[Mniej]","Wesprzyj autora","Postaw autorowi kawę","Dzięki, że korzystasz.","Skopiowano adres","Nie udało się skopiować","dotknij adresu, aby zobaczyć go w całości","Prywatny","Grupowy","VIP","AFK","Bez grupy","+ Nowa grupa…","Wszystkie grupy","Ostatnio online","przed chwilą","{n} temu","min","godz.","d","MB","GB","Język","Automatycznie","Dotknięcie: nagrywaj · Przytrzymanie: ustawienia","Ustawienia nagrywania","Jakość (bitrate)","Wysoka","Średnia","Niska","Oszczędna","Rozmiar części (plik jest dzielony)","Zatrzymaj przy rozmiarze","Wył.","do","MB/min","GB/godz.","Teraz","część","razem","Każda część jest w pamięci telefonu do czasu zapisu; mniejsze części zużywają mniej RAM.","Jakość obowiązuje od następnej części lub nagrania.","Szukaj po nazwie…","Przypnij na górze","Odepnij"],"TR":["⁞⁞ KUMANDA","ARKA","SES","FOTO","KAYIT","HATA","VİDEO YOK","KALİTE","PIP","TAM","SİNEMA","ARA","LİNK","Ana sayfa","Yenile","Küçült","Gizle (H)","M=SES F=TAM T=SİNEMA H=GİZLE","FAVORİ","Model bulunamadı","Favoriler","Mevcut olanı ekle","Liste boş.","Zaten eklendi!","Not... (#etiket)","Gizleme","Kategoriler","Kurallarım","Henüz kural yok.","Öğe seç","Bu site için sıfırla","Hepsini gizle","Neyi gizlediğini görmek için bir öğeye basılı tutun","henüz bulunamadı","Hepsini göster","Tüm kurallarımı sil","Sayfadaki bir öğeye dokunun","Yukarı","Gizle","İptal","eşleşme","Minimum","Temiz oynatıcı","Koyu / açık tema","Tarih","Ad","Canlı","Son","Çevrimiçi","Yalnızca çevrimiçi olanları göster","Özel","Tümü","Galeri","Liste","Filtreye uyan model yok","Sil","[Daha fazla]","[Daha az]","Yazarı destekle","Yazara bir kahve ısmarla","Kullandığın için teşekkürler.","Adres kopyalandı","Kopyalanamadı","tamamını görmek için adrese dokun","Özel","Grup","VIP","AFK","Grupsuz","+ Yeni grup…","Tüm gruplar","Son çevrimiçi","az önce","{n} önce","dk","sa","g","MB","GB","Dil","Otomatik","Dokun: kaydet · Basılı tut: ayarlar","Kayıt ayarları","Kalite (bit hızı)","Yüksek","Orta","Düşük","Tasarruf","Parça boyutu (dosya bölünür)","Toplam boyutta durdur","Kapalı","en fazla","MB/dk","GB/sa","Şimdi","parça","toplam","Her parça kaydedilene kadar telefonun belleğinde tutulur; küçük parçalar daha az RAM kullanır.","Kalite bir sonraki parça veya kayıttan itibaren geçerli olur.","İsme göre ara…","En üste sabitle","Sabitlemeyi kaldır"],"NL":["⁞⁞ BEDIENING","ACHT.","GELUID","FOTO","OPN.","FOUT","GEEN VIDEO","KWAL.","PIP","VOL","THEATER","ZOEK","LINK","Home","Herladen","Minimaliseren","Verbergen (H)","M=GELUID F=VOL T=THEATER H=VERBERG","FAVO'S","Model niet gevonden","Favorieten","Huidige toevoegen","De lijst is leeg.","Al toegevoegd!","Notitie... (#tags)","Verbergen","Categorieën","Mijn regels","Nog geen regels.","Element kiezen","Resetten voor deze site","Alles verbergen","Houd een item ingedrukt om te zien wat het verbergt","nog niet gevonden","Alles tonen","Al mijn regels wissen","Tik op een element op de pagina","Hoger","Verbergen","Annuleren","treffers","Minimaal","Schone speler","Donker / licht thema","Datum","Naam","Live","Gezien","Online","Alleen online tonen","Priv","Alle","Galerij","Lijst","Geen modellen voldoen aan het filter","Verwijderen","[Meer]","[Minder]","Steun de auteur","Trakteer de auteur op een koffie","Bedankt voor het gebruik.","Adres gekopieerd","Kopiëren mislukt","tik op het adres om het volledig te zien","Privé","Groep","VIP","AFK","Geen groep","+ Nieuwe groep…","Alle groepen","Laatst online gezien","zojuist","{n} geleden","min","u","d","MB","GB","Taal","Auto","Tik: opnemen · Vasthouden: instellingen","Opname-instellingen","Kwaliteit (bitrate)","Hoog","Gemiddeld","Laag","Besparen","Deelgrootte (bestand wordt gesplitst)","Stop bij totale grootte","Uit","tot","MB/min","GB/u","Nu","deel","totaal","Een deel blijft in het telefoongeheugen tot het is opgeslagen, dus kleinere delen gebruiken minder RAM.","De kwaliteit geldt vanaf het volgende deel of de volgende opname.","Zoeken op naam…","Bovenaan vastzetten","Losmaken"],"CS":["⁞⁞ OVLÁDÁNÍ","POZADÍ","ZVUK","FOTO","NAHR.","CHYBA","BEZ VIDEA","KVAL.","PIP","CELÁ","KINO","HLEDAT","ODKAZ","Domů","Obnovit","Minimalizovat","Skrýt (H)","M=ZVUK F=CELÁ T=KINO H=SKRÝT","OBLÍBENÉ","Modelka nenalezena","Oblíbené","Přidat aktuální","Seznam je prázdný.","Už přidáno!","Poznámka... (#tagy)","Skrývání","Kategorie","Moje pravidla","Zatím žádná pravidla.","Vybrat prvek","Obnovit pro tento web","Skrýt vše","Podržte položku, abyste viděli, co skrývá","zatím nenalezeno","Zobrazit vše","Smazat všechna moje pravidla","Klepněte na prvek na stránce","Výše","Skrýt","Zrušit","shod","Minimum","Čistý přehrávač","Tmavý / světlý motiv","Datum","Jméno","Live","Viděna","Online","Zobrazit jen online","Priv","Vše","Galerie","Seznam","Filtru neodpovídá žádná modelka","Smazat","[Více]","[Méně]","Podpořit autora","Kupte autorovi kávu","Děkuji, že to používáte.","Adresa zkopírována","Kopírování se nezdařilo","klepnutím na adresu ji zobrazíte celou","Privát","Skupina","VIP","AFK","Bez skupiny","+ Nová skupina…","Všechny skupiny","Naposledy online","právě teď","před {n}","min","h","d","MB","GB","Jazyk","Auto","Klepnutí: nahrávat · Podržení: nastavení","Nastavení nahrávání","Kvalita (bitrate)","Vysoká","Střední","Nízká","Úsporná","Velikost části (soubor se dělí)","Zastavit při celkové velikosti","Vyp.","až","MB/min","GB/h","Nyní","část","celkem","Část zůstává v paměti telefonu, dokud se neuloží, takže menší části šetří RAM.","Kvalita platí od další části nebo nahrávky.","Hledat podle jména…","Připnout nahoru","Odepnout"],"RO":["⁞⁞ COMENZI","FUNDAL","SUNET","FOTO","ÎNREG.","EROARE","FĂRĂ VIDEO","CALIT.","PIP","ECRAN","TEATRU","CAUTĂ","LINK","Acasă","Reîncarcă","Minimizează","Ascunde (H)","M=SUNET F=ECRAN T=TEATRU H=ASCUNDE","FAVORITE","Modelul nu a fost găsit","Favorite","Adaugă curentul","Lista este goală.","Deja adăugat!","Notă... (#taguri)","Ascundere","Categorii","Regulile mele","Încă nu există reguli.","Alege element","Resetează pentru acest site","Ascunde tot","Ține apăsat un element ca să vezi ce ascunde","încă negăsit","Arată tot","Șterge toate regulile mele","Atinge un element de pe pagină","Mai sus","Ascunde","Anulează","potriviri","Minim","Player curat","Temă închisă / deschisă","Data","Nume","Live","Văzută","Online","Arată doar online","Priv","Toate","Galerie","Listă","Niciun model nu se potrivește filtrului","Șterge","[Mai mult]","[Mai puțin]","Susține autorul","Cumpără-i autorului o cafea","Mulțumesc că folosești scriptul.","Adresă copiată","Copierea a eșuat","atinge adresa ca să o vezi completă","Privat","Grup","VIP","AFK","Fără grup","+ Grup nou…","Toate grupurile","Ultima oară online","chiar acum","acum {n}","min","h","z","MB","GB","Limbă","Auto","Atingere: înregistrează · Apăsare lungă: setări","Setări de înregistrare","Calitate (bitrate)","Înaltă","Medie","Scăzută","Economie","Mărimea părții (fișierul se împarte)","Oprește la mărimea totală","Oprit","până la","MB/min","GB/h","Acum","parte","total","O parte rămâne în memoria telefonului până se salvează, deci părțile mici folosesc mai puțină RAM.","Calitatea se aplică de la următoarea parte sau înregistrare.","Caută după nume…","Fixează sus","Anulează fixarea"],"HU":["⁞⁞ VEZÉRLŐ","HÁTTÉR","HANG","FOTÓ","FELV.","HIBA","NINCS VIDEÓ","MIN.","PIP","TELJES","MOZI","KERESÉS","LINK","Kezdőlap","Újratöltés","Kicsinyítés","Elrejtés (H)","M=HANG F=TELJES T=MOZI H=ELREJT","KEDVENCEK","A modell nem található","Kedvencek","Jelenlegi hozzáadása","A lista üres.","Már hozzá van adva!","Jegyzet... (#címkék)","Elrejtés","Kategóriák","Saját szabályok","Még nincsenek szabályok.","Elem kiválasztása","Visszaállítás ezen az oldalon","Mindent elrejt","Tartsd nyomva a tételt, hogy lásd, mit rejt el","még nem található","Mindent mutat","Összes saját szabály törlése","Érints meg egy elemet az oldalon","Feljebb","Elrejtés","Mégse","találat","Minimum","Tiszta lejátszó","Sötét / világos téma","Dátum","Név","Live","Látva","Online","Csak az online-ok","Priv","Mind","Galéria","Lista","Nincs a szűrőnek megfelelő modell","Törlés","[Több]","[Kevesebb]","A szerző támogatása","Fizess egy kávét a szerzőnek","Köszönöm, hogy használod.","Cím másolva","A másolás nem sikerült","érintsd meg a címet a teljes megjelenítéshez","Privát","Csoport","VIP","AFK","Nincs csoport","+ Új csoport…","Minden csoport","Utoljára online","épp most","{n} ezelőtt","perc","ó","n","MB","GB","Nyelv","Auto","Érintés: felvétel · Nyomva tartás: beállítások","Felvétel beállításai","Minőség (bitráta)","Magas","Közepes","Alacsony","Takarékos","Részméret (a fájl darabolódik)","Leállítás összméretnél","Ki","legfeljebb","MB/perc","GB/ó","Most","rész","összes","Egy rész a telefon memóriájában marad a mentésig, ezért a kisebb részek kevesebb RAM-ot használnak.","A minőség a következő résztől vagy felvételtől érvényes.","Keresés név szerint…","Kitűzés felülre","Kitűzés megszüntetése"],"BG":["⁞⁞ ПУЛТ","ФОН","ЗВУК","СНИМКА","ЗАПИС","ГРЕШКА","НЯМА ВИДЕО","КАЧ-ВО","PIP","ЕКРАН","ТЕАТЪР","ТЪРСЕНЕ","ЛИНК","Начало","Рестарт","Свиване","Скриване (H)","M=ЗВУК F=ЕКРАН T=ТЕАТЪР H=СКРИЙ","ЛЮБИМИ","Моделът не е намерен","Любими","Добави текущия","Списъкът е празен.","Вече е добавен!","Бележка... (#тагове)","Скриване","Категории","Моите правила","Все още няма правила.","Избор на елемент","Нулиране за този сайт","Скрий всичко","Задръжте елемент, за да видите какво скрива","още не е намерено","Покажи всичко","Изтрий всички мои правила","Докоснете елемент на страницата","По-горе","Скрий","Отказ","съвп.","Минимум","Чист плеър","Тъмна / светла тема","Дата","Име","Лайв","Видяна","Онлайн","Само онлайн","Прив","Всички","Галерия","Списък","Няма модели по филтъра","Изтрий","[Още]","[По-малко]","Подкрепи автора","Почерпи автора с кафе","Благодаря, че го ползвате.","Адресът е копиран","Неуспешно копиране","докоснете адреса, за да го видите изцяло","Приват","Група","VIP","AFK","Без група","+ Нова група…","Всички групи","Последно онлайн","току-що","преди {n}","мин","ч","д","МБ","ГБ","Език","Авто","Докосване: запис · Задържане: настройки","Настройки на записа","Качество (битрейт)","Високо","Средно","Ниско","Икономия","Размер на част (файлът се дели)","Спри при общ размер","Изкл.","до","МБ/мин","ГБ/ч","Сега","част","общо","Частта стои в паметта на телефона, докато не бъде запазена, затова по-малките части ползват по-малко RAM.","Качеството важи от следващата част или запис.","Търсене по име…","Закрепи най-горе","Откачи"],"EL":["⁞⁞ ΧΕΙΡΙΣΤΗΡΙΟ","ΦΟΝΤΟ","ΗΧΟΣ","ΦΩΤΟ","ΕΓΓΡ.","ΣΦΑΛΜΑ","ΧΩΡΙΣ ΒΙΝΤΕΟ","ΠΟΙΟΤ.","PIP","ΠΛΗΡΗΣ","ΘΕΑΤΡΟ","ΑΝΑΖΗΤ.","LINK","Αρχική","Επανάληψη","Ελαχιστοποίηση","Απόκρυψη (H)","M=ΗΧΟΣ F=ΠΛΗΡΗΣ T=ΘΕΑΤΡΟ H=ΚΡΥΨΕ","ΑΓΑΠΗΜΕΝΑ","Το μοντέλο δεν βρέθηκε","Αγαπημένα","Προσθήκη τρέχοντος","Η λίστα είναι άδεια.","Έχει ήδη προστεθεί!","Σημείωση... (#ετικέτες)","Απόκρυψη","Κατηγορίες","Οι κανόνες μου","Δεν υπάρχουν κανόνες ακόμα.","Επιλογή στοιχείου","Επαναφορά για αυτόν τον ιστότοπο","Απόκρυψη όλων","Κρατήστε πατημένο ένα στοιχείο για να δείτε τι κρύβει","δεν βρέθηκε ακόμα","Εμφάνιση όλων","Διαγραφή όλων των κανόνων μου","Αγγίξτε ένα στοιχείο της σελίδας","Πιο πάνω","Απόκρυψη","Ακύρωση","αντιστ.","Ελάχιστο","Καθαρός player","Σκούρο / ανοιχτό θέμα","Ημ/νία","Όνομα","Live","Τελευταία","Online","Μόνο online","Priv","Όλα","Γκαλερί","Λίστα","Κανένα μοντέλο δεν ταιριάζει με το φίλτρο","Διαγραφή","[Περισσότερα]","[Λιγότερα]","Υποστήριξη του δημιουργού","Κεράστε τον δημιουργό έναν καφέ","Ευχαριστώ που το χρησιμοποιείτε.","Η διεύθυνση αντιγράφηκε","Η αντιγραφή απέτυχε","αγγίξτε τη διεύθυνση για να τη δείτε ολόκληρη","Private","Group","VIP","AFK","Χωρίς ομάδα","+ Νέα ομάδα…","Όλες οι ομάδες","Τελευταία φορά online","μόλις τώρα","πριν {n}","λεπ.","ώ","μ","MB","GB","Γλώσσα","Αυτόματο","Πάτημα: εγγραφή · Παρατεταμένο: ρυθμίσεις","Ρυθμίσεις εγγραφής","Ποιότητα (bitrate)","Υψηλή","Μεσαία","Χαμηλή","Οικονομία","Μέγεθος τμήματος (το αρχείο σπάει)","Διακοπή στο συνολικό μέγεθος","Off","έως","MB/λεπτό","GB/ώρα","Τώρα","τμήμα","σύνολο","Ένα τμήμα μένει στη μνήμη του τηλεφώνου μέχρι να αποθηκευτεί, οπότε τα μικρότερα τμήματα χρησιμοποιούν λιγότερη RAM.","Η ποιότητα ισχύει από το επόμενο τμήμα ή την επόμενη εγγραφή.","Αναζήτηση με όνομα…","Καρφίτσωμα στην κορυφή","Ξεκαρφίτσωμα"],"JA":["⁞⁞ 操作パネル","背景","音声","撮影","録画","エラー","動画なし","画質","PIP","全画面","シアター","検索","リンク","ホーム","再読込","最小化","非表示 (H)","M=音声 F=全画面 T=シアター H=非表示","お気に入り","モデルが見つかりません","お気に入り","現在のものを追加","リストは空です。","追加済みです!","メモ... (#タグ)","非表示設定","カテゴリ","マイルール","ルールはまだありません。","要素を選択","このサイトをリセット","すべて非表示","項目を長押しすると、何を隠すか確認できます","まだ見つかりません","すべて表示","マイルールをすべて削除","ページ上の要素をタップしてください","上の階層","非表示","キャンセル","件一致","最小","クリーンプレーヤー","ダーク / ライトテーマ","日付","名前","ライブ","最終","オンライン","オンラインのみ表示","プライベート","すべて","ギャラリー","リスト","条件に合うモデルがいません","削除","[もっと見る]","[閉じる]","作者を支援","作者にコーヒーをおごる","ご利用ありがとうございます。","アドレスをコピーしました","コピーに失敗しました","アドレスをタップすると全体が表示されます","プライベート","グループ","VIP","AFK","グループなし","+ 新しいグループ…","すべてのグループ","最終オンライン","たった今","{n}前","分","時間","日","MB","GB","言語","自動","タップ: 録画 · 長押し: 設定","録画設定","画質(ビットレート)","高","中","低","節約","分割サイズ(ファイルを分割)","合計サイズで停止","オフ","最大","MB/分","GB/時","現在","パート","合計","各パートは保存されるまでスマホのメモリに残るため、小さいパートほどRAMを節約できます。","画質は次のパートまたは次の録画から適用されます。","名前で検索…","先頭に固定","固定を解除"],"ZH":["⁞⁞ 控制面板","后台","声音","截图","录制","错误","无视频","画质","PIP","全屏","影院","搜索","链接","主页","重新加载","最小化","隐藏 (H)","M=声音 F=全屏 T=影院 H=隐藏","收藏","未找到主播","收藏夹","添加当前","列表为空。","已添加!","备注... (#标签)","隐藏设置","分类","我的规则","暂无规则。","选择元素","重置此网站","全部隐藏","长按项目可查看其隐藏的内容","暂未找到","全部显示","删除我的所有规则","点击页面上的元素","上一级","隐藏","取消","个匹配","最简","纯净播放器","深色 / 浅色主题","日期","名称","直播","最近","在线","仅显示在线","私密","全部","图库","列表","没有符合筛选条件的主播","删除","[展开]","[收起]","支持作者","请作者喝杯咖啡","感谢使用。","地址已复制","复制失败","点击地址可查看完整内容","私密","群组","VIP","AFK","无分组","+ 新建分组…","所有分组","最后在线","刚刚","{n}前","分钟","小时","天","MB","GB","语言","自动","点按:录制 · 长按:设置","录制设置","画质(码率)","高","中","低","省空间","分段大小(文件会被拆分)","达到总大小时停止","关闭","最多","MB/分钟","GB/小时","当前","段","总计","每一段在保存前都会留在手机内存中,因此分段越小占用的 RAM 越少。","画质将从下一段或下一次录制开始生效。","按名称搜索…","置顶","取消置顶"],"KO":["⁞⁞ 컨트롤","배경","소리","캡처","녹화","오류","영상 없음","화질","PIP","전체","극장","검색","링크","홈","새로고침","최소화","숨기기 (H)","M=소리 F=전체 T=극장 H=숨김","즐겨찾기","모델을 찾을 수 없습니다","즐겨찾기","현재 추가","목록이 비어 있습니다.","이미 추가됨!","메모... (#태그)","숨기기","카테고리","내 규칙","아직 규칙이 없습니다.","요소 선택","이 사이트 초기화","모두 숨기기","항목을 길게 누르면 무엇을 숨기는지 볼 수 있습니다","아직 찾지 못함","모두 표시","내 규칙 모두 삭제","페이지의 요소를 탭하세요","상위","숨기기","취소","개 일치","최소","깔끔한 플레이어","다크 / 라이트 테마","날짜","이름","라이브","최근","온라인","온라인만 표시","프라이빗","전체","갤러리","목록","필터에 맞는 모델이 없습니다","삭제","[더보기]","[접기]","제작자 후원","제작자에게 커피 한 잔 사주기","이용해 주셔서 감사합니다.","주소가 복사되었습니다","복사 실패","주소를 탭하면 전체가 표시됩니다","프라이빗","그룹","VIP","AFK","그룹 없음","+ 새 그룹…","모든 그룹","마지막 온라인","방금","{n} 전","분","시간","일","MB","GB","언어","자동","탭: 녹화 · 길게 누르기: 설정","녹화 설정","화질(비트레이트)","높음","보통","낮음","절약","파트 크기(파일 분할)","총 크기에서 중지","끔","최대","MB/분","GB/시간","현재","파트","전체","각 파트는 저장되기 전까지 휴대폰 메모리에 남아 있으므로, 파트가 작을수록 RAM을 적게 사용합니다.","화질은 다음 파트 또는 다음 녹화부터 적용됩니다.","이름으로 검색…","맨 위에 고정","고정 해제"],"HE":["⁞⁞ בקרה","רקע","קול","צילום","הקלטה","שגיאה","אין וידאו","איכות","PIP","מסך מלא","תיאטרון","חיפוש","קישור","בית","רענון","מזעור","הסתר (H)","M=קול F=מסך מלא T=תיאטרון H=הסתר","מועדפים","המודל לא נמצא","מועדפים","הוסף את הנוכחי","הרשימה ריקה.","כבר נוסף!","הערה... (#תגיות)","הסתרה","קטגוריות","הכללים שלי","אין כללים עדיין.","בחר אלמנט","איפוס עבור אתר זה","הסתר הכול","החזק פריט לחוץ כדי לראות מה הוא מסתיר","עדיין לא נמצא","הצג הכול","מחק את כל הכללים שלי","הקש על אלמנט בדף","למעלה","הסתר","ביטול","התאמות","מינימלי","נגן נקי","ערכת נושא כהה / בהירה","תאריך","שם","לייב","נראה","אונליין","הצג רק אונליין","פרטי","הכול","גלריה","רשימה","אין מודלים התואמים לסינון","מחק","[עוד]","[פחות]","תמיכה ביוצר","קנה ליוצר כוס קפה","תודה על השימוש.","הכתובת הועתקה","ההעתקה נכשלה","הקש על הכתובת כדי לראות אותה במלואה","פרטי","קבוצה","VIP","AFK","ללא קבוצה","+ קבוצה חדשה…","כל הקבוצות","נראה אונליין לאחרונה","הרגע","לפני {n}","דק׳","שע׳","י׳","MB","GB","שפה","אוטומטי","הקשה: הקלטה · לחיצה ארוכה: הגדרות","הגדרות הקלטה","איכות (ביטרייט)","גבוהה","בינונית","נמוכה","חיסכון","גודל חלק (הקובץ מתפצל)","עצור בגודל כולל","כבוי","עד","MB/דקה","GB/שעה","עכשיו","חלק","סה״כ","כל חלק נשאר בזיכרון הטלפון עד שנשמר, ולכן חלקים קטנים יותר צורכים פחות RAM.","האיכות תחול מהחלק הבא או מההקלטה הבאה.","חיפוש לפי שם…","הצמד למעלה","בטל הצמדה"],"AR":["⁞⁞ التحكم","الخلفية","الصوت","لقطة","تسجيل","خطأ","لا فيديو","الجودة","PIP","ملء الشاشة","المسرح","بحث","رابط","الرئيسية","تحديث","تصغير","إخفاء (H)","M=الصوت F=ملء الشاشة T=المسرح H=إخفاء","المفضلة","لم يتم العثور على الموديل","المفضلة","إضافة الحالي","القائمة فارغة.","تمت الإضافة مسبقًا!","ملاحظة... (#وسوم)","الإخفاء","الفئات","قواعدي","لا توجد قواعد بعد.","اختيار عنصر","إعادة الضبط لهذا الموقع","إخفاء الكل","اضغط مطولًا على عنصر لترى ما الذي يخفيه","لم يُعثر عليه بعد","إظهار الكل","حذف جميع قواعدي","اضغط على عنصر في الصفحة","أعلى","إخفاء","إلغاء","تطابق","الحد الأدنى","مشغّل نظيف","مظهر داكن / فاتح","التاريخ","الاسم","مباشر","آخر ظهور","متصل","إظهار المتصلين فقط","خاص","الكل","معرض","قائمة","لا يوجد موديل يطابق الفلتر","حذف","[المزيد]","[أقل]","ادعم المطوّر","اشترِ للمطوّر فنجان قهوة","شكرًا لاستخدامك الأداة.","تم نسخ العنوان","فشل النسخ","اضغط على العنوان لعرضه كاملًا","خاص","مجموعة","VIP","AFK","بدون مجموعة","+ مجموعة جديدة…","كل المجموعات","آخر ظهور على الإنترنت","الآن","منذ {n}","د","س","ي","MB","GB","اللغة","تلقائي","نقرة: تسجيل · ضغط مطوّل: الإعدادات","إعدادات التسجيل","الجودة (معدل البت)","عالية","متوسطة","منخفضة","توفير","حجم الجزء (يُقسَّم الملف)","إيقاف عند الحجم الإجمالي","إيقاف","حتى","MB/د","GB/س","الآن","جزء","الإجمالي","يبقى كل جزء في ذاكرة الهاتف حتى يُحفظ، لذا تستهلك الأجزاء الأصغر ذاكرة RAM أقل.","تُطبَّق الجودة من الجزء التالي أو التسجيل التالي.","البحث بالاسم…","تثبيت في الأعلى","إلغاء التثبيت"],"HI":["⁞⁞ नियंत्रण","बैकग्राउंड","आवाज़","स्क्रीनशॉट","रिकॉर्ड","त्रुटि","वीडियो नहीं","क्वालिटी","PIP","फुलस्क्रीन","थिएटर","खोज","लिंक","होम","रीलोड","छोटा करें","छिपाएँ (H)","M=आवाज़ F=फुलस्क्रीन T=थिएटर H=छिपाएँ","पसंदीदा","मॉडल नहीं मिली","पसंदीदा","मौजूदा जोड़ें","सूची खाली है।","पहले ही जोड़ा जा चुका है!","नोट... (#टैग)","छिपाना","श्रेणियाँ","मेरे नियम","अभी कोई नियम नहीं।","एलिमेंट चुनें","इस साइट के लिए रीसेट करें","सब छिपाएँ","कोई आइटम दबाए रखें, देखने के लिए कि वह क्या छिपाता है","अभी नहीं मिला","सब दिखाएँ","मेरे सभी नियम हटाएँ","पेज पर किसी एलिमेंट को टैप करें","ऊपर","छिपाएँ","रद्द करें","मिलान","न्यूनतम","साफ़ प्लेयर","डार्क / लाइट थीम","तारीख़","नाम","लाइव","आख़िरी बार","ऑनलाइन","सिर्फ़ ऑनलाइन दिखाएँ","प्राइवेट","सभी","गैलरी","सूची","फ़िल्टर से कोई मॉडल मेल नहीं खाती","हटाएँ","[और]","[कम]","लेखक का समर्थन करें","लेखक को एक कॉफ़ी पिलाएँ","इस्तेमाल करने के लिए धन्यवाद।","पता कॉपी हो गया","कॉपी नहीं हो सका","पूरा पता देखने के लिए उस पर टैप करें","प्राइवेट","ग्रुप","VIP","AFK","कोई ग्रुप नहीं","+ नया ग्रुप…","सभी ग्रुप","आख़िरी बार ऑनलाइन","अभी-अभी","{n} पहले","मिनट","घं","दिन","MB","GB","भाषा","ऑटो","टैप: रिकॉर्ड · दबाए रखें: सेटिंग्स","रिकॉर्डिंग सेटिंग्स","क्वालिटी (बिटरेट)","उच्च","मध्यम","कम","बचत","पार्ट का आकार (फ़ाइल बँटती है)","कुल आकार पर रोकें","बंद","तक","MB/मिनट","GB/घंटा","अभी","पार्ट","कुल","हर पार्ट सेव होने तक फ़ोन की मेमोरी में रहता है, इसलिए छोटे पार्ट कम RAM इस्तेमाल करते हैं।","क्वालिटी अगले पार्ट या अगली रिकॉर्डिंग से लागू होगी।","नाम से खोजें…","ऊपर पिन करें","पिन हटाएँ"],"ID":["⁞⁞ KONTROL","LATAR","SUARA","FOTO","REKAM","ERROR","TANPA VIDEO","KUALITAS","PIP","PENUH","TEATER","CARI","TAUTAN","Beranda","Muat ulang","Perkecil","Sembunyikan (H)","M=SUARA F=PENUH T=TEATER H=SEMBUNYI","FAVORIT","Model tidak ditemukan","Favorit","Tambah yang sekarang","Daftar kosong.","Sudah ditambahkan!","Catatan... (#tag)","Penyembunyian","Kategori","Aturan saya","Belum ada aturan.","Pilih elemen","Setel ulang untuk situs ini","Sembunyikan semua","Tahan item untuk melihat apa yang disembunyikannya","belum ditemukan","Tampilkan semua","Hapus semua aturan saya","Ketuk elemen di halaman","Naik","Sembunyikan","Batal","cocok","Minimal","Pemutar bersih","Tema gelap / terang","Tanggal","Nama","Live","Terlihat","Online","Tampilkan hanya online","Priv","Semua","Galeri","Daftar","Tidak ada model yang cocok dengan filter","Hapus","[Selengkapnya]","[Lebih sedikit]","Dukung pembuat","Traktir pembuat secangkir kopi","Terima kasih telah menggunakannya.","Alamat disalin","Gagal menyalin","ketuk alamat untuk melihatnya utuh","Privat","Grup","VIP","AFK","Tanpa grup","+ Grup baru…","Semua grup","Terakhir online","baru saja","{n} lalu","mnt","j","h","MB","GB","Bahasa","Otomatis","Ketuk: rekam · Tahan: pengaturan","Pengaturan rekaman","Kualitas (bitrate)","Tinggi","Sedang","Rendah","Hemat","Ukuran bagian (file dipecah)","Berhenti pada ukuran total","Mati","hingga","MB/mnt","GB/j","Sekarang","bagian","total","Satu bagian tetap di memori ponsel sampai disimpan, jadi bagian yang lebih kecil memakai lebih sedikit RAM.","Kualitas berlaku mulai bagian atau rekaman berikutnya.","Cari berdasarkan nama…","Sematkan di atas","Lepas sematan"],"VI":["⁞⁞ ĐIỀU KHIỂN","NỀN","ÂM","CHỤP","GHI","LỖI","KHÔNG VIDEO","CHẤT LƯỢNG","PIP","TOÀN MH","RẠP","TÌM","LIÊN KẾT","Trang chủ","Tải lại","Thu nhỏ","Ẩn (H)","M=ÂM F=TOÀN MH T=RẠP H=ẨN","YÊU THÍCH","Không tìm thấy model","Yêu thích","Thêm mục hiện tại","Danh sách trống.","Đã thêm rồi!","Ghi chú... (#thẻ)","Ẩn","Danh mục","Quy tắc của tôi","Chưa có quy tắc.","Chọn phần tử","Đặt lại cho trang này","Ẩn tất cả","Giữ một mục để xem nó ẩn gì","chưa tìm thấy","Hiện tất cả","Xóa tất cả quy tắc của tôi","Chạm vào một phần tử trên trang","Lên","Ẩn","Hủy","khớp","Tối thiểu","Trình phát sạch","Giao diện tối / sáng","Ngày","Tên","Live","Lần cuối","Online","Chỉ hiện online","Riêng","Tất cả","Thư viện","Danh sách","Không có model khớp bộ lọc","Xóa","[Thêm]","[Ít hơn]","Ủng hộ tác giả","Mời tác giả một ly cà phê","Cảm ơn bạn đã sử dụng.","Đã sao chép địa chỉ","Sao chép thất bại","chạm vào địa chỉ để xem đầy đủ","Riêng tư","Nhóm","VIP","AFK","Không nhóm","+ Nhóm mới…","Tất cả nhóm","Online lần cuối","vừa xong","{n} trước","phút","giờ","ngày","MB","GB","Ngôn ngữ","Tự động","Chạm: ghi · Giữ: cài đặt","Cài đặt ghi hình","Chất lượng (bitrate)","Cao","Vừa","Thấp","Tiết kiệm","Kích thước phần (tệp được chia)","Dừng ở tổng dung lượng","Tắt","tối đa","MB/phút","GB/giờ","Hiện tại","phần","tổng","Mỗi phần nằm trong bộ nhớ điện thoại cho đến khi được lưu, nên phần nhỏ hơn dùng ít RAM hơn.","Chất lượng áp dụng từ phần hoặc bản ghi tiếp theo.","Tìm theo tên…","Ghim lên đầu","Bỏ ghim"],"TH":["⁞⁞ ควบคุม","พื้นหลัง","เสียง","แคป","อัด","ผิดพลาด","ไม่มีวิดีโอ","คุณภาพ","PIP","เต็มจอ","โรงหนัง","ค้นหา","ลิงก์","หน้าแรก","โหลดใหม่","ย่อ","ซ่อน (H)","M=เสียง F=เต็มจอ T=โรงหนัง H=ซ่อน","รายการโปรด","ไม่พบโมเดล","รายการโปรด","เพิ่มรายการปัจจุบัน","รายการว่างเปล่า","เพิ่มไว้แล้ว!","บันทึก... (#แท็ก)","การซ่อน","หมวดหมู่","กฎของฉัน","ยังไม่มีกฎ","เลือกองค์ประกอบ","รีเซ็ตสำหรับเว็บนี้","ซ่อนทั้งหมด","กดค้างที่รายการเพื่อดูว่าซ่อนอะไร","ยังไม่พบ","แสดงทั้งหมด","ลบกฎทั้งหมดของฉัน","แตะองค์ประกอบบนหน้าเว็บ","ขึ้น","ซ่อน","ยกเลิก","ตรงกัน","น้อยที่สุด","เครื่องเล่นสะอาด","ธีมมืด / สว่าง","วันที่","ชื่อ","ไลฟ์","ล่าสุด","ออนไลน์","แสดงเฉพาะออนไลน์","ส่วนตัว","ทั้งหมด","แกลเลอรี","รายการ","ไม่มีโมเดลที่ตรงกับตัวกรอง","ลบ","[เพิ่มเติม]","[น้อยลง]","สนับสนุนผู้สร้าง","เลี้ยงกาแฟผู้สร้างสักแก้ว","ขอบคุณที่ใช้งาน","คัดลอกที่อยู่แล้ว","คัดลอกไม่สำเร็จ","แตะที่อยู่เพื่อดูแบบเต็ม","ส่วนตัว","กลุ่ม","VIP","AFK","ไม่มีกลุ่ม","+ กลุ่มใหม่…","ทุกกลุ่ม","ออนไลน์ล่าสุด","เมื่อสักครู่","{n}ที่แล้ว","นาที","ชม.","วัน","MB","GB","ภาษา","อัตโนมัติ","แตะ: อัด · กดค้าง: ตั้งค่า","การตั้งค่าการอัด","คุณภาพ (บิตเรต)","สูง","กลาง","ต่ำ","ประหยัด","ขนาดแต่ละส่วน (ไฟล์จะถูกแบ่ง)","หยุดเมื่อถึงขนาดรวม","ปิด","สูงสุด","MB/นาที","GB/ชม.","ตอนนี้","ส่วน","รวม","แต่ละส่วนจะอยู่ในหน่วยความจำโทรศัพท์จนกว่าจะบันทึก ส่วนที่เล็กกว่าจึงใช้ RAM น้อยกว่า","คุณภาพจะมีผลตั้งแต่ส่วนถัดไปหรือการอัดครั้งถัดไป","ค้นหาตามชื่อ…","ปักหมุดไว้บนสุด","เลิกปักหมุด"]}},"HIDE":{"k":["hdr_m","hdr_d","seotitle","chat_tips","chat_topic","chat_boost","tabs","ftr","promo","lastview","joinpop","tips","modelchat","games","popups","actions","balance","chathdr","tipking","below","wm","age18"],"v":{"UK":[["Верх сайту","Логотип, меню, кнопки входу"],["Шапка сайту (ПК)","Верхня панель на комп’ютері"],["Заголовок-реклама","Рядок із SEO-заголовком над списком"],["Чайові в чаті","Повідомлення «подарував токени», меню чайових"],["Тема кімнати","Довгий опис «Тема: …» на початку чату"],["Бусти в чаті","Плашки «підняв модель на N секунд» (FAN BOOSTED)"],["Вкладки та сортування","Дівчата/пари, фільтри, значок сортування"],["Низ сторінки","Футер, соцмережі, SEO-текст"],["Реклама та банери","Банери, промо, плашка «Приєднуйся» на плеєрі, застосунок"],["Плашка «Продовжити перегляд»","Кнопка на превʼю останньої моделі"],["Вікно реєстрації","Спливаюча форма «Створіть акаунт»"],["Підказки в чаті","Спливаючі підказки та сповіщення"],["Спливаючий чат моделі","Рожеве віконце з автопривітанням моделі внизу"],["Кнопка «Ігри»","Іконка геймпада в червоній панелі"],["Спливаючі вікна","Вибір чату, група, підглядання"],["Кнопки «Приват / Чайові»","Сині (на ПК зелені) кнопки під червоною панеллю"],["Баланс і меню (ПК)","Баланс і навігація на комп’ютері"],["Плашка «Чат із …»","Рядок «Безкоштовний чат із …» і король чайових"],["Король чайових","Рядок короля та вікна чайових"],["Панель під плеєром (ПК)","Блок кнопок під відео"],["Водяний знак (ПК)","Логотип поверх відео"],["Вікно «Старше 18»","Заставка «Заходь, ТІЛЬКИ якщо тобі вже є 18»"]],"ES":[["Parte superior del sitio","Logo, menú, botones de acceso"],["Cabecera del sitio (PC)","Barra superior en ordenador"],["Título publicitario","Línea de título SEO sobre la lista"],["Propinas en el chat","Mensajes de «dio tokens» y menú de propinas"],["Tema de la sala","Bloque largo «Tema: …» al inicio del chat"],["Boosts en el chat","Tarjetas de «impulsó a la modelo N segundos»"],["Pestañas y orden","Chicas/parejas, filtros, icono de orden"],["Pie de página","Pie, redes sociales, texto SEO"],["Anuncios y banners","Banners, promos, franja «Únete» sobre el reproductor, app"],["Marca «Seguir viendo»","Botón sobre la miniatura de la última modelo"],["Ventana de registro","Formulario emergente «Crea una cuenta»"],["Consejos del chat","Avisos y notificaciones emergentes"],["Chat emergente de la modelo","Ventana rosa con el saludo automático abajo"],["Botón «Juegos»","Icono de mando en la barra roja"],["Ventanas emergentes","Elección de chat, grupo, voyeur"],["Botones «Privado / Propinas»","Botones azules (verdes en PC) bajo la barra roja"],["Saldo y menú (PC)","Saldo y navegación en ordenador"],["Barra «Chat con …»","Franja «Chat gratis con …» y rey de propinas"],["Rey de propinas","Franja del rey y ventanas de propinas"],["Barra bajo el reproductor (PC)","Fila de botones bajo el vídeo"],["Marca de agua (PC)","Logo sobre el vídeo"],["Aviso +18","Pantalla de entrada «Solo mayores de 18»"]],"DE":[["Seitenkopf","Logo, Menü, Anmelde-Buttons"],["Seitenkopf (PC)","Obere Leiste am Computer"],["Werbe-Überschrift","SEO-Überschrift über der Liste"],["Trinkgelder im Chat","Meldungen „hat Tokens gegeben“, Tip-Menü"],["Raumthema","Langer Block „Thema: …“ am Chatanfang"],["Boosts im Chat","Karten „hat das Model N Sekunden geboostet“"],["Tabs & Sortierung","Mädchen/Paare, Filter, Sortier-Symbol"],["Seitenende","Footer, Social Media, SEO-Text"],["Werbung & Banner","Banner, Promos, „Mach mit“-Leiste am Player, App"],["Hinweis „Weiter ansehen“","Button auf der Vorschau des zuletzt gesehenen Models"],["Anmelde-Fenster","Popup „Konto erstellen“"],["Chat-Hinweise","Tooltips und Benachrichtigungen"],["Pop-up-Chat des Models","Rosa Fenster mit der Auto-Begrüßung unten"],["Button „Spiele“","Gamepad-Symbol in der roten Leiste"],["Pop-up-Fenster","Chat-Auswahl, Gruppe, Voyeur"],["Buttons „Privat / Trinkgeld“","Blaue (am PC grüne) Buttons unter der roten Leiste"],["Guthaben & Menü (PC)","Guthaben und Navigation am Computer"],["Leiste „Chat mit …“","Streifen „Gratis-Chat mit …“ und Tip-König"],["Tip-König","Königs-Streifen und Trinkgeld-Fenster"],["Leiste unter dem Player (PC)","Button-Reihe unter dem Video"],["Wasserzeichen (PC)","Logo über dem Video"],["18+-Hinweis","Einstiegsbildschirm „Nur ab 18“"]],"FR":[["Haut du site","Logo, menu, boutons de connexion"],["En-tête du site (PC)","Barre supérieure sur ordinateur"],["Titre publicitaire","Ligne de titre SEO au-dessus de la liste"],["Pourboires dans le chat","Messages « a donné des tokens », menu de pourboires"],["Sujet du salon","Long bloc « Sujet : … » en haut du chat"],["Boosts dans le chat","Cartes « a boosté la modèle N secondes »"],["Onglets et tri","Filles/couples, filtres, icône de tri"],["Bas de page","Pied de page, réseaux sociaux, texte SEO"],["Pubs et bannières","Bannières, promos, bandeau « Rejoins-moi » sur le lecteur, appli"],["Pastille « Reprendre »","Bouton sur la miniature du dernier modèle vu"],["Fenêtre d’inscription","Formulaire « Créez un compte »"],["Astuces du chat","Infobulles et notifications"],["Chat flottant de la modèle","Fenêtre rose avec le message d’accueil automatique, en bas"],["Bouton « Jeux »","Icône de manette dans la barre rouge"],["Fenêtres surgissantes","Choix de chat, groupe, voyeur"],["Boutons « Privé / Pourboires »","Boutons bleus (verts sur PC) sous la barre rouge"],["Solde et menu (PC)","Solde et navigation sur ordinateur"],["Barre « Chat avec … »","Bandeau « Chat gratuit avec … » et roi des pourboires"],["Roi des pourboires","Bandeau du roi et fenêtres de pourboires"],["Barre sous le lecteur (PC)","Rangée de boutons sous la vidéo"],["Filigrane (PC)","Logo sur la vidéo"],["Avis 18+","Écran d’entrée « Réservé aux plus de 18 ans »"]],"PT":[["Topo do site","Logo, menu, botões de login"],["Cabeçalho do site (PC)","Barra superior no computador"],["Título publicitário","Linha de título SEO acima da lista"],["Gorjetas no chat","Mensagens de «deu tokens» e menu de gorjetas"],["Tema da sala","Bloco longo «Tema: …» no início do chat"],["Boosts no chat","Cartões de «impulsionou a modelo por N segundos»"],["Abas e ordenação","Garotas/casais, filtros, ícone de ordenação"],["Rodapé","Rodapé, redes sociais, texto SEO"],["Anúncios e banners","Banners, promoções, faixa «Junte-se» no player, app"],["Selo «Continuar assistindo»","Botão na miniatura da última modelo vista"],["Janela de cadastro","Pop-up «Crie uma conta»"],["Dicas do chat","Dicas e notificações pop-up"],["Chat pop-up da modelo","Janela rosa com a saudação automática, embaixo"],["Botão «Jogos»","Ícone de controle na barra vermelha"],["Janelas pop-up","Escolha de chat, grupo, voyeur"],["Botões «Privado / Gorjetas»","Botões azuis (verdes no PC) sob a barra vermelha"],["Saldo e menu (PC)","Saldo e navegação no computador"],["Barra «Chat com …»","Faixa «Chat grátis com …» e rei das gorjetas"],["Rei das gorjetas","Faixa do rei e janelas de gorjetas"],["Barra sob o player (PC)","Fileira de botões sob o vídeo"],["Marca d’água (PC)","Logo sobre o vídeo"],["Aviso 18+","Tela de entrada «Somente maiores de 18»"]],"IT":[["Parte alta del sito","Logo, menu, pulsanti di accesso"],["Intestazione del sito (PC)","Barra superiore su computer"],["Titolo pubblicitario","Riga di titolo SEO sopra l’elenco"],["Mance in chat","Messaggi «ha dato token» e menu mance"],["Argomento della stanza","Lungo blocco «Argomento: …» all’inizio della chat"],["Boost in chat","Schede «ha potenziato la modella per N secondi»"],["Schede e ordinamento","Ragazze/coppie, filtri, icona di ordinamento"],["Fondo pagina","Footer, social, testo SEO"],["Pubblicità e banner","Banner, promo, striscia «Unisciti» sul player, app"],["Badge «Continua a guardare»","Pulsante sull’anteprima dell’ultima modella vista"],["Finestra di registrazione","Popup «Crea un account»"],["Suggerimenti della chat","Tooltip e notifiche"],["Chat popup della modella","Finestra rosa con il saluto automatico, in basso"],["Pulsante «Giochi»","Icona del gamepad nella barra rossa"],["Finestre popup","Scelta chat, gruppo, voyeur"],["Pulsanti «Privato / Mance»","Pulsanti blu (verdi su PC) sotto la barra rossa"],["Saldo e menu (PC)","Saldo e navigazione su computer"],["Barra «Chat con …»","Striscia «Chat gratis con …» e re delle mance"],["Re delle mance","Striscia del re e finestre delle mance"],["Barra sotto il player (PC)","Fila di pulsanti sotto il video"],["Filigrana (PC)","Logo sopra il video"],["Avviso 18+","Schermata d’ingresso «Solo maggiorenni»"]],"PL":[["Góra strony","Logo, menu, przyciski logowania"],["Nagłówek strony (PC)","Górny pasek na komputerze"],["Reklamowy nagłówek","Linia z nagłówkiem SEO nad listą"],["Napiwki na czacie","Wiadomości „dał tokeny”, menu napiwków"],["Temat pokoju","Długi blok „Temat: …” na początku czatu"],["Boosty na czacie","Karty „podbił modelkę na N sekund”"],["Zakładki i sortowanie","Dziewczyny/pary, filtry, ikona sortowania"],["Dół strony","Stopka, social media, tekst SEO"],["Reklamy i banery","Banery, promocje, pasek „Dołącz” na odtwarzaczu, aplikacja"],["Plakietka „Kontynuuj oglądanie”","Przycisk na miniaturze ostatniej modelki"],["Okno rejestracji","Wyskakujący formularz „Załóż konto”"],["Podpowiedzi czatu","Dymki i powiadomienia"],["Wyskakujący czat modelki","Różowe okienko z automatycznym powitaniem na dole"],["Przycisk „Gry”","Ikona pada w czerwonym pasku"],["Okna wyskakujące","Wybór czatu, grupa, podglądanie"],["Przyciski „Prywatny / Napiwki”","Niebieskie (na PC zielone) przyciski pod czerwonym paskiem"],["Saldo i menu (PC)","Saldo i nawigacja na komputerze"],["Pasek „Czat z …”","Pasek „Darmowy czat z …” i król napiwków"],["Król napiwków","Pasek króla i okna napiwków"],["Pasek pod odtwarzaczem (PC)","Rząd przycisków pod wideo"],["Znak wodny (PC)","Logo na wideo"],["Ostrzeżenie 18+","Ekran wejściowy „Tylko dla pełnoletnich”"]],"TR":[["Sitenin üst kısmı","Logo, menü, giriş düğmeleri"],["Site başlığı (PC)","Bilgisayarda üst çubuk"],["Reklam başlığı","Listenin üstündeki SEO başlık satırı"],["Sohbette bahşişler","«Token verdi» mesajları ve bahşiş menüsü"],["Oda konusu","Sohbetin başındaki uzun «Konu: …» bloğu"],["Sohbette boostlar","«Modeli N saniye öne çıkardı» kartları"],["Sekmeler ve sıralama","Kızlar/çiftler, filtreler, sıralama simgesi"],["Sayfa altı","Alt bilgi, sosyal ağlar, SEO metni"],["Reklamlar ve bannerlar","Bannerlar, promolar, oynatıcıdaki «Katıl» şeridi, uygulama"],["«İzlemeye devam et» rozeti","Son bakılan modelin önizlemesindeki düğme"],["Kayıt penceresi","«Hesap oluştur» açılır formu"],["Sohbet ipuçları","Açılır ipuçları ve bildirimler"],["Modelin açılır sohbeti","Altta otomatik karşılama mesajlı pembe pencere"],["«Oyunlar» düğmesi","Kırmızı çubuktaki oyun kolu simgesi"],["Açılır pencereler","Sohbet seçimi, grup, gözetleme"],["«Özel / Bahşiş» düğmeleri","Kırmızı çubuğun altındaki mavi (PC’de yeşil) düğmeler"],["Bakiye ve menü (PC)","Bilgisayarda bakiye ve gezinme"],["«… ile sohbet» çubuğu","«… ile ücretsiz sohbet» şeridi ve bahşiş kralı"],["Bahşiş kralı","Kral şeridi ve bahşiş pencereleri"],["Oynatıcı altı çubuk (PC)","Videonun altındaki düğme sırası"],["Filigran (PC)","Videonun üzerindeki logo"],["18+ uyarısı","«Yalnızca 18 yaş üstü» giriş ekranı"]],"NL":[["Site-header","Logo, menu, inlogknoppen"],["Site-header (pc)","Bovenbalk op de computer"],["Reclamekop","SEO-kop boven de lijst"],["Tips in de chat","Meldingen „gaf tokens”, tipmenu"],["Kamerthema","Lang blok „Thema: …” aan het begin van de chat"],["Boosts in de chat","Kaarten „heeft het model N seconden geboost”"],["Tabs en sortering","Meisjes/koppels, filters, sorteericoon"],["Voettekst","Footer, socials, SEO-tekst"],["Reclame en banners","Banners, promo's, „Doe mee”-balk op de speler, app"],["Melding „Verder kijken”","Knop op de preview van het laatst bekeken model"],["Aanmeldvenster","Pop-up „Account maken”"],["Chat-hints","Tooltips en meldingen"],["Pop-upchat van model","Roze venster met automatische begroeting onderaan"],["Knop „Spelletjes”","Gamepad-icoon in de rode balk"],["Pop-upvensters","Chatkeuze, groep, voyeur"],["Knoppen „Privé / Tip”","Blauwe (op pc groene) knoppen onder de rode balk"],["Saldo en menu (pc)","Saldo en navigatie op de computer"],["Balk „Chat met …”","Strook „Gratis chat met …” en tipkoning"],["Tipkoning","Koningsstrook en tipvenster"],["Balk onder de speler (pc)","Knoppenrij onder de video"],["Watermerk (pc)","Logo over de video"],["18+-melding","Startscherm „Alleen 18+”"]],"CS":[["Hlavička webu","Logo, menu, tlačítka přihlášení"],["Hlavička webu (PC)","Horní panel na počítači"],["Reklamní nadpis","SEO nadpis nad seznamem"],["Tipy v chatu","Zprávy „dal tokeny“, menu tipů"],["Téma místnosti","Dlouhý blok „Téma: …“ na začátku chatu"],["Boosty v chatu","Karty „boostl modelku na N sekund“"],["Záložky a řazení","Dívky/páry, filtry, ikona řazení"],["Patička","Patička, sítě, SEO text"],["Reklama a bannery","Bannery, promo, lišta „Připoj se“ na přehrávači, aplikace"],["Lišta „Pokračovat ve sledování“","Tlačítko na náhledu poslední modelky"],["Registrační okno","Vyskakovací formulář „Vytvořit účet“"],["Nápovědy v chatu","Bubliny a oznámení"],["Vyskakovací chat modelky","Růžové okno s automatickým pozdravem dole"],["Tlačítko „Hry“","Ikona gamepadu v červené liště"],["Vyskakovací okna","Výběr chatu, skupina, voyeur"],["Tlačítka „Privát / Tip“","Modrá (na PC zelená) tlačítka pod červenou lištou"],["Zůstatek a menu (PC)","Zůstatek a navigace na počítači"],["Lišta „Chat s …“","Pruh „Zdarma chat s …“ a král tipů"],["Král tipů","Královský pruh a okno tipů"],["Lišta pod přehrávačem (PC)","Řada tlačítek pod videem"],["Vodoznak (PC)","Logo přes video"],["Upozornění 18+","Úvodní obrazovka „Pouze 18+“"]],"RO":[["Antetul site-ului","Logo, meniu, butoane de autentificare"],["Antetul site-ului (PC)","Bara de sus pe computer"],["Titlu publicitar","Titlu SEO deasupra listei"],["Tipuri în chat","Mesaje „a dat tokeni”, meniul de tip"],["Tema camerei","Bloc lung „Temă: …” la începutul chatului"],["Boost-uri în chat","Carduri „a boostat modelul N secunde”"],["Taburi și sortare","Fete/cupluri, filtre, pictogramă de sortare"],["Subsolul paginii","Footer, rețele sociale, text SEO"],["Reclame și bannere","Bannere, promo, bara „Alătură-te” de pe player, aplicația"],["Mesajul „Continuă vizionarea”","Buton pe previzualizarea ultimului model"],["Fereastra de înregistrare","Formularul pop-up „Creează cont”"],["Sfaturi în chat","Tooltip-uri și notificări"],["Chatul pop-up al modelului","Fereastră roz cu salut automat jos"],["Butonul „Jocuri”","Pictograma de gamepad din bara roșie"],["Ferestre pop-up","Alegerea chatului, grup, voyeur"],["Butoanele „Privat / Tip”","Butoane albastre (pe PC verzi) sub bara roșie"],["Sold și meniu (PC)","Soldul și navigarea pe computer"],["Bara „Chat cu …”","Banda „Chat gratuit cu …” și regele tipurilor"],["Regele tipurilor","Banda regelui și fereastra de tip"],["Bara de sub player (PC)","Rândul de butoane de sub video"],["Filigran (PC)","Logo peste video"],["Avertisment 18+","Ecranul de intrare „Doar 18+”"]],"HU":[["Oldal fejléce","Logó, menü, belépés gombok"],["Oldal fejléce (PC)","Felső sáv számítógépen"],["Reklámcím","SEO-cím a lista felett"],["Borravaló a csevegésben","„tokent adott” üzenetek, borravaló menü"],["Szoba témája","Hosszú „Téma: …” blokk a csevegés elején"],["Boostok a csevegésben","„N másodpercre boostolta a modellt” kártyák"],["Fülek és rendezés","Lányok/párok, szűrők, rendezés ikon"],["Oldal alja","Lábléc, közösségi média, SEO-szöveg"],["Reklámok és bannerek","Bannerek, promók, „Csatlakozz” sáv a lejátszón, app"],["„Folytatás” jelzés","Gomb az utoljára nézett modell előnézetén"],["Regisztrációs ablak","„Fiók létrehozása” felugró űrlap"],["Csevegési tippek","Buborékok és értesítések"],["A modell felugró csevegése","Rózsaszín ablak automatikus köszöntéssel alul"],["„Játékok” gomb","Gamepad ikon a piros sávban"],["Felugró ablakok","Csevegés választás, csoport, voyeur"],["„Privát / Borravaló” gombok","Kék (PC-n zöld) gombok a piros sáv alatt"],["Egyenleg és menü (PC)","Egyenleg és navigáció számítógépen"],["„Csevegés vele: …” sáv","„Ingyenes csevegés vele: …” csík és borravalókirály"],["Borravalókirály","Király csík és borravaló ablak"],["Sáv a lejátszó alatt (PC)","Gombsor a videó alatt"],["Vízjel (PC)","Logó a videó felett"],["18+ figyelmeztetés","„Csak 18+” belépő képernyő"]],"BG":[["Хедър на сайта","Лого, меню, бутони за вход"],["Хедър на сайта (PC)","Горна лента на компютър"],["Рекламно заглавие","SEO заглавие над списъка"],["Бакшиши в чата","Съобщения „даде токени“, меню за бакшиш"],["Тема на стаята","Дълъг блок „Тема: …“ в началото на чата"],["Бустове в чата","Карти „бустна модела за N секунди“"],["Раздели и сортиране","Момичета/двойки, филтри, иконка за сортиране"],["Долна част на страницата","Футър, социални мрежи, SEO текст"],["Реклами и банери","Банери, промо, лента „Присъедини се“ на плеъра, приложение"],["Плашка „Продължи гледането“","Бутон на превюто на последния модел"],["Прозорец за регистрация","Изскачаща форма „Създай акаунт“"],["Съвети в чата","Подсказки и известия"],["Изскачащ чат на модела","Розов прозорец с автоматичен поздрав долу"],["Бутон „Игри“","Иконка на геймпад в червената лента"],["Изскачащи прозорци","Избор на чат, група, воаяор"],["Бутони „Приват / Бакшиш“","Сини (на PC зелени) бутони под червената лента"],["Баланс и меню (PC)","Баланс и навигация на компютър"],["Лента „Чат с …“","Ивица „Безплатен чат с …“ и цар на бакшишите"],["Цар на бакшишите","Царска ивица и прозорец за бакшиш"],["Лента под плеъра (PC)","Ред с бутони под видеото"],["Воден знак (PC)","Лого върху видеото"],["Предупреждение 18+","Входен екран „Само 18+“"]],"EL":[["Κεφαλίδα ιστότοπου","Λογότυπο, μενού, κουμπιά σύνδεσης"],["Κεφαλίδα ιστότοπου (PC)","Επάνω γραμμή στον υπολογιστή"],["Διαφημιστικός τίτλος","Τίτλος SEO πάνω από τη λίστα"],["Φιλοδωρήματα στο chat","Μηνύματα «έδωσε tokens», μενού tip"],["Θέμα δωματίου","Μεγάλο μπλοκ «Θέμα: …» στην αρχή του chat"],["Boosts στο chat","Κάρτες «ενίσχυσε το μοντέλο για N δευτερόλεπτα»"],["Καρτέλες και ταξινόμηση","Κορίτσια/ζευγάρια, φίλτρα, εικονίδιο ταξινόμησης"],["Υποσέλιδο","Footer, social, κείμενο SEO"],["Διαφημίσεις και banners","Banners, promo, γραμμή «Γίνε μέλος» στον player, εφαρμογή"],["Ειδοποίηση «Συνέχεια παρακολούθησης»","Κουμπί στην προεπισκόπηση του τελευταίου μοντέλου"],["Παράθυρο εγγραφής","Αναδυόμενη φόρμα «Δημιουργία λογαριασμού»"],["Συμβουλές chat","Tooltips και ειδοποιήσεις"],["Αναδυόμενο chat μοντέλου","Ροζ παράθυρο με αυτόματο χαιρετισμό κάτω"],["Κουμπί «Παιχνίδια»","Εικονίδιο gamepad στην κόκκινη γραμμή"],["Αναδυόμενα παράθυρα","Επιλογή chat, ομάδα, voyeur"],["Κουμπιά «Ιδιωτικό / Φιλοδώρημα»","Μπλε (στον υπολογιστή πράσινα) κουμπιά κάτω από την κόκκινη γραμμή"],["Υπόλοιπο και μενού (PC)","Υπόλοιπο και πλοήγηση στον υπολογιστή"],["Γραμμή «Chat με …»","Λωρίδα «Δωρεάν chat με …» και βασιλιάς φιλοδωρημάτων"],["Βασιλιάς φιλοδωρημάτων","Λωρίδα βασιλιά και παράθυρο φιλοδωρημάτων"],["Γραμμή κάτω από τον player (PC)","Σειρά κουμπιών κάτω από το βίντεο"],["Υδατογράφημα (PC)","Λογότυπο πάνω από το βίντεο"],["Ειδοποίηση 18+","Αρχική οθόνη «Μόνο 18+»"]],"JA":[["サイトのヘッダー","ロゴ、メニュー、ログインボタン"],["サイトのヘッダー(PC)","パソコン表示の上部バー"],["宣伝見出し","リスト上のSEO見出し"],["チャットのチップ","「トークンを贈りました」メッセージ、チップメニュー"],["ルームのトピック","チャット冒頭の長い「トピック: …」ブロック"],["チャットのブースト","「モデルをN秒ブースト」カード"],["タブと並べ替え","女の子/カップル、フィルター、並べ替えアイコン"],["ページ下部","フッター、SNS、SEOテキスト"],["広告とバナー","バナー、プロモ、プレーヤー上の「参加」バー、アプリ"],["「続きを見る」表示","最後に見たモデルのプレビュー上のボタン"],["登録ウィンドウ","「アカウント作成」ポップアップ"],["チャットのヒント","ツールチップと通知"],["モデルのポップアップチャット","下部に自動あいさつが出るピンクのウィンドウ"],["「ゲーム」ボタン","赤いバーのゲームパッドアイコン"],["ポップアップウィンドウ","チャット選択、グループ、のぞき見"],["「プライベート / チップ」ボタン","赤いバー下の青い(PCでは緑の)ボタン"],["残高とメニュー(PC)","パソコン表示の残高とナビゲーション"],["「〜とチャット」バー","「〜と無料チャット」帯とチップキング"],["チップキング","キングの帯とチップウィンドウ"],["プレーヤー下のバー(PC)","動画下のボタン列"],["透かし(PC)","動画上のロゴ"],["18歳以上の確認","「18歳以上のみ」入口画面"]],"ZH":[["网站顶部","Logo、菜单、登录按钮"],["网站顶部(电脑)","电脑端的顶部栏"],["广告标题","列表上方的 SEO 标题"],["聊天打赏","“赠送了代币”消息、打赏菜单"],["房间话题","聊天开头很长的“话题:…”块"],["聊天加成","“为主播加成 N 秒”卡片"],["标签页和排序","女生/情侣、筛选、排序图标"],["页面底部","页脚、社交媒体、SEO 文字"],["广告和横幅","横幅、推广、播放器上的“加入”条、应用"],["“继续观看”提示","最近观看主播预览上的按钮"],["注册窗口","“创建账号”弹窗"],["聊天提示","提示气泡和通知"],["主播弹出聊天","底部带自动问候的粉色窗口"],["“游戏”按钮","红色栏中的手柄图标"],["弹出窗口","聊天选择、群组、偷看"],["“私密 / 打赏”按钮","红色栏下方的蓝色(电脑端为绿色)按钮"],["余额和菜单(电脑)","电脑端的余额和导航"],["“与…聊天”栏","“与…免费聊天”条和打赏之王"],["打赏之王","国王条和打赏窗口"],["播放器下方栏(电脑)","视频下方的按钮行"],["水印(电脑)","视频上的 Logo"],["18+ 提示","“仅限 18 岁以上”入口页"]],"KO":[["사이트 헤더","로고, 메뉴, 로그인 버튼"],["사이트 헤더(PC)","컴퓨터 화면의 상단 바"],["광고성 제목","목록 위의 SEO 제목"],["채팅 팁","“토큰을 선물했습니다” 메시지, 팁 메뉴"],["방 주제","채팅 시작 부분의 긴 “주제: …” 블록"],["채팅 부스트","“모델을 N초 부스트했습니다” 카드"],["탭과 정렬","여성/커플, 필터, 정렬 아이콘"],["페이지 하단","푸터, SNS, SEO 텍스트"],["광고 및 배너","배너, 프로모션, 플레이어의 “가입” 바, 앱"],["“이어보기” 표시","마지막으로 본 모델 미리보기의 버튼"],["가입 창","“계정 만들기” 팝업"],["채팅 안내","툴팁과 알림"],["모델 팝업 채팅","하단에 자동 인사가 있는 분홍색 창"],["“게임” 버튼","빨간 바의 게임패드 아이콘"],["팝업 창","채팅 선택, 그룹, 훔쳐보기"],["“프라이빗 / 팁” 버튼","빨간 바 아래의 파란색(PC에서는 녹색) 버튼"],["잔액 및 메뉴(PC)","컴퓨터 화면의 잔액과 내비게이션"],["“…와 채팅” 바","“…와 무료 채팅” 띠와 팁 킹"],["팁 킹","킹 띠와 팁 창"],["플레이어 아래 바(PC)","영상 아래의 버튼 줄"],["워터마크(PC)","영상 위의 로고"],["18+ 안내","“18세 이상만” 입장 화면"]],"HE":[["כותרת האתר","לוגו, תפריט, כפתורי כניסה"],["כותרת האתר (מחשב)","הסרגל העליון במחשב"],["כותרת פרסומית","כותרת SEO מעל הרשימה"],["טיפים בצ׳אט","הודעות “שלח טוקנים”, תפריט טיפים"],["נושא החדר","בלוק ארוך “נושא: …” בתחילת הצ׳אט"],["בוסטים בצ׳אט","כרטיסים “הגביר את המודל ל-N שניות”"],["לשוניות ומיון","בנות/זוגות, סינון, סמל מיון"],["תחתית העמוד","פוטר, רשתות חברתיות, טקסט SEO"],["פרסומות ובאנרים","באנרים, מבצעים, פס “הצטרף” בנגן, אפליקציה"],["הודעת “המשך צפייה”","כפתור על התצוגה המקדימה של המודל האחרון"],["חלון הרשמה","חלון קופץ “יצירת חשבון”"],["רמזים בצ׳אט","טיפים צפים והתראות"],["צ׳אט קופץ של המודל","חלון ורוד עם ברכה אוטומטית בתחתית"],["כפתור “משחקים”","סמל שלט משחק בפס האדום"],["חלונות קופצים","בחירת צ׳אט, קבוצה, מציצן"],["כפתורי “פרטי / טיפ”","כפתורים כחולים (במחשב ירוקים) מתחת לפס האדום"],["יתרה ותפריט (מחשב)","יתרה וניווט במחשב"],["פס “צ׳אט עם …”","רצועת “צ׳אט חינם עם …” ומלך הטיפים"],["מלך הטיפים","רצועת המלך וחלון הטיפים"],["פס מתחת לנגן (מחשב)","שורת כפתורים מתחת לוידאו"],["סימן מים (מחשב)","לוגו מעל הוידאו"],["הודעת 18+","מסך כניסה “18 ומעלה בלבד”"]],"AR":[["رأس الموقع","الشعار والقائمة وأزرار الدخول"],["رأس الموقع (الكمبيوتر)","الشريط العلوي على الكمبيوتر"],["عنوان إعلاني","عنوان SEO فوق القائمة"],["البقشيش في الدردشة","رسائل «أهدى رموزًا»، قائمة البقشيش"],["موضوع الغرفة","كتلة طويلة «الموضوع: …» في بداية الدردشة"],["التعزيزات في الدردشة","بطاقات «عزّز الموديل لمدة N ثانية»"],["التبويبات والفرز","فتيات/أزواج، فلاتر، أيقونة الفرز"],["أسفل الصفحة","التذييل، الشبكات الاجتماعية، نص SEO"],["الإعلانات واللافتات","لافتات، عروض، شريط «انضم» على المشغّل، التطبيق"],["تنبيه «متابعة المشاهدة»","زر على معاينة آخر موديل"],["نافذة التسجيل","نافذة منبثقة «إنشاء حساب»"],["تلميحات الدردشة","تلميحات وإشعارات"],["دردشة الموديل المنبثقة","نافذة وردية بتحية تلقائية في الأسفل"],["زر «الألعاب»","أيقونة يد التحكم في الشريط الأحمر"],["النوافذ المنبثقة","اختيار الدردشة، المجموعة، المتلصص"],["أزرار «خاص / بقشيش»","أزرار زرقاء (خضراء على الكمبيوتر) تحت الشريط الأحمر"],["الرصيد والقائمة (الكمبيوتر)","الرصيد والتنقل على الكمبيوتر"],["شريط «دردشة مع …»","شريط «دردشة مجانية مع …» وملك البقشيش"],["ملك البقشيش","شريط الملك ونافذة البقشيش"],["الشريط تحت المشغّل (الكمبيوتر)","صف الأزرار تحت الفيديو"],["العلامة المائية (الكمبيوتر)","الشعار فوق الفيديو"],["تنبيه +18","شاشة الدخول «للكبار فقط 18+»"]],"HI":[["साइट का हेडर","लोगो, मेन्यू, लॉगिन बटन"],["साइट का हेडर (PC)","कंप्यूटर पर ऊपर की पट्टी"],["विज्ञापन शीर्षक","सूची के ऊपर SEO शीर्षक"],["चैट में टिप","“टोकन दिए” संदेश, टिप मेन्यू"],["रूम का विषय","चैट की शुरुआत में लंबा “विषय: …” ब्लॉक"],["चैट में बूस्ट","“मॉडल को N सेकंड बूस्ट किया” कार्ड"],["टैब और सॉर्टिंग","लड़कियाँ/जोड़े, फ़िल्टर, सॉर्ट आइकन"],["पेज का निचला हिस्सा","फ़ुटर, सोशल मीडिया, SEO टेक्स्ट"],["विज्ञापन और बैनर","बैनर, प्रोमो, प्लेयर पर “जुड़ें” पट्टी, ऐप"],["“देखना जारी रखें” सूचना","आख़िरी देखी मॉडल के प्रीव्यू पर बटन"],["रजिस्ट्रेशन विंडो","“खाता बनाएँ” पॉप-अप"],["चैट सुझाव","टूलटिप और सूचनाएँ"],["मॉडल का पॉप-अप चैट","नीचे ऑटो-अभिवादन वाली गुलाबी विंडो"],["“गेम” बटन","लाल पट्टी में गेमपैड आइकन"],["पॉप-अप विंडो","चैट चयन, ग्रुप, वॉयर"],["“प्राइवेट / टिप” बटन","लाल पट्टी के नीचे नीले (PC पर हरे) बटन"],["बैलेंस और मेन्यू (PC)","कंप्यूटर पर बैलेंस और नेविगेशन"],["“… के साथ चैट” पट्टी","“… के साथ मुफ़्त चैट” पट्टी और टिप किंग"],["टिप किंग","किंग पट्टी और टिप विंडो"],["प्लेयर के नीचे की पट्टी (PC)","वीडियो के नीचे बटनों की पंक्ति"],["वॉटरमार्क (PC)","वीडियो के ऊपर लोगो"],["18+ चेतावनी","“केवल 18+” एंट्री स्क्रीन"]],"ID":[["Header situs","Logo, menu, tombol masuk"],["Header situs (PC)","Bilah atas di komputer"],["Judul iklan","Judul SEO di atas daftar"],["Tip di chat","Pesan “memberi token”, menu tip"],["Topik ruangan","Blok panjang “Topik: …” di awal chat"],["Boost di chat","Kartu “mem-boost model selama N detik”"],["Tab dan pengurutan","Cewek/pasangan, filter, ikon urutkan"],["Bagian bawah halaman","Footer, media sosial, teks SEO"],["Iklan dan banner","Banner, promo, bilah “Bergabung” di pemutar, aplikasi"],["Pemberitahuan “Lanjutkan menonton”","Tombol di pratinjau model terakhir"],["Jendela pendaftaran","Pop-up “Buat akun”"],["Petunjuk chat","Tooltip dan notifikasi"],["Chat pop-up model","Jendela pink dengan sapaan otomatis di bawah"],["Tombol “Game”","Ikon gamepad di bilah merah"],["Jendela pop-up","Pilihan chat, grup, voyeur"],["Tombol “Privat / Tip”","Tombol biru (hijau di PC) di bawah bilah merah"],["Saldo dan menu (PC)","Saldo dan navigasi di komputer"],["Bilah “Chat dengan …”","Pita “Chat gratis dengan …” dan raja tip"],["Raja tip","Pita raja dan jendela tip"],["Bilah di bawah pemutar (PC)","Baris tombol di bawah video"],["Watermark (PC)","Logo di atas video"],["Peringatan 18+","Layar masuk “Khusus 18+”"]],"VI":[["Phần đầu trang","Logo, menu, nút đăng nhập"],["Phần đầu trang (PC)","Thanh trên cùng trên máy tính"],["Tiêu đề quảng cáo","Tiêu đề SEO phía trên danh sách"],["Tip trong chat","Tin nhắn “đã tặng token”, menu tip"],["Chủ đề phòng","Khối dài “Chủ đề: …” ở đầu chat"],["Boost trong chat","Thẻ “đã boost model N giây”"],["Tab và sắp xếp","Các cô gái/cặp đôi, bộ lọc, biểu tượng sắp xếp"],["Chân trang","Footer, mạng xã hội, văn bản SEO"],["Quảng cáo và banner","Banner, khuyến mãi, thanh “Tham gia” trên trình phát, ứng dụng"],["Thông báo “Xem tiếp”","Nút trên bản xem trước của model xem gần nhất"],["Cửa sổ đăng ký","Cửa sổ bật lên “Tạo tài khoản”"],["Gợi ý trong chat","Tooltip và thông báo"],["Chat bật lên của model","Cửa sổ màu hồng có lời chào tự động ở dưới"],["Nút “Trò chơi”","Biểu tượng tay cầm ở thanh đỏ"],["Cửa sổ bật lên","Chọn chat, nhóm, voyeur"],["Nút “Riêng tư / Tip”","Nút xanh dương (xanh lá trên PC) dưới thanh đỏ"],["Số dư và menu (PC)","Số dư và điều hướng trên máy tính"],["Thanh “Chat với …”","Dải “Chat miễn phí với …” và vua tip"],["Vua tip","Dải vua và cửa sổ tip"],["Thanh dưới trình phát (PC)","Hàng nút bên dưới video"],["Hình mờ (PC)","Logo phía trên video"],["Cảnh báo 18+","Màn hình vào “Chỉ dành cho 18+”"]],"TH":[["ส่วนหัวเว็บไซต์","โลโก้ เมนู ปุ่มเข้าสู่ระบบ"],["ส่วนหัวเว็บไซต์ (PC)","แถบด้านบนบนคอมพิวเตอร์"],["หัวข้อโฆษณา","หัวข้อ SEO เหนือรายการ"],["ทิปในแชต","ข้อความ “ให้โทเคน” เมนูทิป"],["หัวข้อห้อง","บล็อกยาว “หัวข้อ: …” ตอนต้นแชต"],["บูสต์ในแชต","การ์ด “บูสต์โมเดล N วินาที”"],["แท็บและการเรียง","สาวๆ/คู่รัก ตัวกรอง ไอคอนเรียง"],["ท้ายหน้า","ส่วนท้าย โซเชียล ข้อความ SEO"],["โฆษณาและแบนเนอร์","แบนเนอร์ โปรโมชัน แถบ “เข้าร่วม” บนเครื่องเล่น แอป"],["แจ้งเตือน “ดูต่อ”","ปุ่มบนตัวอย่างของโมเดลที่ดูล่าสุด"],["หน้าต่างสมัครสมาชิก","ป๊อปอัป “สร้างบัญชี”"],["คำแนะนำในแชต","ทูลทิปและการแจ้งเตือน"],["แชตป๊อปอัปของโมเดล","หน้าต่างสีชมพูพร้อมคำทักทายอัตโนมัติด้านล่าง"],["ปุ่ม “เกม”","ไอคอนจอยเกมในแถบสีแดง"],["หน้าต่างป๊อปอัป","เลือกแชต กลุ่ม คนแอบดู"],["ปุ่ม “ส่วนตัว / ทิป”","ปุ่มสีน้ำเงิน (บน PC เป็นสีเขียว) ใต้แถบสีแดง"],["ยอดเงินและเมนู (PC)","ยอดเงินและการนำทางบนคอมพิวเตอร์"],["แถบ “แชตกับ …”","แถบ “แชตฟรีกับ …” และราชาทิป"],["ราชาทิป","แถบราชาและหน้าต่างทิป"],["แถบใต้เครื่องเล่น (PC)","แถวปุ่มใต้วิดีโอ"],["ลายน้ำ (PC)","โลโก้เหนือวิดีโอ"],["คำเตือน 18+","หน้าจอเข้าสู่ระบบ “เฉพาะ 18+”"]]}}}).map(([n, p]) => [n, unpackI18N(p)]));
Object.assign(i18n.RU, I18N_X.NEW.RU);
Object.assign(i18n.EN, I18N_X.NEW.EN);
Object.assign(i18n, I18N_X.LANG);
const I18N_Y = unpackI18N({"k":["st_favnav","st_prev","st_hide_topic","st_hide_grp","st_prev_spd","rs_cur","rs_resnote","st_av_refresh","fr_none","fr_hold"],"v":{"RU":["Кнопки «назад / вперёд» на пульте","Превью моделей","Скрыть описание модели","Скрыть выбор группы","Скорость превью","Сейчас поток:","Разрешение записи равно разрешению потока и не меняется. Пункты выше ограничивают только битрейт (сжатие); 1080p/720p/480p/360p — примерное качество картинки при таком битрейте.","Обновить аватарки","Кадр недоступен: модель не в эфире","Удерживайте — показать текущий кадр"],"EN":["Prev / next buttons on remote","Model previews","Hide model description","Hide group selector","Preview speed","Current stream:","Recording resolution equals the stream resolution and is not changed. The options above only limit the bitrate (compression); 1080p/720p/480p/360p show the approximate picture quality at that bitrate.","Refresh avatars","No frame: model is offline","Hold to show the current frame"],"UK":["Кнопки «назад / вперед» на пульті","Превʼю моделей","Сховати опис моделі","Сховати вибір групи","Швидкість превʼю","Зараз потік:","Роздільна здатність запису дорівнює роздільній здатності потоку і не змінюється. Пункти вище обмежують лише бітрейт (стиснення); 1080p/720p/480p/360p — приблизна якість картинки за такого бітрейту.","Оновити аватарки","Кадр недоступний: модель не в ефірі","Утримуйте — показати поточний кадр"],"ES":["Botones «anterior / siguiente» en el mando","Vistas previas de modelos","Ocultar la descripción de la modelo","Ocultar el selector de grupo","Velocidad de la vista previa","Transmisión actual:","La resolución de la grabación es la de la transmisión y no cambia. Las opciones de arriba solo limitan el bitrate (compresión); 1080p/720p/480p/360p indican la calidad aproximada de la imagen con ese bitrate.","Actualizar avatares","Sin imagen: la modelo no está en directo","Mantén pulsado para ver el fotograma actual"],"DE":["Zurück-/Weiter-Tasten an der Steuerung","Modell-Vorschauen","Modellbeschreibung ausblenden","Gruppenauswahl ausblenden","Vorschau-Geschwindigkeit","Aktueller Stream:","Die Aufnahmeauflösung entspricht der Stream-Auflösung und wird nicht verändert. Die Optionen oben begrenzen nur die Bitrate (Kompression); 1080p/720p/480p/360p zeigen die ungefähre Bildqualität bei dieser Bitrate.","Avatare aktualisieren","Kein Bild: Model ist offline","Gedrückt halten für das aktuelle Bild"],"FR":["Boutons « précédent / suivant » sur la télécommande","Aperçus des modèles","Masquer la description du modèle","Masquer le sélecteur de groupe","Vitesse des aperçus","Flux actuel :","La résolution de l’enregistrement est celle du flux et ne change pas. Les options ci-dessus limitent uniquement le débit (compression) ; 1080p/720p/480p/360p indiquent la qualité d’image approximative à ce débit.","Actualiser les avatars","Image indisponible : le modèle est hors ligne","Maintenez pour voir l’image actuelle"],"PT":["Botões «anterior / próximo» no controle","Pré-visualizações das modelos","Ocultar a descrição da modelo","Ocultar o seletor de grupo","Velocidade da pré-visualização","Transmissão atual:","A resolução da gravação é a mesma da transmissão e não muda. As opções acima limitam apenas o bitrate (compressão); 1080p/720p/480p/360p indicam a qualidade aproximada da imagem nesse bitrate.","Atualizar avatares","Sem imagem: a modelo está offline","Segure para ver o quadro atual"],"IT":["Pulsanti «precedente / successivo» sul telecomando","Anteprime delle modelle","Nascondi la descrizione della modella","Nascondi il selettore di gruppo","Velocità delle anteprime","Stream attuale:","La risoluzione della registrazione è quella dello stream e non cambia. Le opzioni sopra limitano solo il bitrate (compressione); 1080p/720p/480p/360p indicano la qualità approssimativa dell’immagine con quel bitrate.","Aggiorna avatar","Nessun fotogramma: la modella è offline","Tieni premuto per vedere il fotogramma attuale"],"PL":["Przyciski „wstecz / dalej” na pilocie","Podglądy modelek","Ukryj opis modelki","Ukryj wybór grupy","Szybkość podglądu","Obecny strumień:","Rozdzielczość nagrania jest taka jak rozdzielczość strumienia i się nie zmienia. Powyższe opcje ograniczają tylko bitrate (kompresję); 1080p/720p/480p/360p to przybliżona jakość obrazu przy takim bitrate.","Odśwież awatary","Brak klatki: modelka jest offline","Przytrzymaj, aby zobaczyć bieżącą klatkę"],"TR":["Kumandada «geri / ileri» düğmeleri","Model önizlemeleri","Model açıklamasını gizle","Grup seçicisini gizle","Önizleme hızı","Mevcut yayın:","Kayıt çözünürlüğü yayın çözünürlüğüne eşittir ve değişmez. Yukarıdaki seçenekler yalnızca bit hızını (sıkıştırmayı) sınırlar; 1080p/720p/480p/360p bu bit hızındaki yaklaşık görüntü kalitesini gösterir.","Avatarları yenile","Kare yok: model çevrimdışı","Geçerli kareyi görmek için basılı tut"],"NL":["«Vorige / volgende»-knoppen op de bediening","Voorbeelden van modellen","Modelbeschrijving verbergen","Groepskeuze verbergen","Snelheid van voorbeelden","Huidige stream:","De opnameresolutie is gelijk aan de streamresolutie en verandert niet. De opties hierboven beperken alleen de bitrate (compressie); 1080p/720p/480p/360p geven de ongeveer verwachte beeldkwaliteit bij die bitrate.","Avatars vernieuwen","Geen beeld: model is offline","Houd ingedrukt voor het huidige beeld"],"CS":["Tlačítka „zpět / vpřed“ na ovladači","Náhledy modelek","Skrýt popis modelky","Skrýt výběr skupiny","Rychlost náhledů","Aktuální stream:","Rozlišení nahrávky se rovná rozlišení streamu a nemění se. Možnosti výše omezují jen bitrate (kompresi); 1080p/720p/480p/360p udávají přibližnou kvalitu obrazu při daném bitrate.","Obnovit avatary","Snímek není k dispozici: modelka je offline","Podržením zobrazíte aktuální snímek"],"RO":["Butoane „înapoi / înainte” pe telecomandă","Previzualizări ale modelelor","Ascunde descrierea modelului","Ascunde selectorul de grup","Viteza previzualizărilor","Fluxul curent:","Rezoluția înregistrării este aceeași cu a fluxului și nu se schimbă. Opțiunile de mai sus limitează doar bitrate-ul (compresia); 1080p/720p/480p/360p arată calitatea aproximativă a imaginii la acel bitrate.","Actualizează avatarele","Fără cadru: modelul este offline","Ține apăsat pentru cadrul curent"],"HU":["„Vissza / előre” gombok a vezérlőn","Modellek előnézete","Modell leírásának elrejtése","Csoportválasztó elrejtése","Előnézet sebessége","Jelenlegi adás:","A felvétel felbontása megegyezik az adás felbontásával, és nem változik. A fenti opciók csak a bitrátát (tömörítést) korlátozzák; az 1080p/720p/480p/360p az adott bitrátánál kapott körülbelüli képminőséget jelzi.","Avatarok frissítése","Nincs kép: a modell offline","Tartsd nyomva az aktuális képkockához"],"BG":["Бутони «назад / напред» на пулта","Превюта на моделите","Скриване на описанието на модела","Скриване на избора на група","Скорост на превютата","Текущ поток:","Резолюцията на записа е равна на тази на потока и не се променя. Опциите по-горе ограничават само битрейта (компресията); 1080p/720p/480p/360p показват приблизителното качество на картината при този битрейт.","Обнови аватарите","Няма кадър: моделът е офлайн","Задръжте, за да видите текущия кадър"],"EL":["Κουμπιά «προηγούμενο / επόμενο» στο χειριστήριο","Προεπισκοπήσεις μοντέλων","Απόκρυψη περιγραφής μοντέλου","Απόκρυψη επιλογής ομάδας","Ταχύτητα προεπισκόπησης","Τρέχον stream:","Η ανάλυση της εγγραφής είναι ίδια με του stream και δεν αλλάζει. Οι επιλογές παραπάνω περιορίζουν μόνο το bitrate (συμπίεση)· τα 1080p/720p/480p/360p δείχνουν την προσεγγιστική ποιότητα εικόνας σε αυτό το bitrate.","Ανανέωση avatar","Δεν υπάρχει καρέ: το μοντέλο είναι εκτός σύνδεσης","Πατήστε παρατεταμένα για το τρέχον καρέ"],"JA":["操作パネルの「前へ/次へ」ボタン","モデルのプレビュー","モデルの説明を非表示","グループ選択を非表示","プレビューの速度","現在のストリーム:","録画の解像度はストリームの解像度と同じで、変更されません。上の項目はビットレート(圧縮)のみを制限します。1080p/720p/480p/360pは、そのビットレートでのおおよその画質の目安です。","アバターを更新","フレームなし:モデルはオフラインです","長押しで現在のフレームを表示"],"ZH":["控制面板上的“上一个 / 下一个”按钮","主播预览","隐藏主播简介","隐藏分组选择","预览速度","当前直播流:","录制分辨率与直播流分辨率相同,不会改变。上面的选项只限制码率(压缩);1080p/720p/480p/360p 表示该码率下大致的画质。","刷新头像","无画面:主播已离线","长按查看当前画面"],"KO":["컨트롤의 “이전 / 다음” 버튼","모델 미리보기","모델 소개 숨기기","그룹 선택 숨기기","미리보기 속도","현재 스트림:","녹화 해상도는 스트림 해상도와 같으며 변경되지 않습니다. 위 옵션은 비트레이트(압축)만 제한하며, 1080p/720p/480p/360p는 해당 비트레이트에서의 대략적인 화질입니다.","아바타 새로고침","프레임 없음: 모델이 오프라인입니다","길게 눌러 현재 프레임 보기"],"HE":["כפתורי «הקודם / הבא» בבקרה","תצוגות מקדימות של מודלים","הסתר את תיאור המודל","הסתר את בחירת הקבוצה","מהירות התצוגה המקדימה","הסטרים הנוכחי:","רזולוציית ההקלטה זהה לרזולוציית הסטרים ואינה משתנה. האפשרויות למעלה מגבילות רק את קצב הסיביות (דחיסה); 1080p/720p/480p/360p מציינות את איכות התמונה המשוערת בקצב סיביות זה.","רענון תמונות פרופיל","אין פריים: המודל לא מחובר","לחיצה ארוכה להצגת הפריים הנוכחי"],"AR":["أزرار «السابق / التالي» في لوحة التحكم","معاينات الموديلات","إخفاء وصف الموديل","إخفاء اختيار المجموعة","سرعة المعاينة","البث الحالي:","دقة التسجيل تساوي دقة البث ولا تتغير. الخيارات أعلاه تحدّ من معدل البت (الضغط) فقط؛ 1080p/720p/480p/360p تشير إلى جودة الصورة التقريبية عند هذا المعدل.","تحديث الصور الرمزية","لا توجد لقطة: الموديل غير متصل","اضغط مطولًا لعرض اللقطة الحالية"],"HI":["कंट्रोल पर «पिछला / अगला» बटन","मॉडल प्रीव्यू","मॉडल का विवरण छिपाएँ","ग्रुप चयन छिपाएँ","प्रीव्यू की गति","मौजूदा स्ट्रीम:","रिकॉर्डिंग का रेज़ोल्यूशन स्ट्रीम के रेज़ोल्यूशन जितना ही रहता है और बदलता नहीं। ऊपर के विकल्प केवल बिटरेट (कंप्रेशन) सीमित करते हैं; 1080p/720p/480p/360p उस बिटरेट पर लगभग कैसी तस्वीर मिलेगी, यह बताते हैं।","अवतार रीफ़्रेश करें","फ़्रेम उपलब्ध नहीं: मॉडल ऑफ़लाइन है","मौजूदा फ़्रेम देखने के लिए दबाए रखें"],"ID":["Tombol «sebelumnya / berikutnya» di kontrol","Pratinjau model","Sembunyikan deskripsi model","Sembunyikan pilihan grup","Kecepatan pratinjau","Stream saat ini:","Resolusi rekaman sama dengan resolusi stream dan tidak berubah. Opsi di atas hanya membatasi bitrate (kompresi); 1080p/720p/480p/360p menunjukkan perkiraan kualitas gambar pada bitrate tersebut.","Segarkan avatar","Tidak ada bingkai: model sedang offline","Tahan untuk melihat bingkai saat ini"],"VI":["Nút «trước / sau» trên bảng điều khiển","Xem trước model","Ẩn mô tả model","Ẩn lựa chọn nhóm","Tốc độ xem trước","Luồng hiện tại:","Độ phân giải bản ghi bằng độ phân giải của luồng và không thay đổi. Các tùy chọn ở trên chỉ giới hạn bitrate (nén); 1080p/720p/480p/360p cho biết chất lượng hình ảnh xấp xỉ ở bitrate đó.","Làm mới ảnh đại diện","Không có khung hình: model đang offline","Giữ để xem khung hình hiện tại"],"TH":["ปุ่ม «ก่อนหน้า / ถัดไป» บนแผงควบคุม","พรีวิวโมเดล","ซ่อนคำอธิบายโมเดล","ซ่อนตัวเลือกกลุ่ม","ความเร็วพรีวิว","สตรีมปัจจุบัน:","ความละเอียดของการอัดเท่ากับความละเอียดของสตรีมและไม่เปลี่ยนแปลง ตัวเลือกด้านบนจำกัดเฉพาะบิตเรต (การบีบอัด) เท่านั้น 1080p/720p/480p/360p คือคุณภาพภาพโดยประมาณที่บิตเรตนั้น","รีเฟรชอวาตาร์","ไม่มีเฟรม: โมเดลออฟไลน์","กดค้างเพื่อดูเฟรมปัจจุบัน"]}});
Object.keys(I18N_Y).forEach(k => { i18n[k] = Object.assign(i18n[k] || {}, I18N_Y[k]); });
const I18N_Z = {
    RU: {
        settings: 'Настройки', st_look: 'Оформление', st_lang: 'Язык', st_color: 'Цвет панели', st_color_rnd: 'Случайный', st_custom: 'Свой цвет', st_scale: 'Размер панели',
        st_hue: 'Оттенок', st_sat: 'Насыщенность', st_lig: 'Яркость',
        st_site_dark: 'Тёмная тема сайта', st_btns: 'Кнопки панели', st_btns_hint: 'Нажмите, чтобы скрыть кнопку или вернуть её на панель.',
        st_btns_reset: 'Показать все кнопки', st_open: 'Открыть', st_rec: 'Запись видео', st_fav: 'Избранное', st_star: 'Звёздочка на миниатюрах', st_list: 'Список',
        st_hist: 'История просмотров', st_hist_on: 'Вести историю', st_data: 'Данные', bk_parts: 'Состав копии', bk_p_set: 'Настройки', bk_p_fav: 'Избранное', bk_p_hist: 'История', bk_csv: 'Таблицы CSV', bk_csv_fav: 'Избранное', bk_csv_hist: 'История', bk_csv_ses: 'Сеансы',
        bt_stats: 'Зрители', bt_vol: 'Громкость', bt_hints: 'Подсказки', sort_viewers: 'Зрители', viewers_tip: 'Зрителей в комнате',
        hist_title: 'История', hist_empty: 'Пока пусто. Время считается, пока идёт видео.', hist_s_last: 'Недавние', hist_s_time: 'Время', hist_s_vis: 'Визиты',
        hist_total: 'Моделей: {n} · Всего: {t}', hist_visits: 'виз.', hist_clear: 'Очистить', hist_clear_q: 'Удалить всю историю просмотров?',
        hist_del: 'Убрать из истории',
        star_add: 'В избранное', star_del: 'Убрать из избранного', star_del_q: 'У этой модели есть заметка или группа. Убрать из избранного?',
        cf_ok: 'Да', cf_cancel: 'Отмена'
    },
    EN: {
        settings: 'Settings', st_look: 'Appearance', st_lang: 'Language', st_color: 'Panel color', st_color_rnd: 'Random', st_custom: 'Custom color', st_scale: 'Panel size',
        st_hue: 'Hue', st_sat: 'Saturation', st_lig: 'Lightness',
        st_site_dark: 'Site dark theme', st_btns: 'Panel buttons', st_btns_hint: 'Tap to hide a button or bring it back.',
        st_btns_reset: 'Show all buttons', st_open: 'Open', st_rec: 'Video recording', st_fav: 'Favorites', st_star: 'Star on thumbnails', st_list: 'List',
        st_hist: 'Watch history', st_hist_on: 'Keep history', st_data: 'Data', bk_parts: 'Backup contents', bk_p_set: 'Settings', bk_p_fav: 'Favorites', bk_p_hist: 'History', bk_csv: 'CSV tables', bk_csv_fav: 'Favorites', bk_csv_hist: 'History', bk_csv_ses: 'Sessions',
        bt_stats: 'Viewers', bt_vol: 'Volume', bt_hints: 'Hints', sort_viewers: 'Viewers', viewers_tip: 'Viewers in the room',
        hist_title: 'History', hist_empty: 'Empty for now. Time is counted while the video is playing.', hist_s_last: 'Recent', hist_s_time: 'Time', hist_s_vis: 'Visits',
        hist_total: 'Models: {n} · Total: {t}', hist_visits: 'visits', hist_clear: 'Clear', hist_clear_q: 'Delete the whole watch history?',
        hist_del: 'Remove from history',
        star_add: 'Add to favorites', star_del: 'Remove from favorites', star_del_q: 'This model has a note or a group. Remove from favorites?',
        cf_ok: 'Yes', cf_cancel: 'Cancel'
    },
    UK: {
        settings: 'Налаштування', st_look: 'Оформлення', st_lang: 'Мова', st_color: 'Колір панелі', st_color_rnd: 'Випадковий', st_custom: 'Свій колір', st_scale: 'Розмір панелі',
        st_hue: 'Відтінок', st_sat: 'Насиченість', st_lig: 'Яскравість',
        st_site_dark: 'Темна тема сайту', st_btns: 'Кнопки панелі', st_btns_hint: 'Натисніть, щоб сховати кнопку або повернути її на панель.',
        st_btns_reset: 'Показати всі кнопки', st_open: 'Відкрити', st_rec: 'Запис відео', st_fav: 'Обране', st_star: 'Зірочка на мініатюрах', st_list: 'Список',
        st_hist: 'Історія переглядів', st_hist_on: 'Зберігати історію', st_data: 'Дані', bk_parts: 'Склад копії', bk_p_set: 'Налаштування', bk_p_fav: 'Обране', bk_p_hist: 'Історія', bk_csv: 'Таблиці CSV', bk_csv_fav: 'Обране', bk_csv_hist: 'Історія', bk_csv_ses: 'Сеанси',
        bt_stats: 'Глядачі', bt_vol: 'Гучність', bt_hints: 'Підказки', sort_viewers: 'Глядачі', viewers_tip: 'Глядачів у кімнаті',
        hist_title: 'Історія', hist_empty: 'Поки порожньо. Час враховується, поки йде відео.', hist_s_last: 'Нещодавні', hist_s_time: 'Час', hist_s_vis: 'Візити',
        hist_total: 'Моделей: {n} · Усього: {t}', hist_visits: 'віз.', hist_clear: 'Очистити', hist_clear_q: 'Видалити всю історію переглядів?',
        hist_del: 'Прибрати з історії',
        star_add: 'В обране', star_del: 'Прибрати з обраного', star_del_q: 'У цієї моделі є нотатка або група. Прибрати з обраного?',
        cf_ok: 'Так', cf_cancel: 'Скасувати'
    }
};
Object.keys(I18N_Z).forEach(k => { i18n[k] = Object.assign(i18n[k] || {}, I18N_Z[k]); });
const I18N_W = unpackI18N({"k":["settings","st_look","st_lang","st_color","st_color_rnd","st_custom","st_scale","st_hue","st_sat","st_lig","st_site_dark","st_btns","st_btns_hint","st_btns_reset","st_open","st_rec","st_fav","st_star","st_list","st_hist","st_hist_on","st_data","bk_parts","bk_p_set","bk_p_fav","bk_p_hist","bk_csv","bk_csv_fav","bk_csv_hist","bk_csv_ses","bt_stats","bt_vol","bt_hints","sort_viewers","viewers_tip","hist_title","hist_empty","hist_s_last","hist_s_time","hist_s_vis","hist_total","hist_visits","hist_clear","hist_clear_q","hist_del","star_add","star_del","star_del_q","cf_ok","cf_cancel"],"v":{"ES":["Ajustes","Apariencia","Idioma","Color del panel","Aleatorio","Color personalizado","Tamaño del panel","Tono","Saturación","Luminosidad","Tema oscuro del sitio","Botones del panel","Toca para ocultar un botón o devolverlo.","Mostrar todos los botones","Abrir","Grabación de vídeo","Favoritos","Estrella en las miniaturas","Lista","Historial de visualización","Guardar historial","Datos","Contenido de la copia","Ajustes","Favoritos","Historial","Tablas CSV","Favoritos","Historial","Sesiones","Espectadores","Volumen","Consejos","Espectadores","Espectadores en la sala","Historial","Vacío por ahora. El tiempo se cuenta mientras se reproduce el vídeo.","Recientes","Tiempo","Visitas","Modelos: {n} · Total: {t}","visitas","Borrar","¿Borrar todo el historial de visualización?","Quitar del historial","Añadir a favoritos","Quitar de favoritos","Este modelo tiene una nota o un grupo. ¿Quitar de favoritos?","Sí","Cancelar"],"DE":["Einstellungen","Darstellung","Sprache","Panelfarbe","Zufällig","Eigene Farbe","Panelgröße","Farbton","Sättigung","Helligkeit","Dunkles Seitendesign","Panel-Schaltflächen","Tippen, um eine Schaltfläche aus- oder wieder einzublenden.","Alle Schaltflächen anzeigen","Öffnen","Videoaufnahme","Favoriten","Stern auf Vorschaubildern","Liste","Wiedergabeverlauf","Verlauf speichern","Daten","Inhalt der Sicherung","Einstellungen","Favoriten","Verlauf","CSV-Tabellen","Favoriten","Verlauf","Sitzungen","Zuschauer","Lautstärke","Hinweise","Zuschauer","Zuschauer im Raum","Verlauf","Noch leer. Die Zeit wird gezählt, solange das Video läuft.","Zuletzt","Zeit","Besuche","Models: {n} · Gesamt: {t}","Besuche","Leeren","Gesamten Wiedergabeverlauf löschen?","Aus dem Verlauf entfernen","Zu Favoriten hinzufügen","Aus Favoriten entfernen","Dieses Model hat eine Notiz oder eine Gruppe. Aus Favoriten entfernen?","Ja","Abbrechen"],"FR":["Paramètres","Apparence","Langue","Couleur du panneau","Aléatoire","Couleur personnalisée","Taille du panneau","Teinte","Saturation","Luminosité","Thème sombre du site","Boutons du panneau","Touchez pour masquer un bouton ou le remettre.","Afficher tous les boutons","Ouvrir","Enregistrement vidéo","Favoris","Étoile sur les miniatures","Liste","Historique de visionnage","Conserver l’historique","Données","Contenu de la sauvegarde","Paramètres","Favoris","Historique","Tableaux CSV","Favoris","Historique","Sessions","Spectateurs","Volume","Astuces","Spectateurs","Spectateurs dans le salon","Historique","Vide pour l’instant. Le temps est compté pendant la lecture de la vidéo.","Récents","Durée","Visites","Modèles : {n} · Total : {t}","visites","Effacer","Supprimer tout l’historique de visionnage ?","Retirer de l’historique","Ajouter aux favoris","Retirer des favoris","Ce modèle a une note ou un groupe. Le retirer des favoris ?","Oui","Annuler"],"PT":["Configurações","Aparência","Idioma","Cor do painel","Aleatória","Cor personalizada","Tamanho do painel","Matiz","Saturação","Luminosidade","Tema escuro do site","Botões do painel","Toque para ocultar um botão ou trazê-lo de volta.","Mostrar todos os botões","Abrir","Gravação de vídeo","Favoritos","Estrela nas miniaturas","Lista","Histórico de visualização","Manter histórico","Dados","Conteúdo do backup","Configurações","Favoritos","Histórico","Tabelas CSV","Favoritos","Histórico","Sessões","Espectadores","Volume","Dicas","Espectadores","Espectadores na sala","Histórico","Vazio por enquanto. O tempo é contado enquanto o vídeo está tocando.","Recentes","Tempo","Visitas","Modelos: {n} · Total: {t}","visitas","Limpar","Apagar todo o histórico de visualização?","Remover do histórico","Adicionar aos favoritos","Remover dos favoritos","Este modelo tem uma nota ou um grupo. Remover dos favoritos?","Sim","Cancelar"],"IT":["Impostazioni","Aspetto","Lingua","Colore del pannello","Casuale","Colore personalizzato","Dimensione del pannello","Tonalità","Saturazione","Luminosità","Tema scuro del sito","Pulsanti del pannello","Tocca per nascondere un pulsante o riportarlo.","Mostra tutti i pulsanti","Apri","Registrazione video","Preferiti","Stella sulle miniature","Elenco","Cronologia di visione","Salva cronologia","Dati","Contenuto del backup","Impostazioni","Preferiti","Cronologia","Tabelle CSV","Preferiti","Cronologia","Sessioni","Spettatori","Volume","Suggerimenti","Spettatori","Spettatori nella stanza","Cronologia","Ancora vuota. Il tempo viene conteggiato mentre il video è in riproduzione.","Recenti","Tempo","Visite","Modelli: {n} · Totale: {t}","visite","Svuota","Eliminare tutta la cronologia di visione?","Rimuovi dalla cronologia","Aggiungi ai preferiti","Rimuovi dai preferiti","Questo modello ha una nota o un gruppo. Rimuoverlo dai preferiti?","Sì","Annulla"],"PL":["Ustawienia","Wygląd","Język","Kolor panelu","Losowy","Własny kolor","Rozmiar panelu","Odcień","Nasycenie","Jasność","Ciemny motyw strony","Przyciski panelu","Dotknij, aby ukryć przycisk lub go przywrócić.","Pokaż wszystkie przyciski","Otwórz","Nagrywanie wideo","Ulubione","Gwiazdka na miniaturach","Lista","Historia oglądania","Zapisuj historię","Dane","Zawartość kopii","Ustawienia","Ulubione","Historia","Tabele CSV","Ulubione","Historia","Sesje","Widzowie","Głośność","Podpowiedzi","Widzowie","Widzowie w pokoju","Historia","Na razie pusto. Czas jest liczony, gdy wideo jest odtwarzane.","Ostatnie","Czas","Wizyty","Modele: {n} · Razem: {t}","wizyt","Wyczyść","Usunąć całą historię oglądania?","Usuń z historii","Dodaj do ulubionych","Usuń z ulubionych","Ten model ma notatkę lub grupę. Usunąć z ulubionych?","Tak","Anuluj"],"TR":["Ayarlar","Görünüm","Dil","Panel rengi","Rastgele","Özel renk","Panel boyutu","Ton","Doygunluk","Parlaklık","Sitenin koyu teması","Panel düğmeleri","Bir düğmeyi gizlemek veya geri getirmek için dokunun.","Tüm düğmeleri göster","Aç","Video kaydı","Favoriler","Küçük resimlerde yıldız","Liste","İzleme geçmişi","Geçmişi tut","Veri","Yedek içeriği","Ayarlar","Favoriler","Geçmiş","CSV tabloları","Favoriler","Geçmiş","Oturumlar","İzleyiciler","Ses","İpuçları","İzleyiciler","Odadaki izleyiciler","Geçmiş","Şimdilik boş. Süre, video oynarken sayılır.","Son","Süre","Ziyaret","Modeller: {n} · Toplam: {t}","ziyaret","Temizle","Tüm izleme geçmişi silinsin mi?","Geçmişten kaldır","Favorilere ekle","Favorilerden kaldır","Bu modelin notu veya grubu var. Favorilerden kaldırılsın mı?","Evet","İptal"],"NL":["Instellingen","Uiterlijk","Taal","Paneelkleur","Willekeurig","Eigen kleur","Paneelgrootte","Tint","Verzadiging","Helderheid","Donker thema van de site","Paneelknoppen","Tik om een knop te verbergen of terug te zetten.","Alle knoppen tonen","Openen","Video-opname","Favorieten","Ster op miniaturen","Lijst","Kijkgeschiedenis","Geschiedenis bewaren","Gegevens","Inhoud van de back-up","Instellingen","Favorieten","Geschiedenis","CSV-tabellen","Favorieten","Geschiedenis","Sessies","Kijkers","Volume","Tips","Kijkers","Kijkers in de kamer","Geschiedenis","Nog leeg. De tijd wordt geteld terwijl de video speelt.","Recent","Tijd","Bezoeken","Modellen: {n} · Totaal: {t}","bezoeken","Wissen","De hele kijkgeschiedenis verwijderen?","Verwijderen uit geschiedenis","Toevoegen aan favorieten","Verwijderen uit favorieten","Dit model heeft een notitie of groep. Verwijderen uit favorieten?","Ja","Annuleren"],"CS":["Nastavení","Vzhled","Jazyk","Barva panelu","Náhodná","Vlastní barva","Velikost panelu","Odstín","Sytost","Jas","Tmavý motiv webu","Tlačítka panelu","Klepnutím tlačítko skryjete nebo vrátíte.","Zobrazit všechna tlačítka","Otevřít","Nahrávání videa","Oblíbené","Hvězdička na náhledech","Seznam","Historie sledování","Ukládat historii","Data","Obsah zálohy","Nastavení","Oblíbené","Historie","Tabulky CSV","Oblíbené","Historie","Relace","Diváci","Hlasitost","Tipy","Diváci","Diváci v místnosti","Historie","Zatím prázdné. Čas se počítá, dokud video běží.","Nedávné","Čas","Návštěvy","Modelky: {n} · Celkem: {t}","návštěv","Vymazat","Smazat celou historii sledování?","Odebrat z historie","Přidat do oblíbených","Odebrat z oblíbených","Tato modelka má poznámku nebo skupinu. Odebrat z oblíbených?","Ano","Zrušit"],"RO":["Setări","Aspect","Limbă","Culoarea panoului","Aleatorie","Culoare personalizată","Dimensiunea panoului","Nuanță","Saturație","Luminozitate","Tema întunecată a site-ului","Butoanele panoului","Atinge pentru a ascunde un buton sau a-l readuce.","Arată toate butoanele","Deschide","Înregistrare video","Favorite","Stea pe miniaturi","Listă","Istoric vizionări","Păstrează istoricul","Date","Conținutul copiei","Setări","Favorite","Istoric","Tabele CSV","Favorite","Istoric","Sesiuni","Spectatori","Volum","Sfaturi","Spectatori","Spectatori în cameră","Istoric","Gol deocamdată. Timpul se numără cât timp rulează videoul.","Recente","Timp","Vizite","Modele: {n} · Total: {t}","vizite","Șterge","Ștergi tot istoricul de vizionări?","Elimină din istoric","Adaugă la favorite","Elimină din favorite","Acest model are o notă sau un grup. Îl elimini din favorite?","Da","Anulează"],"HU":["Beállítások","Megjelenés","Nyelv","Panel színe","Véletlen","Egyéni szín","Panel mérete","Árnyalat","Telítettség","Fényerő","Az oldal sötét témája","Panelgombok","Koppints egy gomb elrejtéséhez vagy visszaállításához.","Összes gomb megjelenítése","Megnyitás","Videófelvétel","Kedvencek","Csillag az előnézeteken","Lista","Megtekintési előzmények","Előzmények mentése","Adatok","A mentés tartalma","Beállítások","Kedvencek","Előzmények","CSV-táblázatok","Kedvencek","Előzmények","Munkamenetek","Nézők","Hangerő","Tippek","Nézők","Nézők a szobában","Előzmények","Egyelőre üres. Az idő a videó lejátszása közben telik.","Legutóbbi","Idő","Látogatások","Modellek: {n} · Összesen: {t}","látogatás","Törlés","Törlöd a teljes megtekintési előzményt?","Eltávolítás az előzményekből","Hozzáadás a kedvencekhez","Eltávolítás a kedvencekből","Ennek a modellnek van jegyzete vagy csoportja. Eltávolítod a kedvencekből?","Igen","Mégse"],"BG":["Настройки","Оформление","Език","Цвят на панела","Случаен","Собствен цвят","Размер на панела","Нюанс","Наситеност","Яркост","Тъмна тема на сайта","Бутони на панела","Докоснете, за да скриете бутон или да го върнете.","Покажи всички бутони","Отвори","Запис на видео","Любими","Звезда върху миниатюрите","Списък","История на гледането","Пази история","Данни","Съдържание на копието","Настройки","Любими","История","CSV таблици","Любими","История","Сесии","Зрители","Сила на звука","Подсказки","Зрители","Зрители в стаята","История","Засега е празно. Времето се брои, докато видеото върви.","Скорошни","Време","Посещения","Модели: {n} · Общо: {t}","посещ.","Изчисти","Да се изтрие ли цялата история на гледане?","Премахни от историята","Добави в любими","Премахни от любими","Този модел има бележка или група. Да се премахне ли от любими?","Да","Отказ"],"EL":["Ρυθμίσεις","Εμφάνιση","Γλώσσα","Χρώμα πάνελ","Τυχαίο","Προσαρμοσμένο χρώμα","Μέγεθος πάνελ","Απόχρωση","Κορεσμός","Φωτεινότητα","Σκούρο θέμα ιστοτόπου","Κουμπιά πάνελ","Πατήστε για να κρύψετε ένα κουμπί ή να το επαναφέρετε.","Εμφάνιση όλων των κουμπιών","Άνοιγμα","Εγγραφή βίντεο","Αγαπημένα","Αστέρι στις μικρογραφίες","Λίστα","Ιστορικό προβολών","Διατήρηση ιστορικού","Δεδομένα","Περιεχόμενο αντιγράφου","Ρυθμίσεις","Αγαπημένα","Ιστορικό","Πίνακες CSV","Αγαπημένα","Ιστορικό","Συνεδρίες","Θεατές","Ένταση","Συμβουλές","Θεατές","Θεατές στο δωμάτιο","Ιστορικό","Άδειο προς το παρόν. Ο χρόνος μετριέται όσο παίζει το βίντεο.","Πρόσφατα","Χρόνος","Επισκέψεις","Μοντέλα: {n} · Σύνολο: {t}","επισκέψεις","Εκκαθάριση","Διαγραφή ολόκληρου του ιστορικού προβολών;","Αφαίρεση από το ιστορικό","Προσθήκη στα αγαπημένα","Αφαίρεση από τα αγαπημένα","Αυτό το μοντέλο έχει σημείωση ή ομάδα. Αφαίρεση από τα αγαπημένα;","Ναι","Ακύρωση"],"JA":["設定","外観","言語","パネルの色","ランダム","カスタムカラー","パネルのサイズ","色相","彩度","明度","サイトのダークテーマ","パネルのボタン","タップしてボタンを非表示にしたり、元に戻したりできます。","すべてのボタンを表示","開く","動画の録画","お気に入り","サムネイルの星","リスト","視聴履歴","履歴を保存","データ","バックアップの内容","設定","お気に入り","履歴","CSV表","お気に入り","履歴","セッション","視聴者","音量","ヒント","視聴者","ルームの視聴者数","履歴","まだ空です。動画の再生中に時間がカウントされます。","最近","時間","訪問","モデル: {n} · 合計: {t}","回","消去","視聴履歴をすべて削除しますか?","履歴から削除","お気に入りに追加","お気に入りから削除","このモデルにはメモまたはグループがあります。お気に入りから削除しますか?","はい","キャンセル"],"ZH":["设置","外观","语言","面板颜色","随机","自定义颜色","面板大小","色相","饱和度","亮度","网站深色主题","面板按钮","点按可隐藏按钮或将其恢复。","显示所有按钮","打开","视频录制","收藏夹","缩略图上的星标","列表","观看历史","保存历史","数据","备份内容","设置","收藏夹","历史","CSV 表格","收藏夹","历史","会话","观众","音量","提示","观众","房间内观众","历史","暂无记录。视频播放时才会计时。","最近","时长","访问","模特:{n} · 总计:{t}","次访问","清空","删除全部观看历史?","从历史中移除","加入收藏夹","从收藏夹移除","该模特有备注或分组。要从收藏夹移除吗?","是","取消"],"KO":["설정","외관","언어","패널 색상","무작위","사용자 지정 색상","패널 크기","색조","채도","명도","사이트 다크 테마","패널 버튼","버튼을 숨기거나 다시 표시하려면 탭하세요.","모든 버튼 표시","열기","영상 녹화","즐겨찾기","썸네일 별표","목록","시청 기록","기록 저장","데이터","백업 내용","설정","즐겨찾기","기록","CSV 표","즐겨찾기","기록","세션","시청자","볼륨","도움말","시청자","방 시청자 수","기록","아직 비어 있습니다. 영상이 재생되는 동안 시간이 집계됩니다.","최근","시간","방문","모델: {n} · 합계: {t}","회","비우기","시청 기록을 모두 삭제할까요?","기록에서 제거","즐겨찾기에 추가","즐겨찾기에서 제거","이 모델에 메모나 그룹이 있습니다. 즐겨찾기에서 제거할까요?","예","취소"],"HE":["הגדרות","מראה","שפה","צבע הפאנל","אקראי","צבע מותאם","גודל הפאנל","גוון","רוויה","בהירות","ערכת נושא כהה לאתר","כפתורי הפאנל","הקש כדי להסתיר כפתור או להחזיר אותו.","הצג את כל הכפתורים","פתח","הקלטת וידאו","מועדפים","כוכב על התמונות הממוזערות","רשימה","היסטוריית צפייה","שמור היסטוריה","נתונים","תוכן הגיבוי","הגדרות","מועדפים","היסטוריה","טבלאות CSV","מועדפים","היסטוריה","סשנים","צופים","עוצמת קול","טיפים","צופים","צופים בחדר","היסטוריה","ריק לבינתיים. הזמן נספר בזמן שהווידאו מנגן.","אחרונים","זמן","ביקורים","מודלים: {n} · סה״כ: {t}","ביקורים","נקה","למחוק את כל היסטוריית הצפייה?","הסר מההיסטוריה","הוסף למועדפים","הסר מהמועדפים","למודל הזה יש הערה או קבוצה. להסיר מהמועדפים?","כן","ביטול"],"AR":["الإعدادات","المظهر","اللغة","لون اللوحة","عشوائي","لون مخصص","حجم اللوحة","التدرج اللوني","التشبع","السطوع","الوضع الداكن للموقع","أزرار اللوحة","المس لإخفاء زر أو إعادته.","إظهار كل الأزرار","فتح","تسجيل الفيديو","المفضلة","نجمة على الصور المصغرة","القائمة","سجل المشاهدة","حفظ السجل","البيانات","محتوى النسخة الاحتياطية","الإعدادات","المفضلة","السجل","جداول CSV","المفضلة","السجل","الجلسات","المشاهدون","الصوت","تلميحات","المشاهدون","المشاهدون في الغرفة","السجل","فارغ حتى الآن. يُحتسب الوقت أثناء تشغيل الفيديو.","الأحدث","الوقت","الزيارات","العارضات: {n} · الإجمالي: {t}","زيارات","مسح","حذف كل سجل المشاهدة؟","إزالة من السجل","إضافة إلى المفضلة","إزالة من المفضلة","لدى هذه العارضة ملاحظة أو مجموعة. هل تريد إزالتها من المفضلة؟","نعم","إلغاء"],"HI":["सेटिंग्स","दिखावट","भाषा","पैनल का रंग","रैंडम","अपना रंग","पैनल का आकार","रंगत","संतृप्ति","चमक","साइट की डार्क थीम","पैनल बटन","किसी बटन को छिपाने या वापस लाने के लिए टैप करें।","सभी बटन दिखाएँ","खोलें","वीडियो रिकॉर्डिंग","पसंदीदा","थंबनेल पर तारा","सूची","देखने का इतिहास","इतिहास सहेजें","डेटा","बैकअप की सामग्री","सेटिंग्स","पसंदीदा","इतिहास","CSV तालिकाएँ","पसंदीदा","इतिहास","सेशन","दर्शक","आवाज़","सुझाव","दर्शक","कमरे में दर्शक","इतिहास","अभी खाली है। वीडियो चलने पर ही समय गिना जाता है।","हाल के","समय","विज़िट","मॉडल: {n} · कुल: {t}","विज़िट","साफ़ करें","पूरा देखने का इतिहास हटाएँ?","इतिहास से हटाएँ","पसंदीदा में जोड़ें","पसंदीदा से हटाएँ","इस मॉडल का नोट या ग्रुप है। पसंदीदा से हटाएँ?","हाँ","रद्द करें"],"ID":["Pengaturan","Tampilan","Bahasa","Warna panel","Acak","Warna kustom","Ukuran panel","Rona","Saturasi","Kecerahan","Tema gelap situs","Tombol panel","Ketuk untuk menyembunyikan tombol atau memunculkannya kembali.","Tampilkan semua tombol","Buka","Perekaman video","Favorit","Bintang di thumbnail","Daftar","Riwayat tontonan","Simpan riwayat","Data","Isi cadangan","Pengaturan","Favorit","Riwayat","Tabel CSV","Favorit","Riwayat","Sesi","Penonton","Volume","Petunjuk","Penonton","Penonton di ruangan","Riwayat","Masih kosong. Waktu dihitung saat video diputar.","Terbaru","Waktu","Kunjungan","Model: {n} · Total: {t}","kunjungan","Hapus","Hapus seluruh riwayat tontonan?","Hapus dari riwayat","Tambah ke favorit","Hapus dari favorit","Model ini punya catatan atau grup. Hapus dari favorit?","Ya","Batal"],"VI":["Cài đặt","Giao diện","Ngôn ngữ","Màu bảng điều khiển","Ngẫu nhiên","Màu tùy chỉnh","Kích thước bảng","Sắc độ","Độ bão hòa","Độ sáng","Giao diện tối của trang","Nút trên bảng","Chạm để ẩn nút hoặc hiện lại.","Hiện tất cả nút","Mở","Ghi video","Yêu thích","Ngôi sao trên ảnh thu nhỏ","Danh sách","Lịch sử xem","Lưu lịch sử","Dữ liệu","Nội dung bản sao lưu","Cài đặt","Yêu thích","Lịch sử","Bảng CSV","Yêu thích","Lịch sử","Phiên","Người xem","Âm lượng","Gợi ý","Người xem","Người xem trong phòng","Lịch sử","Hiện còn trống. Thời gian được tính khi video đang phát.","Gần đây","Thời gian","Lượt xem","Người mẫu: {n} · Tổng: {t}","lượt","Xóa","Xóa toàn bộ lịch sử xem?","Xóa khỏi lịch sử","Thêm vào yêu thích","Xóa khỏi yêu thích","Người mẫu này có ghi chú hoặc nhóm. Xóa khỏi yêu thích?","Có","Hủy"],"TH":["การตั้งค่า","รูปลักษณ์","ภาษา","สีของแผง","สุ่ม","สีกำหนดเอง","ขนาดแผง","เฉดสี","ความอิ่มตัว","ความสว่าง","ธีมมืดของเว็บไซต์","ปุ่มบนแผง","แตะเพื่อซ่อนปุ่มหรือนำกลับมา","แสดงปุ่มทั้งหมด","เปิด","การบันทึกวิดีโอ","รายการโปรด","ดาวบนภาพขนาดย่อ","รายการ","ประวัติการรับชม","เก็บประวัติ","ข้อมูล","เนื้อหาของข้อมูลสำรอง","การตั้งค่า","รายการโปรด","ประวัติ","ตาราง CSV","รายการโปรด","ประวัติ","เซสชัน","ผู้ชม","ระดับเสียง","คำแนะนำ","ผู้ชม","ผู้ชมในห้อง","ประวัติ","ยังว่างอยู่ เวลาจะนับขณะที่วิดีโอเล่น","ล่าสุด","เวลา","การเข้าชม","โมเดล: {n} · รวม: {t}","ครั้ง","ล้าง","ลบประวัติการรับชมทั้งหมดหรือไม่?","นำออกจากประวัติ","เพิ่มในรายการโปรด","นำออกจากรายการโปรด","โมเดลนี้มีโน้ตหรือกลุ่ม นำออกจากรายการโปรดหรือไม่?","ใช่","ยกเลิก"]}});
Object.keys(I18N_W).forEach(k => { i18n[k] = Object.assign(i18n[k] || {}, I18N_W[k]); });
const I18N_FIX = {"ES": {"bg": "FONDO","bk_exp": "Exportar copia de seguridad","bk_imp": "Importar copia de seguridad","rs_off": "Desactivado","star_del_q": "Esta modelo tiene una nota o un grupo. ¿Quitar de favoritos?"},"DE": {"bg": "HINT.","bk_exp": "Sicherung exportieren","bk_imp": "Sicherung importieren"},"FR": {"bg": "FOND","bk_exp": "Exporter la sauvegarde","bk_imp": "Importer la sauvegarde","rs_off": "Désactivé"},"PT": {"bg": "FUNDO","bk_exp": "Exportar backup","bk_imp": "Importar backup","rs_off": "Desativado","star_del_q": "Esta modelo tem uma nota ou um grupo. Remover dos favoritos?"},"IT": {"bg": "SFONDO","bk_exp": "Esporta backup","bk_imp": "Importa backup","rs_off": "Disattivato","star_del_q": "Questa modella ha una nota o un gruppo. Rimuoverla dai preferiti?","hist_total": "Modelle: {n} · Totale: {t}"},"PL": {"bk_exp": "Eksport kopii zapasowej","bk_imp": "Import kopii zapasowej","star_del_q": "Ta modelka ma notatkę lub grupę. Usunąć z ulubionych?","hist_total": "Modelki: {n} · Razem: {t}"},"TR": {"bk_exp": "Yedeği dışa aktar","bk_imp": "Yedeği içe aktar"},"NL": {"bk_exp": "Back-up exporteren","bk_imp": "Back-up importeren"},"CS": {"bk_exp": "Export zálohy","bk_imp": "Import zálohy"},"RO": {"sort_last": "Văzut","bk_exp": "Exportă copia de rezervă","bk_imp": "Importă copia de rezervă"},"HU": {"bk_exp": "Biztonsági mentés exportálása","bk_imp": "Biztonsági mentés importálása"},"BG": {"bk_exp": "Експорт на резервно копие","bk_imp": "Импорт на резервно копие"},"EL": {"rel": "Ανανέωση","bk_exp": "Εξαγωγή αντιγράφου ασφαλείας","bk_imp": "Εισαγωγή αντιγράφου ασφαλείας","rs_off": "Ανενεργό","st_private": "Ιδιωτικό","st_group": "Ομάδα"},"JA": {"bk_exp": "バックアップをエクスポート","bk_imp": "バックアップをインポート"},"ZH": {"bg": "背景","bk_exp": "导出备份","bk_imp": "导入备份","star_del_q": "该主播有备注或分组。要从收藏夹移除吗?","hist_total": "主播:{n} · 总计:{t}"},"KO": {"bk_exp": "백업 내보내기","bk_imp": "백업 가져오기"},"HE": {"bk_exp": "ייצוא גיבוי","bk_imp": "ייבוא גיבוי"},"AR": {"bk_exp": "تصدير النسخة الاحتياطية","bk_imp": "استيراد النسخة الاحتياطية","star_del_q": "لدى هذا الموديل ملاحظة أو مجموعة. هل تريد إزالته من المفضلة؟","hist_total": "الموديلات: {n} · الإجمالي: {t}"},"HI": {"st_away": "अनुपलब्ध","bk_exp": "बैकअप निर्यात करें","bk_imp": "बैकअप आयात करें","no_model": "मॉडल नहीं मिला","bm_nomatch": "फ़िल्टर से कोई मॉडल मेल नहीं खाता"},"ID": {"st_away": "Tidak di tempat","sort_last": "Terakhir dilihat","bk_exp": "Ekspor cadangan","bk_imp": "Impor cadangan"},"VI": {"bk_exp": "Xuất bản sao lưu","bk_imp": "Nhập bản sao lưu","hist_total": "Model: {n} · Tổng: {t}"},"TH": {"bk_exp": "ส่งออกข้อมูลสำรอง","bk_imp": "นำเข้าข้อมูลสำรอง"},"UK": {"bk_exp": "Експорт резервної копії","bk_imp": "Імпорт резервної копії"}};
Object.keys(I18N_FIX).forEach(k => { i18n[k] = Object.assign(i18n[k] || {}, I18N_FIX[k]); });
const I18N_HIDE = {"ES":{"st_ptags":"Ocultar etiquetas del perfil","st_hide_note":"Ocultar campo de nota (etiquetas)"},"DE":{"st_ptags":"Profil-Tags ausblenden","st_hide_note":"Notizfeld (Tags) ausblenden"},"FR":{"st_ptags":"Masquer les tags du profil","st_hide_note":"Masquer le champ de note (tags)"},"PT":{"st_ptags":"Ocultar tags do perfil","st_hide_note":"Ocultar campo de nota (tags)"},"IT":{"st_ptags":"Nascondi i tag del profilo","st_hide_note":"Nascondi il campo note (tag)"},"PL":{"st_ptags":"Ukryj tagi profilu","st_hide_note":"Ukryj pole notatki (tagi)"},"TR":{"st_ptags":"Profil etiketlerini gizle","st_hide_note":"Not alanını gizle (etiketler)"},"NL":{"st_ptags":"Profieltags verbergen","st_hide_note":"Notitieveld (tags) verbergen"},"CS":{"st_ptags":"Skrýt štítky profilu","st_hide_note":"Skrýt pole poznámky (štítky)"},"RO":{"st_ptags":"Ascunde etichetele profilului","st_hide_note":"Ascunde câmpul de notițe (etichete)"},"HU":{"st_ptags":"Profilcímkék elrejtése","st_hide_note":"Megjegyzés mező elrejtése (címkék)"},"BG":{"st_ptags":"Скрий таговете на профила","st_hide_note":"Скрий полето за бележка (тагове)"},"EL":{"st_ptags":"Απόκρυψη ετικετών προφίλ","st_hide_note":"Απόκρυψη πεδίου σημείωσης (ετικέτες)"},"JA":{"st_ptags":"プロフィールのタグを非表示","st_hide_note":"メモ欄(タグ)を非表示"},"ZH":{"st_ptags":"隐藏个人资料标签","st_hide_note":"隐藏备注栏(标签)"},"KO":{"st_ptags":"프로필 태그 숨기기","st_hide_note":"메모 입력란(태그) 숨기기"},"HE":{"st_ptags":"הסתר תגיות פרופיל","st_hide_note":"הסתר שדה הערה (תגיות)"},"AR":{"st_ptags":"إخفاء وسوم الملف الشخصي","st_hide_note":"إخفاء حقل الملاحظة (الوسوم)"},"HI":{"st_ptags":"प्रोफ़ाइल टैग छिपाएँ","st_hide_note":"नोट फ़ील्ड (टैग) छिपाएँ"},"ID":{"st_ptags":"Sembunyikan tag profil","st_hide_note":"Sembunyikan kolom catatan (tag)"},"VI":{"st_ptags":"Ẩn thẻ hồ sơ","st_hide_note":"Ẩn ô ghi chú (thẻ)"},"TH":{"st_ptags":"ซ่อนแท็กโปรไฟล์","st_hide_note":"ซ่อนช่องบันทึก (แท็ก)"}};
Object.keys(I18N_HIDE).forEach(k => { Object.assign(i18n[k], I18N_HIDE[k]); });
Object.assign(i18n.RU, { sleep_title: 'Таймер сна', sleep_hint: 'Через выбранное время плеер будет выключен, а запись остановится и сохранится. Нажмите на чёрный экран, чтобы вернуть плеер.', sleep_left: 'Осталось', sleep_custom: 'Своё время', sleep_sec: 'сек', sleep_start: 'Запустить', sleep_wake: 'Таймер сна сработал.\nНажмите, чтобы продолжить' });
Object.assign(i18n.EN, { sleep_title: 'Sleep timer', sleep_hint: 'When time is up, the player is switched off and any recording stops and is saved. Tap the black screen to bring it back.', sleep_left: 'Left', sleep_custom: 'Custom time', sleep_sec: 'sec', sleep_start: 'Start', sleep_wake: 'Sleep timer finished.\nTap to continue' });
i18n.UK = Object.assign(i18n.UK || {}, { sleep_title: 'Таймер сну', sleep_hint: 'Через обраний час плеєр буде вимкнено, а запис зупиниться й збережеться. Натисніть на чорний екран, щоб повернути плеєр.', sleep_left: 'Залишилось', sleep_custom: 'Свій час', sleep_sec: 'сек', sleep_start: 'Запустити', sleep_wake: 'Таймер сну спрацював.\nНатисніть, щоб продовжити' });
Object.assign(i18n.RU, { ch_btn: 'Диаграммы', ch_days: 'Время по дням, 14 дней', ch_hours: 'Активность по часам', ch_top: 'Топ по времени', ch_peak: 'Пик', ch_avg: 'В среднем в день' });
Object.assign(i18n.EN, { ch_btn: 'Charts', ch_days: 'Time per day, 14 days', ch_hours: 'Activity by hour', ch_top: 'Top by time', ch_peak: 'Peak', ch_avg: 'Daily average' });
i18n.UK = Object.assign(i18n.UK || {}, { ch_btn: 'Діаграми', ch_days: 'Час по днях, 14 днів', ch_hours: 'Активність по годинах', ch_top: 'Топ за часом', ch_peak: 'Пік', ch_avg: 'У середньому за день' });
const I18N_S = {
    RU: { st_cols: "Колонки", st_back: "Назад", st_ptags: "Скрыть теги профиля", st_hide_note: "Скрыть поле заметки (теги)" },
    EN: { st_cols: "Columns", st_back: "Back", st_ptags: "Hide profile tags", st_hide_note: "Hide note field (tags)" },
    UK: { st_cols: "Колонки", st_back: "Назад", st_ptags: "Сховати теги профілю", st_hide_note: "Сховати поле нотатки (теги)" },
    ES: { sleep_title: "Temporizador de apagado", sleep_hint: "Al terminar el tiempo, el reproductor se apaga y cualquier grabación se detiene y se guarda. Toca la pantalla negra para recuperarlo.", sleep_left: "Quedan", sleep_custom: "Tiempo personalizado", sleep_sec: "seg", sleep_start: "Iniciar", sleep_wake: "El temporizador ha terminado.\nToca para continuar", st_cols: "Columnas", st_back: "Atrás" },
    DE: { sleep_title: "Schlaf-Timer", sleep_hint: "Nach Ablauf der Zeit wird der Player ausgeschaltet, und eine laufende Aufnahme wird gestoppt und gespeichert. Tippe auf den schwarzen Bildschirm, um ihn zurückzuholen.", sleep_left: "Übrig", sleep_custom: "Eigene Zeit", sleep_sec: "Sek", sleep_start: "Starten", sleep_wake: "Schlaf-Timer abgelaufen.\nTippen zum Fortsetzen", st_cols: "Spalten", st_back: "Zurück" },
    FR: { sleep_title: "Minuteur de veille", sleep_hint: "À la fin du temps, le lecteur s’éteint et tout enregistrement s’arrête et est sauvegardé. Touchez l’écran noir pour le rallumer.", sleep_left: "Restant", sleep_custom: "Durée personnalisée", sleep_sec: "s", sleep_start: "Démarrer", sleep_wake: "Minuteur terminé.\nTouchez pour continuer", st_cols: "Colonnes", st_back: "Retour" },
    PT: { sleep_title: "Temporizador de sono", sleep_hint: "Ao fim do tempo, o player é desligado e qualquer gravação é interrompida e salva. Toque na tela preta para trazê-lo de volta.", sleep_left: "Restante", sleep_custom: "Tempo personalizado", sleep_sec: "seg", sleep_start: "Iniciar", sleep_wake: "O temporizador terminou.\nToque para continuar", st_cols: "Colunas", st_back: "Voltar" },
    IT: { sleep_title: "Timer di spegnimento", sleep_hint: "Allo scadere del tempo il player si spegne e ogni registrazione si interrompe e viene salvata. Tocca lo schermo nero per riattivarlo.", sleep_left: "Rimanente", sleep_custom: "Tempo personalizzato", sleep_sec: "sec", sleep_start: "Avvia", sleep_wake: "Timer terminato.\nTocca per continuare", st_cols: "Colonne", st_back: "Indietro" },
    PL: { sleep_title: "Wyłącznik czasowy", sleep_hint: "Po upływie czasu odtwarzacz zostanie wyłączony, a nagrywanie zatrzymane i zapisane. Dotknij czarnego ekranu, aby go przywrócić.", sleep_left: "Pozostało", sleep_custom: "Własny czas", sleep_sec: "sek", sleep_start: "Start", sleep_wake: "Czas minął.\nDotknij, aby kontynuować", st_cols: "Kolumny", st_back: "Wstecz" },
    TR: { sleep_title: "Uyku zamanlayıcısı", sleep_hint: "Süre dolunca oynatıcı kapanır, varsa kayıt durdurulur ve kaydedilir. Geri getirmek için siyah ekrana dokunun.", sleep_left: "Kalan", sleep_custom: "Özel süre", sleep_sec: "sn", sleep_start: "Başlat", sleep_wake: "Zamanlayıcı bitti.\nDevam etmek için dokunun", st_cols: "Sütunlar", st_back: "Geri" },
    NL: { sleep_title: "Slaaptimer", sleep_hint: "Als de tijd om is, wordt de speler uitgeschakeld en wordt een lopende opname gestopt en opgeslagen. Tik op het zwarte scherm om de speler terug te halen.", sleep_left: "Resterend", sleep_custom: "Eigen tijd", sleep_sec: "sec", sleep_start: "Starten", sleep_wake: "Slaaptimer afgelopen.\nTik om door te gaan", st_cols: "Kolommen", st_back: "Terug" },
    CS: { sleep_title: "Časovač vypnutí", sleep_hint: "Po uplynutí času se přehrávač vypne a případné nahrávání se zastaví a uloží. Klepnutím na černou obrazovku ho vrátíte.", sleep_left: "Zbývá", sleep_custom: "Vlastní čas", sleep_sec: "s", sleep_start: "Spustit", sleep_wake: "Časovač skončil.\nKlepnutím pokračujte", st_cols: "Sloupce", st_back: "Zpět" },
    RO: { sleep_title: "Temporizator de somn", sleep_hint: "La expirarea timpului, playerul se oprește, iar orice înregistrare se oprește și se salvează. Atinge ecranul negru pentru a-l readuce.", sleep_left: "Rămas", sleep_custom: "Timp personalizat", sleep_sec: "sec", sleep_start: "Pornește", sleep_wake: "Temporizatorul s-a încheiat.\nAtinge pentru a continua", st_cols: "Coloane", st_back: "Înapoi" },
    HU: { sleep_title: "Alvásidőzítő", sleep_hint: "Az idő leteltével a lejátszó kikapcsol, a felvétel pedig leáll és mentésre kerül. Koppints a fekete képernyőre a visszakapcsoláshoz.", sleep_left: "Hátra van", sleep_custom: "Egyéni idő", sleep_sec: "mp", sleep_start: "Indítás", sleep_wake: "Az időzítő lejárt.\nKoppints a folytatáshoz", st_cols: "Oszlopok", st_back: "Vissza" },
    BG: { sleep_title: "Таймер за заспиване", sleep_hint: "Когато времето изтече, плеърът се изключва, а всеки запис спира и се запазва. Докоснете черния екран, за да го върнете.", sleep_left: "Остава", sleep_custom: "Собствено време", sleep_sec: "сек", sleep_start: "Старт", sleep_wake: "Таймерът приключи.\nДокоснете, за да продължите", st_cols: "Колони", st_back: "Назад" },
    EL: { sleep_title: "Χρονοδιακόπτης ύπνου", sleep_hint: "Όταν λήξει ο χρόνος, ο player απενεργοποιείται και κάθε εγγραφή σταματά και αποθηκεύεται. Αγγίξτε τη μαύρη οθόνη για να τον επαναφέρετε.", sleep_left: "Απομένουν", sleep_custom: "Προσαρμοσμένος χρόνος", sleep_sec: "δευτ.", sleep_start: "Έναρξη", sleep_wake: "Ο χρονοδιακόπτης έληξε.\nΑγγίξτε για συνέχεια", st_cols: "Στήλες", st_back: "Πίσω" },
    JA: { sleep_title: "スリープタイマー", sleep_hint: "時間になるとプレーヤーが停止し、録画中の場合は録画が止まって保存されます。黒い画面をタップすると元に戻ります。", sleep_left: "残り", sleep_custom: "時間を指定", sleep_sec: "秒", sleep_start: "開始", sleep_wake: "スリープタイマーが終了しました。\nタップして続行", st_cols: "列数", st_back: "戻る" },
    ZH: { sleep_title: "睡眠定时器", sleep_hint: "时间到后,播放器会关闭,正在进行的录制会停止并保存。点按黑屏即可恢复播放器。", sleep_left: "剩余", sleep_custom: "自定义时间", sleep_sec: "秒", sleep_start: "开始", sleep_wake: "睡眠定时已结束。\n点按继续", st_cols: "列数", st_back: "返回" },
    KO: { sleep_title: "취침 타이머", sleep_hint: "시간이 되면 플레이어가 꺼지고 녹화 중이던 영상은 중지되어 저장됩니다. 검은 화면을 탭하면 플레이어가 돌아옵니다.", sleep_left: "남음", sleep_custom: "직접 설정", sleep_sec: "초", sleep_start: "시작", sleep_wake: "취침 타이머가 종료되었습니다.\n탭하여 계속", st_cols: "열 수", st_back: "뒤로" },
    HE: { sleep_title: "טיימר שינה", sleep_hint: "בתום הזמן הנגן יכבה, וכל הקלטה תיעצר ותישמר. הקש על המסך השחור כדי להחזיר את הנגן.", sleep_left: "נותר", sleep_custom: "זמן מותאם", sleep_sec: "שנ׳", sleep_start: "התחל", sleep_wake: "טיימר השינה הסתיים.\nהקש להמשך", st_cols: "עמודות", st_back: "חזרה" },
    AR: { sleep_title: "مؤقّت النوم", sleep_hint: "عند انتهاء الوقت يُطفأ المشغّل ويتوقف أي تسجيل ويُحفظ. المس الشاشة السوداء لإعادته.", sleep_left: "المتبقي", sleep_custom: "وقت مخصص", sleep_sec: "ث", sleep_start: "ابدأ", sleep_wake: "انتهى مؤقّت النوم.\nالمس للمتابعة", st_cols: "الأعمدة", st_back: "رجوع" },
    HI: { sleep_title: "स्लीप टाइमर", sleep_hint: "समय पूरा होने पर प्लेयर बंद हो जाएगा, और चल रही रिकॉर्डिंग रुककर सेव हो जाएगी। प्लेयर वापस लाने के लिए काली स्क्रीन पर टैप करें।", sleep_left: "शेष", sleep_custom: "अपना समय", sleep_sec: "सेक", sleep_start: "शुरू करें", sleep_wake: "स्लीप टाइमर पूरा हुआ।\nजारी रखने के लिए टैप करें", st_cols: "कॉलम", st_back: "वापस" },
    ID: { sleep_title: "Timer tidur", sleep_hint: "Saat waktu habis, pemutar dimatikan dan rekaman yang berjalan dihentikan lalu disimpan. Ketuk layar hitam untuk mengembalikannya.", sleep_left: "Sisa", sleep_custom: "Waktu kustom", sleep_sec: "dtk", sleep_start: "Mulai", sleep_wake: "Timer tidur selesai.\nKetuk untuk melanjutkan", st_cols: "Kolom", st_back: "Kembali" },
    VI: { sleep_title: "Hẹn giờ tắt", sleep_hint: "Khi hết giờ, trình phát sẽ tắt và mọi bản ghi đang chạy sẽ dừng và được lưu. Chạm vào màn hình đen để bật lại.", sleep_left: "Còn lại", sleep_custom: "Thời gian tùy chỉnh", sleep_sec: "giây", sleep_start: "Bắt đầu", sleep_wake: "Hẹn giờ đã kết thúc.\nChạm để tiếp tục", st_cols: "Số cột", st_back: "Quay lại" },
    TH: { sleep_title: "ตั้งเวลาปิด", sleep_hint: "เมื่อหมดเวลา เครื่องเล่นจะปิด และการอัดที่กำลังทำอยู่จะหยุดและบันทึกไว้ แตะหน้าจอสีดำเพื่อเปิดกลับมา", sleep_left: "เหลือ", sleep_custom: "กำหนดเวลาเอง", sleep_sec: "วินาที", sleep_start: "เริ่ม", sleep_wake: "ตั้งเวลาปิดสิ้นสุดแล้ว\nแตะเพื่อดำเนินการต่อ", st_cols: "จำนวนคอลัมน์", st_back: "ย้อนกลับ" }
};
Object.keys(I18N_S).forEach(k => { i18n[k] = Object.assign(i18n[k] || {}, I18N_S[k]); });
const I18N_RAD = {
    RU: { rad_title: 'Круговое меню', rad_reset: 'Сбросить позицию кружка', rad_media: 'Медиа', rad_view: 'Экран', rad_nav: 'Избранное', rad_page: 'Страница', rad_vup: 'Громче', rad_vdn: 'Тише', rad_prev: 'Пред.', rad_next: 'След.' },
    EN: { rad_title: 'Radial menu', rad_reset: 'Reset button position', rad_media: 'Media', rad_view: 'View', rad_nav: 'Favorites', rad_page: 'Page', rad_vup: 'Louder', rad_vdn: 'Quieter', rad_prev: 'Prev', rad_next: 'Next' },
    UK: { rad_title: 'Колове меню', rad_reset: 'Скинути позицію кружечка', rad_media: 'Медіа', rad_view: 'Екран', rad_nav: 'Обране', rad_page: 'Сторінка', rad_vup: 'Гучніше', rad_vdn: 'Тихіше', rad_prev: 'Попер.', rad_next: 'Наст.' },
    ES: { ch_btn: "Gráficos", ch_days: "Tiempo por día, 14 días", ch_hours: "Actividad por hora", ch_top: "Top por tiempo", ch_peak: "Pico", ch_avg: "Media diaria", rad_title: "Menú radial", rad_reset: "Restablecer posición del botón", rad_media: "Medios", rad_view: "Pantalla", rad_nav: "Favoritos", rad_page: "Página", rad_vup: "Más alto", rad_vdn: "Más bajo", rad_prev: "Ant.", rad_next: "Sig." },
    DE: { ch_btn: "Diagramme", ch_days: "Zeit pro Tag, 14 Tage", ch_hours: "Aktivität nach Stunde", ch_top: "Top nach Zeit", ch_peak: "Spitze", ch_avg: "Tagesdurchschnitt", rad_title: "Radialmenü", rad_reset: "Position des Buttons zurücksetzen", rad_media: "Medien", rad_view: "Ansicht", rad_nav: "Favoriten", rad_page: "Seite", rad_vup: "Lauter", rad_vdn: "Leiser", rad_prev: "Zurück", rad_next: "Weiter" },
    FR: { ch_btn: "Graphiques", ch_days: "Temps par jour, 14 jours", ch_hours: "Activité par heure", ch_top: "Top par durée", ch_peak: "Pic", ch_avg: "Moyenne quotidienne", rad_title: "Menu radial", rad_reset: "Réinitialiser la position du bouton", rad_media: "Médias", rad_view: "Affichage", rad_nav: "Favoris", rad_page: "Page", rad_vup: "Plus fort", rad_vdn: "Moins fort", rad_prev: "Préc.", rad_next: "Suiv." },
    PT: { ch_btn: "Gráficos", ch_days: "Tempo por dia, 14 dias", ch_hours: "Atividade por hora", ch_top: "Top por tempo", ch_peak: "Pico", ch_avg: "Média diária", rad_title: "Menu radial", rad_reset: "Redefinir posição do botão", rad_media: "Mídia", rad_view: "Tela", rad_nav: "Favoritos", rad_page: "Página", rad_vup: "Mais alto", rad_vdn: "Mais baixo", rad_prev: "Ant.", rad_next: "Próx." },
    IT: { ch_btn: "Grafici", ch_days: "Tempo per giorno, 14 giorni", ch_hours: "Attività per ora", ch_top: "Top per tempo", ch_peak: "Picco", ch_avg: "Media giornaliera", rad_title: "Menu radiale", rad_reset: "Reimposta posizione del pulsante", rad_media: "Media", rad_view: "Schermo", rad_nav: "Preferiti", rad_page: "Pagina", rad_vup: "Più forte", rad_vdn: "Più piano", rad_prev: "Prec.", rad_next: "Succ." },
    PL: { ch_btn: "Wykresy", ch_days: "Czas dziennie, 14 dni", ch_hours: "Aktywność według godzin", ch_top: "Top według czasu", ch_peak: "Szczyt", ch_avg: "Średnia dzienna", rad_title: "Menu kołowe", rad_reset: "Resetuj pozycję przycisku", rad_media: "Media", rad_view: "Widok", rad_nav: "Ulubione", rad_page: "Strona", rad_vup: "Głośniej", rad_vdn: "Ciszej", rad_prev: "Poprz.", rad_next: "Nast." },
    TR: { ch_btn: "Grafikler", ch_days: "Günlük süre, 14 gün", ch_hours: "Saate göre etkinlik", ch_top: "Süreye göre en çok", ch_peak: "Zirve", ch_avg: "Günlük ortalama", rad_title: "Dairesel menü", rad_reset: "Düğme konumunu sıfırla", rad_media: "Medya", rad_view: "Ekran", rad_nav: "Favoriler", rad_page: "Sayfa", rad_vup: "Daha yüksek", rad_vdn: "Daha kısık", rad_prev: "Önceki", rad_next: "Sonraki" },
    NL: { ch_btn: "Grafieken", ch_days: "Tijd per dag, 14 dagen", ch_hours: "Activiteit per uur", ch_top: "Top op tijd", ch_peak: "Piek", ch_avg: "Daggemiddelde", rad_title: "Radiaal menu", rad_reset: "Knoppositie resetten", rad_media: "Media", rad_view: "Weergave", rad_nav: "Favorieten", rad_page: "Pagina", rad_vup: "Harder", rad_vdn: "Zachter", rad_prev: "Vorige", rad_next: "Volgende" },
    CS: { ch_btn: "Grafy", ch_days: "Čas za den, 14 dní", ch_hours: "Aktivita podle hodin", ch_top: "Top podle času", ch_peak: "Špička", ch_avg: "Denní průměr", rad_title: "Kruhové menu", rad_reset: "Obnovit pozici tlačítka", rad_media: "Média", rad_view: "Zobrazení", rad_nav: "Oblíbené", rad_page: "Stránka", rad_vup: "Hlasitěji", rad_vdn: "Tišeji", rad_prev: "Předch.", rad_next: "Další" },
    RO: { ch_btn: "Grafice", ch_days: "Timp pe zi, 14 zile", ch_hours: "Activitate pe ore", ch_top: "Top după timp", ch_peak: "Vârf", ch_avg: "Media zilnică", rad_title: "Meniu radial", rad_reset: "Resetează poziția butonului", rad_media: "Media", rad_view: "Ecran", rad_nav: "Favorite", rad_page: "Pagină", rad_vup: "Mai tare", rad_vdn: "Mai încet", rad_prev: "Ant.", rad_next: "Urm." },
    HU: { ch_btn: "Diagramok", ch_days: "Idő naponta, 14 nap", ch_hours: "Aktivitás óránként", ch_top: "Toplista idő szerint", ch_peak: "Csúcs", ch_avg: "Napi átlag", rad_title: "Körmenü", rad_reset: "Gomb helyének visszaállítása", rad_media: "Média", rad_view: "Nézet", rad_nav: "Kedvencek", rad_page: "Oldal", rad_vup: "Hangosabb", rad_vdn: "Halkabb", rad_prev: "Előző", rad_next: "Következő" },
    BG: { ch_btn: "Диаграми", ch_days: "Време по дни, 14 дни", ch_hours: "Активност по часове", ch_top: "Топ по време", ch_peak: "Пик", ch_avg: "Средно на ден", rad_title: "Радиално меню", rad_reset: "Нулиране на позицията на бутона", rad_media: "Медия", rad_view: "Екран", rad_nav: "Любими", rad_page: "Страница", rad_vup: "По-силно", rad_vdn: "По-тихо", rad_prev: "Пред.", rad_next: "След." },
    EL: { ch_btn: "Διαγράμματα", ch_days: "Χρόνος ανά ημέρα, 14 ημέρες", ch_hours: "Δραστηριότητα ανά ώρα", ch_top: "Κορυφαία ανά χρόνο", ch_peak: "Κορύφωση", ch_avg: "Ημερήσιος μέσος όρος", rad_title: "Κυκλικό μενού", rad_reset: "Επαναφορά θέσης κουμπιού", rad_media: "Πολυμέσα", rad_view: "Προβολή", rad_nav: "Αγαπημένα", rad_page: "Σελίδα", rad_vup: "Πιο δυνατά", rad_vdn: "Πιο χαμηλά", rad_prev: "Προηγ.", rad_next: "Επόμ." },
    JA: { ch_btn: "グラフ", ch_days: "1日あたりの時間(14日間)", ch_hours: "時間帯別のアクティビティ", ch_top: "時間ランキング", ch_peak: "ピーク", ch_avg: "1日の平均", rad_title: "ラジアルメニュー", rad_reset: "ボタン位置をリセット", rad_media: "メディア", rad_view: "表示", rad_nav: "お気に入り", rad_page: "ページ", rad_vup: "音量アップ", rad_vdn: "音量ダウン", rad_prev: "前へ", rad_next: "次へ" },
    ZH: { ch_btn: "图表", ch_days: "每日时长,14天", ch_hours: "按小时的活跃度", ch_top: "时长排行", ch_peak: "峰值", ch_avg: "日均", rad_title: "环形菜单", rad_reset: "重置按钮位置", rad_media: "媒体", rad_view: "显示", rad_nav: "收藏夹", rad_page: "页面", rad_vup: "调大", rad_vdn: "调小", rad_prev: "上一个", rad_next: "下一个" },
    KO: { ch_btn: "차트", ch_days: "일별 시간, 14일", ch_hours: "시간대별 활동", ch_top: "시간 순위", ch_peak: "최고치", ch_avg: "일평균", rad_title: "원형 메뉴", rad_reset: "버튼 위치 초기화", rad_media: "미디어", rad_view: "화면", rad_nav: "즐겨찾기", rad_page: "페이지", rad_vup: "소리 크게", rad_vdn: "소리 작게", rad_prev: "이전", rad_next: "다음" },
    HE: { ch_btn: "תרשימים", ch_days: "זמן ליום, 14 ימים", ch_hours: "פעילות לפי שעה", ch_top: "מובילים לפי זמן", ch_peak: "שיא", ch_avg: "ממוצע יומי", rad_title: "תפריט מעגלי", rad_reset: "איפוס מיקום הכפתור", rad_media: "מדיה", rad_view: "תצוגה", rad_nav: "מועדפים", rad_page: "עמוד", rad_vup: "חזק יותר", rad_vdn: "שקט יותר", rad_prev: "הקודם", rad_next: "הבא" },
    AR: { ch_btn: "الرسوم البيانية", ch_days: "الوقت يوميًا، 14 يومًا", ch_hours: "النشاط حسب الساعة", ch_top: "الأعلى حسب الوقت", ch_peak: "الذروة", ch_avg: "المتوسط اليومي", rad_title: "القائمة الدائرية", rad_reset: "إعادة ضبط موضع الزر", rad_media: "الوسائط", rad_view: "العرض", rad_nav: "المفضلة", rad_page: "الصفحة", rad_vup: "أعلى", rad_vdn: "أخفض", rad_prev: "السابق", rad_next: "التالي" },
    HI: { ch_btn: "चार्ट", ch_days: "प्रति दिन समय, 14 दिन", ch_hours: "घंटे के अनुसार गतिविधि", ch_top: "समय के अनुसार शीर्ष", ch_peak: "शिखर", ch_avg: "दैनिक औसत", rad_title: "गोलाकार मेनू", rad_reset: "बटन की स्थिति रीसेट करें", rad_media: "मीडिया", rad_view: "दृश्य", rad_nav: "पसंदीदा", rad_page: "पेज", rad_vup: "आवाज़ बढ़ाएँ", rad_vdn: "आवाज़ घटाएँ", rad_prev: "पिछला", rad_next: "अगला" },
    ID: { ch_btn: "Grafik", ch_days: "Waktu per hari, 14 hari", ch_hours: "Aktivitas per jam", ch_top: "Teratas menurut waktu", ch_peak: "Puncak", ch_avg: "Rata-rata harian", rad_title: "Menu radial", rad_reset: "Atur ulang posisi tombol", rad_media: "Media", rad_view: "Tampilan", rad_nav: "Favorit", rad_page: "Halaman", rad_vup: "Lebih keras", rad_vdn: "Lebih pelan", rad_prev: "Sebelumnya", rad_next: "Berikutnya" },
    VI: { ch_btn: "Biểu đồ", ch_days: "Thời gian mỗi ngày, 14 ngày", ch_hours: "Hoạt động theo giờ", ch_top: "Xếp hạng theo thời gian", ch_peak: "Đỉnh", ch_avg: "Trung bình mỗi ngày", rad_title: "Menu vòng tròn", rad_reset: "Đặt lại vị trí nút", rad_media: "Phương tiện", rad_view: "Hiển thị", rad_nav: "Yêu thích", rad_page: "Trang", rad_vup: "Tăng âm", rad_vdn: "Giảm âm", rad_prev: "Trước", rad_next: "Sau" },
    TH: { ch_btn: "แผนภูมิ", ch_days: "เวลาต่อวัน 14 วัน", ch_hours: "กิจกรรมตามชั่วโมง", ch_top: "อันดับตามเวลา", ch_peak: "สูงสุด", ch_avg: "ค่าเฉลี่ยรายวัน", rad_title: "เมนูวงกลม", rad_reset: "รีเซ็ตตำแหน่งปุ่ม", rad_media: "สื่อ", rad_view: "มุมมอง", rad_nav: "รายการโปรด", rad_page: "หน้า", rad_vup: "เสียงดังขึ้น", rad_vdn: "เสียงเบาลง", rad_prev: "ก่อนหน้า", rad_next: "ถัดไป" }
};
Object.keys(I18N_RAD).forEach(k => { i18n[k] = Object.assign(i18n[k] || {}, I18N_RAD[k]); });
LANGS.forEach(k => { i18n[k] = Object.assign({}, i18n.EN, i18n[k]); });
const HIDE_L = I18N_X.HIDE;
const I18N_HIDE2 = unpackI18N({"k":["sc_hdr","sc_sub","sc_promo","sc_cookie","sc_footer","sc_widgets","sc_goal","sc_topic","sc_king","sc_wm","sc_about","cb_hdr","cb_alerts","cb_footer","cb_sort","cb_tags","cb_tips","cb_status","cb_actions","cb_info"],"v":{"UK":[["Верх сайту","Шапка з логотипом, пошуком і кнопками входу"],["Рядок моделі","Аватар, підписка та меню над плеєром"],["Реклама та банери","Розіграші токенів, кнопка «Приєднатися» на плеєрі"],["Плашка cookies","Сповіщення про cookie внизу"],["Низ сторінки","Футер і юридичний текст"],["Віджети на плеєрі","Опитування та реакції поверх відео"],["Ціль (гол)","Смуга прогресу цілі"],["Тема кімнати","Текст теми над плеєром і всередині нього"],["Король чайових","Плашка короля чайових"],["Водяний знак","Логотип поверх відео"],["Блоки під плеєром","Про мене, розклад, схожі моделі"],["Верх сайту","Шапка з логотипом і меню"],["Сповіщення","Попередження про мову та нотатки, що закриваються"],["Низ сторінки","Футер і соцмережі"],["Сортування","Панель сортування в мобільній версії"],["Смуга тегів","Популярні теги над списком"],["Чайові в чаті","Повідомлення про токени та чайові"],["Статус кімнати","Плашка про офлайн і приват з підказками"],["Кнопка чайових","Кнопка та форма надсилання токенів"],["Назва кімнати","Імʼя та лічильник глядачів у шапці"]],"ES":[["Parte superior del sitio","Cabecera con logo, búsqueda y botones de acceso"],["Barra de la modelo","Avatar, seguir y menú sobre el reproductor"],["Anuncios y banners","Sorteos de tokens, botón «Unirse» en el reproductor"],["Aviso de cookies","Aviso de cookies en la parte inferior"],["Pie de página","Pie y texto legal"],["Widgets del reproductor","Encuestas y reacciones sobre el vídeo"],["Objetivo (goal)","Barra de progreso del objetivo"],["Tema de la sala","Texto del tema sobre y dentro del reproductor"],["Rey de propinas","Franja del rey de propinas"],["Marca de agua","Logo sobre el vídeo"],["Bloques bajo el reproductor","Sobre mí, horario, modelos similares"],["Parte superior del sitio","Cabecera con logo y menú"],["Avisos","Aviso de idioma y notas descartables"],["Pie de página","Pie y redes sociales"],["Orden","Panel de orden en la versión móvil"],["Franja de etiquetas","Etiquetas populares sobre la lista"],["Propinas en el chat","Mensajes de tokens y propinas"],["Estado de la sala","Aviso de desconexión y privado con sugerencias"],["Botón de propina","Botón y formulario para enviar tokens"],["Nombre de la sala","Nombre y contador de espectadores en la cabecera"]],"DE":[["Seitenkopf","Kopfzeile mit Logo, Suche und Anmelde-Buttons"],["Model-Leiste","Avatar, Folgen und Menü über dem Player"],["Werbung & Banner","Token-Verlosungen, „Beitreten“-Button am Player"],["Cookie-Hinweis","Cookie-Hinweis am unteren Rand"],["Seitenende","Footer und rechtliche Texte"],["Player-Widgets","Umfragen und Reaktionen über dem Video"],["Ziel (Goal)","Fortschrittsbalken des Ziels"],["Raumthema","Themen-Text über und im Player"],["Tip-König","Streifen des Tip-Königs"],["Wasserzeichen","Logo über dem Video"],["Bereiche unter dem Player","Über mich, Zeitplan, ähnliche Models"],["Seitenkopf","Kopfzeile mit Logo und Menü"],["Hinweise","Sprachhinweis und schließbare Notizen"],["Seitenende","Footer und Social Media"],["Sortierung","Sortierleiste in der mobilen Ansicht"],["Tag-Leiste","Beliebte Tags über der Liste"],["Trinkgelder im Chat","Meldungen zu Tokens und Trinkgeld"],["Raumstatus","Hinweis zu Offline und Privat mit Tipps"],["Trinkgeld-Button","Button und Formular zum Senden von Tokens"],["Raumname","Name und Zuschauerzahl in der Kopfzeile"]],"FR":[["Haut du site","En-tête avec logo, recherche et boutons de connexion"],["Barre du modèle","Avatar, abonnement et menu au-dessus du lecteur"],["Pubs et bannières","Tirages de tokens, bouton « Rejoindre » sur le lecteur"],["Bandeau cookies","Avis sur les cookies en bas"],["Bas de page","Pied de page et mentions légales"],["Widgets du lecteur","Sondages et réactions sur la vidéo"],["Objectif (goal)","Barre de progression de l’objectif"],["Sujet du salon","Texte du sujet au-dessus et dans le lecteur"],["Roi des pourboires","Bandeau du roi des pourboires"],["Filigrane","Logo sur la vidéo"],["Blocs sous le lecteur","À propos, planning, modèles similaires"],["Haut du site","En-tête avec logo et menu"],["Notifications","Alerte de langue et notes fermables"],["Bas de page","Pied de page et réseaux sociaux"],["Tri","Panneau de tri sur mobile"],["Bandeau de tags","Tags populaires au-dessus de la liste"],["Pourboires dans le chat","Messages de tokens et de pourboires"],["Statut du salon","Bandeau hors ligne et privé avec astuces"],["Bouton de pourboire","Bouton et formulaire d’envoi de tokens"],["Nom du salon","Nom et nombre de spectateurs dans l’en-tête"]],"PT":[["Topo do site","Cabeçalho com logo, busca e botões de login"],["Barra da modelo","Avatar, seguir e menu acima do player"],["Anúncios e banners","Sorteios de tokens, botão «Participar» no player"],["Aviso de cookies","Aviso de cookies na parte inferior"],["Rodapé","Rodapé e texto legal"],["Widgets do player","Enquetes e reações sobre o vídeo"],["Meta (goal)","Barra de progresso da meta"],["Tema da sala","Texto do tema acima e dentro do player"],["Rei das gorjetas","Faixa do rei das gorjetas"],["Marca d’água","Logo sobre o vídeo"],["Blocos abaixo do player","Sobre mim, agenda, modelos semelhantes"],["Topo do site","Cabeçalho com logo e menu"],["Avisos","Aviso de idioma e notas dispensáveis"],["Rodapé","Rodapé e redes sociais"],["Ordenação","Painel de ordenação na versão móvel"],["Faixa de tags","Tags populares acima da lista"],["Gorjetas no chat","Mensagens de tokens e gorjetas"],["Status da sala","Aviso de offline e privado com dicas"],["Botão de gorjeta","Botão e formulário para enviar tokens"],["Nome da sala","Nome e contador de espectadores no cabeçalho"]],"IT":[["Parte alta del sito","Intestazione con logo, ricerca e pulsanti di accesso"],["Barra della modella","Avatar, segui e menu sopra il player"],["Pubblicità e banner","Estrazioni di token, pulsante «Unisciti» sul player"],["Avviso cookie","Avviso sui cookie in basso"],["Fondo pagina","Footer e testo legale"],["Widget del player","Sondaggi e reazioni sopra il video"],["Obiettivo (goal)","Barra di avanzamento dell’obiettivo"],["Argomento della stanza","Testo dell’argomento sopra e dentro il player"],["Re delle mance","Striscia del re delle mance"],["Filigrana","Logo sopra il video"],["Blocchi sotto il player","Chi sono, programma, modelle simili"],["Parte alta del sito","Intestazione con logo e menu"],["Avvisi","Avviso sulla lingua e note chiudibili"],["Fondo pagina","Footer e social"],["Ordinamento","Pannello di ordinamento nella versione mobile"],["Striscia dei tag","Tag popolari sopra l’elenco"],["Mance in chat","Messaggi su token e mance"],["Stato della stanza","Avviso su offline e privato con suggerimenti"],["Pulsante mancia","Pulsante e modulo per inviare token"],["Nome della stanza","Nome e contatore spettatori nell’intestazione"]],"PL":[["Góra strony","Nagłówek z logo, wyszukiwarką i przyciskami logowania"],["Pasek modelki","Awatar, obserwowanie i menu nad odtwarzaczem"],["Reklamy i banery","Losowania tokenów, przycisk „Dołącz” na odtwarzaczu"],["Komunikat o cookies","Informacja o cookies na dole"],["Dół strony","Stopka i teksty prawne"],["Widżety odtwarzacza","Ankiety i reakcje nad wideo"],["Cel (goal)","Pasek postępu celu"],["Temat pokoju","Tekst tematu nad odtwarzaczem i w nim"],["Król napiwków","Pasek króla napiwków"],["Znak wodny","Logo na wideo"],["Bloki pod odtwarzaczem","O mnie, harmonogram, podobne modelki"],["Góra strony","Nagłówek z logo i menu"],["Powiadomienia","Ostrzeżenie o języku i zamykane notatki"],["Dół strony","Stopka i social media"],["Sortowanie","Panel sortowania w wersji mobilnej"],["Pasek tagów","Popularne tagi nad listą"],["Napiwki na czacie","Wiadomości o tokenach i napiwkach"],["Status pokoju","Plakietka offline i prywatny z podpowiedziami"],["Przycisk napiwku","Przycisk i formularz wysyłania tokenów"],["Nazwa pokoju","Nazwa i licznik widzów w nagłówku"]],"TR":[["Sitenin üst kısmı","Logo, arama ve giriş düğmeleri olan başlık"],["Model çubuğu","Oynatıcının üstünde avatar, takip ve menü"],["Reklamlar ve bannerlar","Token çekilişleri, oynatıcıdaki «Katıl» düğmesi"],["Çerez uyarısı","Altta çerez bildirimi"],["Sayfa altı","Alt bilgi ve yasal metin"],["Oynatıcı widget’ları","Videonun üstünde anketler ve tepkiler"],["Hedef (goal)","Hedef ilerleme çubuğu"],["Oda konusu","Oynatıcının üstündeki ve içindeki konu metni"],["Bahşiş kralı","Bahşiş kralı şeridi"],["Filigran","Videonun üzerindeki logo"],["Oynatıcı altı bloklar","Hakkımda, program, benzer modeller"],["Sitenin üst kısmı","Logo ve menü olan başlık"],["Bildirimler","Dil uyarısı ve kapatılabilir notlar"],["Sayfa altı","Alt bilgi ve sosyal ağlar"],["Sıralama","Mobil sürümde sıralama paneli"],["Etiket şeridi","Listenin üstündeki popüler etiketler"],["Sohbette bahşişler","Token ve bahşiş mesajları"],["Oda durumu","Çevrimdışı ve özel şeridi ile ipuçları"],["Bahşiş düğmesi","Token gönderme düğmesi ve formu"],["Oda adı","Başlıktaki ad ve izleyici sayacı"]],"NL":[["Site-header","Header met logo, zoekfunctie en inlogknoppen"],["Modelbalk","Avatar, volgen en menu boven de speler"],["Reclame en banners","Tokenverlotingen, «Doe mee»-knop op de speler"],["Cookiemelding","Cookiemelding onderaan"],["Voettekst","Footer en juridische tekst"],["Speler-widgets","Polls en reacties over de video"],["Doel (goal)","Voortgangsbalk van het doel"],["Kamerthema","Themateksten boven en in de speler"],["Tipkoning","Strook van de tipkoning"],["Watermerk","Logo over de video"],["Blokken onder de speler","Over mij, schema, vergelijkbare modellen"],["Site-header","Header met logo en menu"],["Meldingen","Taalwaarschuwing en sluitbare notities"],["Voettekst","Footer en socials"],["Sortering","Sorteerpaneel in de mobiele versie"],["Tagbalk","Populaire tags boven de lijst"],["Tips in de chat","Berichten over tokens en tips"],["Kamerstatus","Offline- en privémelding met hints"],["Tipknop","Knop en formulier om tokens te sturen"],["Kamernaam","Naam en kijkersteller in de header"]],"CS":[["Hlavička webu","Hlavička s logem, hledáním a tlačítky přihlášení"],["Lišta modelky","Avatar, sledování a menu nad přehrávačem"],["Reklama a bannery","Losování tokenů, tlačítko „Připojit se“ na přehrávači"],["Lišta cookies","Oznámení o cookies dole"],["Patička","Patička a právní text"],["Widgety přehrávače","Ankety a reakce přes video"],["Cíl (goal)","Ukazatel postupu cíle"],["Téma místnosti","Text tématu nad přehrávačem i v něm"],["Král tipů","Pruh krále tipů"],["Vodoznak","Logo přes video"],["Bloky pod přehrávačem","O mně, rozvrh, podobné modelky"],["Hlavička webu","Hlavička s logem a menu"],["Oznámení","Upozornění na jazyk a zavíratelné poznámky"],["Patička","Patička a sociální sítě"],["Řazení","Panel řazení v mobilní verzi"],["Pruh štítků","Oblíbené štítky nad seznamem"],["Tipy v chatu","Zprávy o tokenech a tipech"],["Stav místnosti","Lišta offline a privát s nápovědami"],["Tlačítko tipu","Tlačítko a formulář pro odeslání tokenů"],["Název místnosti","Jméno a počet diváků v hlavičce"]],"RO":[["Antetul site-ului","Antet cu logo, căutare și butoane de autentificare"],["Bara modelului","Avatar, urmărire și meniu deasupra playerului"],["Reclame și bannere","Tombole de tokeni, butonul „Alătură-te” de pe player"],["Aviz cookie","Notificare cookie în partea de jos"],["Subsolul paginii","Footer și text legal"],["Widgeturi pe player","Sondaje și reacții peste video"],["Obiectiv (goal)","Bara de progres a obiectivului"],["Tema camerei","Textul temei deasupra și în player"],["Regele tipurilor","Banda regelui tipurilor"],["Filigran","Logo peste video"],["Blocuri sub player","Despre mine, program, modele similare"],["Antetul site-ului","Antet cu logo și meniu"],["Notificări","Avertisment de limbă și note închise"],["Subsolul paginii","Footer și rețele sociale"],["Sortare","Panou de sortare în versiunea mobilă"],["Banda de taguri","Taguri populare deasupra listei"],["Tipuri în chat","Mesaje despre tokeni și tipuri"],["Starea camerei","Banda offline și privat cu indicii"],["Butonul de tip","Buton și formular pentru trimiterea tokenilor"],["Numele camerei","Nume și contor de spectatori în antet"]],"HU":[["Oldal fejléce","Fejléc logóval, kereséssel és belépés gombokkal"],["Modell sáv","Avatar, követés és menü a lejátszó felett"],["Reklámok és bannerek","Token-sorsolások, „Csatlakozz” gomb a lejátszón"],["Süti értesítés","Süti figyelmeztetés alul"],["Oldal alja","Lábléc és jogi szöveg"],["Lejátszó widgetek","Szavazások és reakciók a videó felett"],["Cél (goal)","A cél haladási sávja"],["Szoba témája","A téma szövege a lejátszó felett és benne"],["Borravalókirály","A borravalókirály sávja"],["Vízjel","Logó a videó felett"],["Blokkok a lejátszó alatt","Rólam, menetrend, hasonló modellek"],["Oldal fejléce","Fejléc logóval és menüvel"],["Értesítések","Nyelvi figyelmeztetés és bezárható jegyzetek"],["Oldal alja","Lábléc és közösségi média"],["Rendezés","Rendezési panel mobil nézetben"],["Címkesáv","Népszerű címkék a lista felett"],["Borravaló a csevegésben","Token és borravaló üzenetek"],["Szoba állapota","Offline és privát sáv tippekkel"],["Borravaló gomb","Gomb és űrlap tokenek küldéséhez"],["Szoba neve","Név és nézőszámláló a fejlécben"]],"BG":[["Хедър на сайта","Хедър с лого, търсене и бутони за вход"],["Лента на модела","Аватар, следване и меню над плеъра"],["Реклами и банери","Томболи с токени, бутон „Присъедини се“ на плеъра"],["Известие за бисквитки","Известие за бисквитки долу"],["Долна част на страницата","Футър и правен текст"],["Приспособления на плеъра","Анкети и реакции върху видеото"],["Цел (goal)","Лента за напредъка на целта"],["Тема на стаята","Текст на темата над и в плеъра"],["Цар на бакшишите","Ивица на царя на бакшишите"],["Воден знак","Лого върху видеото"],["Блокове под плеъра","За мен, разписание, подобни модели"],["Хедър на сайта","Хедър с лого и меню"],["Известия","Предупреждение за език и затваряеми бележки"],["Долна част на страницата","Футър и социални мрежи"],["Сортиране","Панел за сортиране в мобилната версия"],["Лента с тагове","Популярни тагове над списъка"],["Бакшиши в чата","Съобщения за токени и бакшиши"],["Статус на стаята","Лента за офлайн и приват с подсказки"],["Бутон за бакшиш","Бутон и форма за изпращане на токени"],["Име на стаята","Име и брояч на зрители в хедъра"]],"EL":[["Κεφαλίδα ιστότοπου","Κεφαλίδα με λογότυπο, αναζήτηση και κουμπιά σύνδεσης"],["Γραμμή μοντέλου","Avatar, ακολούθηση και μενού πάνω από τον player"],["Διαφημίσεις και banners","Κληρώσεις tokens, κουμπί «Γίνε μέλος» στον player"],["Ειδοποίηση cookies","Ειδοποίηση για cookies στο κάτω μέρος"],["Υποσέλιδο","Footer και νομικό κείμενο"],["Widgets του player","Δημοσκοπήσεις και αντιδράσεις πάνω από το βίντεο"],["Στόχος (goal)","Γραμμή προόδου του στόχου"],["Θέμα δωματίου","Κείμενο θέματος πάνω από και μέσα στον player"],["Βασιλιάς φιλοδωρημάτων","Λωρίδα του βασιλιά tip"],["Υδατογράφημα","Λογότυπο πάνω από το βίντεο"],["Μπλοκ κάτω από τον player","Σχετικά με μένα, πρόγραμμα, παρόμοια μοντέλα"],["Κεφαλίδα ιστότοπου","Κεφαλίδα με λογότυπο και μενού"],["Ειδοποιήσεις","Προειδοποίηση γλώσσας και σημειώσεις που κλείνουν"],["Υποσέλιδο","Footer και social"],["Ταξινόμηση","Πάνελ ταξινόμησης στην έκδοση για κινητά"],["Λωρίδα ετικετών","Δημοφιλείς ετικέτες πάνω από τη λίστα"],["Φιλοδωρήματα στο chat","Μηνύματα για tokens και tips"],["Κατάσταση δωματίου","Λωρίδα offline και private με υποδείξεις"],["Κουμπί tip","Κουμπί και φόρμα αποστολής tokens"],["Όνομα δωματίου","Όνομα και μετρητής θεατών στην κεφαλίδα"]],"JA":[["サイトのヘッダー","ロゴ、検索、ログインボタンのあるヘッダー"],["モデルバー","プレーヤー上のアバター、フォロー、メニュー"],["広告とバナー","トークン抽選、プレーヤー上の「参加」ボタン"],["Cookie通知","下部のCookie通知"],["ページ下部","フッターと法的テキスト"],["プレーヤーのウィジェット","動画上のアンケートとリアクション"],["目標(ゴール)","目標の進行バー"],["ルームのトピック","プレーヤー上と内部のトピック文"],["チップキング","チップキングの帯"],["透かし","動画上のロゴ"],["プレーヤー下のブロック","自己紹介、スケジュール、似たモデル"],["サイトのヘッダー","ロゴとメニューのあるヘッダー"],["通知","言語の警告と閉じられるメモ"],["ページ下部","フッターとSNS"],["並べ替え","モバイル版の並べ替えパネル"],["タグの帯","リスト上の人気タグ"],["チャットのチップ","トークンとチップのメッセージ"],["ルームの状態","オフラインとプライベートの案内帯"],["チップボタン","トークン送信のボタンとフォーム"],["ルーム名","ヘッダーの名前と視聴者数"]],"ZH":[["网站顶部","带有 Logo、搜索和登录按钮的页头"],["主播栏","播放器上方的头像、关注和菜单"],["广告和横幅","代币抽奖、播放器上的“加入”按钮"],["Cookie 提示","底部的 Cookie 通知"],["页面底部","页脚和法律文字"],["播放器小组件","视频上的投票和互动"],["目标(goal)","目标进度条"],["房间话题","播放器上方和内部的话题文字"],["打赏之王","打赏之王条"],["水印","视频上的 Logo"],["播放器下方区块","关于我、日程、相似主播"],["网站顶部","带有 Logo 和菜单的页头"],["通知","语言提示和可关闭的说明"],["页面底部","页脚和社交媒体"],["排序","移动版的排序面板"],["标签条","列表上方的热门标签"],["聊天打赏","代币和打赏消息"],["房间状态","离线和私密提示条"],["打赏按钮","发送代币的按钮和表单"],["房间名称","页头中的名称和观众数"]],"KO":[["사이트 상단","로고, 검색, 로그인 버튼이 있는 헤더"],["모델 바","플레이어 위의 아바타, 팔로우, 메뉴"],["광고 및 배너","토큰 추첨, 플레이어의 “참여” 버튼"],["쿠키 안내","하단의 쿠키 알림"],["페이지 하단","푸터와 법적 문구"],["플레이어 위젯","영상 위의 투표와 반응"],["목표(골)","목표 진행 바"],["방 주제","플레이어 위와 안의 주제 문구"],["팁 킹","팁 킹 띠"],["워터마크","영상 위의 로고"],["플레이어 아래 블록","소개, 일정, 비슷한 모델"],["사이트 상단","로고와 메뉴가 있는 헤더"],["알림","언어 경고와 닫을 수 있는 메모"],["페이지 하단","푸터와 SNS"],["정렬","모바일 버전의 정렬 패널"],["태그 띠","목록 위의 인기 태그"],["채팅 팁","토큰과 팁 메시지"],["방 상태","오프라인과 프라이빗 안내 띠"],["팁 버튼","토큰 전송 버튼과 양식"],["방 이름","헤더의 이름과 시청자 수"]],"HE":[["כותרת האתר","כותרת עם לוגו, חיפוש וכפתורי כניסה"],["סרגל המודל","אווטאר, מעקב ותפריט מעל הנגן"],["פרסומות ובאנרים","הגרלות טוקנים, כפתור “הצטרף” בנגן"],["הודעת קוקיז","הודעת קוקיז בתחתית"],["תחתית העמוד","פוטר וטקסט משפטי"],["ווידג׳טים בנגן","סקרים ותגובות מעל הוידאו"],["יעד (goal)","סרגל התקדמות היעד"],["נושא החדר","טקסט הנושא מעל הנגן ובתוכו"],["מלך הטיפים","רצועת מלך הטיפים"],["סימן מים","לוגו מעל הוידאו"],["בלוקים מתחת לנגן","אודותיי, לוח זמנים, מודלים דומים"],["כותרת האתר","כותרת עם לוגו ותפריט"],["התראות","אזהרת שפה והערות שניתן לסגור"],["תחתית העמוד","פוטר ורשתות חברתיות"],["מיון","לוח מיון בגרסה לנייד"],["רצועת תגיות","תגיות פופולריות מעל הרשימה"],["טיפים בצ׳אט","הודעות על טוקנים וטיפים"],["סטטוס החדר","רצועת לא מחובר ופרטי עם רמזים"],["כפתור טיפ","כפתור וטופס לשליחת טוקנים"],["שם החדר","שם ומונה צופים בכותרת"]],"AR":[["رأس الموقع","رأس مع الشعار والبحث وأزرار الدخول"],["شريط الموديل","الصورة الرمزية والمتابعة والقائمة فوق المشغّل"],["الإعلانات واللافتات","سحوبات الرموز وزر «انضم» على المشغّل"],["إشعار الكوكيز","إشعار الكوكيز في الأسفل"],["أسفل الصفحة","التذييل والنص القانوني"],["أدوات المشغّل","استطلاعات وتفاعلات فوق الفيديو"],["الهدف (goal)","شريط تقدّم الهدف"],["موضوع الغرفة","نص الموضوع فوق المشغّل وداخله"],["ملك البقشيش","شريط ملك البقشيش"],["العلامة المائية","الشعار فوق الفيديو"],["كتل أسفل المشغّل","نبذة عني والجدول وموديلات مشابهة"],["رأس الموقع","رأس مع الشعار والقائمة"],["الإشعارات","تنبيه اللغة وملاحظات قابلة للإغلاق"],["أسفل الصفحة","التذييل والشبكات الاجتماعية"],["الفرز","لوحة الفرز في نسخة الجوال"],["شريط الوسوم","وسوم شائعة فوق القائمة"],["البقشيش في الدردشة","رسائل الرموز والبقشيش"],["حالة الغرفة","شريط غير متصل وخاص مع تلميحات"],["زر البقشيش","زر ونموذج إرسال الرموز"],["اسم الغرفة","الاسم وعدّاد المشاهدين في الرأس"]],"HI":[["साइट का हेडर","लोगो, खोज और लॉगिन बटन वाला हेडर"],["मॉडल बार","प्लेयर के ऊपर अवतार, फ़ॉलो और मेन्यू"],["विज्ञापन और बैनर","टोकन ड्रॉ, प्लेयर पर “जुड़ें” बटन"],["कुकी सूचना","नीचे कुकी की सूचना"],["पेज का निचला हिस्सा","फ़ुटर और कानूनी टेक्स्ट"],["प्लेयर विजेट","वीडियो के ऊपर पोल और रिएक्शन"],["लक्ष्य (गोल)","लक्ष्य की प्रगति पट्टी"],["रूम का विषय","प्लेयर के ऊपर और अंदर विषय का टेक्स्ट"],["टिप किंग","टिप किंग की पट्टी"],["वॉटरमार्क","वीडियो के ऊपर लोगो"],["प्लेयर के नीचे के ब्लॉक","मेरे बारे में, शेड्यूल, मिलती-जुलती मॉडल"],["साइट का हेडर","लोगो और मेन्यू वाला हेडर"],["सूचनाएँ","भाषा की चेतावनी और बंद होने वाले नोट"],["पेज का निचला हिस्सा","फ़ुटर और सोशल मीडिया"],["सॉर्टिंग","मोबाइल संस्करण में सॉर्ट पैनल"],["टैग पट्टी","सूची के ऊपर लोकप्रिय टैग"],["चैट में टिप","टोकन और टिप के संदेश"],["रूम की स्थिति","ऑफ़लाइन और प्राइवेट पट्टी, सुझावों के साथ"],["टिप बटन","टोकन भेजने का बटन और फ़ॉर्म"],["रूम का नाम","हेडर में नाम और दर्शकों की गिनती"]],"ID":[["Header situs","Header dengan logo, pencarian, dan tombol masuk"],["Bilah model","Avatar, ikuti, dan menu di atas pemutar"],["Iklan dan banner","Undian token, tombol “Bergabung” di pemutar"],["Pemberitahuan cookie","Pemberitahuan cookie di bagian bawah"],["Bagian bawah halaman","Footer dan teks hukum"],["Widget pemutar","Polling dan reaksi di atas video"],["Target (goal)","Bilah progres target"],["Topik ruangan","Teks topik di atas dan di dalam pemutar"],["Raja tip","Pita raja tip"],["Watermark","Logo di atas video"],["Blok di bawah pemutar","Tentang saya, jadwal, model serupa"],["Header situs","Header dengan logo dan menu"],["Pemberitahuan","Peringatan bahasa dan catatan yang bisa ditutup"],["Bagian bawah halaman","Footer dan media sosial"],["Pengurutan","Panel urutkan di versi seluler"],["Pita tag","Tag populer di atas daftar"],["Tip di chat","Pesan token dan tip"],["Status ruangan","Pita offline dan privat dengan petunjuk"],["Tombol tip","Tombol dan formulir kirim token"],["Nama ruangan","Nama dan penghitung penonton di header"]],"VI":[["Phần đầu trang","Header có logo, tìm kiếm và nút đăng nhập"],["Thanh model","Avatar, theo dõi và menu phía trên trình phát"],["Quảng cáo và banner","Rút thăm token, nút “Tham gia” trên trình phát"],["Thông báo cookie","Thông báo cookie ở phía dưới"],["Chân trang","Footer và văn bản pháp lý"],["Tiện ích trên trình phát","Bình chọn và phản ứng trên video"],["Mục tiêu (goal)","Thanh tiến độ mục tiêu"],["Chủ đề phòng","Văn bản chủ đề phía trên và trong trình phát"],["Vua tip","Dải vua tip"],["Hình mờ","Logo trên video"],["Khối dưới trình phát","Giới thiệu, lịch, model tương tự"],["Phần đầu trang","Header có logo và menu"],["Thông báo","Cảnh báo ngôn ngữ và ghi chú có thể đóng"],["Chân trang","Footer và mạng xã hội"],["Sắp xếp","Bảng sắp xếp trên bản di động"],["Dải thẻ","Thẻ phổ biến phía trên danh sách"],["Tip trong chat","Tin nhắn về token và tip"],["Trạng thái phòng","Dải offline và riêng tư kèm gợi ý"],["Nút tip","Nút và biểu mẫu gửi token"],["Tên phòng","Tên và số người xem trong header"]],"TH":[["ส่วนหัวเว็บไซต์","ส่วนหัวที่มีโลโก้ ค้นหา และปุ่มเข้าสู่ระบบ"],["แถบโมเดล","อวาตาร์ ติดตาม และเมนูเหนือเครื่องเล่น"],["โฆษณาและแบนเนอร์","จับรางวัลโทเคน ปุ่ม “เข้าร่วม” บนเครื่องเล่น"],["แจ้งเตือนคุกกี้","การแจ้งเตือนคุกกี้ด้านล่าง"],["ท้ายหน้า","ส่วนท้ายและข้อความทางกฎหมาย"],["วิดเจ็ตบนเครื่องเล่น","โพลและรีแอคชันเหนือวิดีโอ"],["เป้าหมาย (goal)","แถบความคืบหน้าของเป้าหมาย"],["หัวข้อห้อง","ข้อความหัวข้อเหนือและในเครื่องเล่น"],["ราชาทิป","แถบราชาทิป"],["ลายน้ำ","โลโก้เหนือวิดีโอ"],["บล็อกใต้เครื่องเล่น","เกี่ยวกับฉัน ตารางเวลา โมเดลที่คล้ายกัน"],["ส่วนหัวเว็บไซต์","ส่วนหัวที่มีโลโก้และเมนู"],["การแจ้งเตือน","คำเตือนเรื่องภาษาและโน้ตที่ปิดได้"],["ท้ายหน้า","ส่วนท้ายและโซเชียล"],["การเรียง","แผงเรียงในเวอร์ชันมือถือ"],["แถบแท็ก","แท็กยอดนิยมเหนือรายการ"],["ทิปในแชต","ข้อความเกี่ยวกับโทเคนและทิป"],["สถานะห้อง","แถบออฟไลน์และส่วนตัวพร้อมคำแนะนำ"],["ปุ่มทิป","ปุ่มและฟอร์มส่งโทเคน"],["ชื่อห้อง","ชื่อและตัวนับผู้ชมในส่วนหัว"]]}});
Object.keys(I18N_HIDE2).forEach(k => { HIDE_L[k] = Object.assign(HIDE_L[k] || {}, I18N_HIDE2[k]); });
const I18N_CAL = {
    RU: {
        w_new: "Не просмотрено",
        w_seen: "Просмотрено",
        w_all: "Все",
        w_tip: "Просмотрено — если вы были в эфире модели 30 секунд и больше",
        cal_title: "Календарь",
        cal_today: "Сегодня",
        cal_hist: "Просмотры",
        cal_sched: "Расписание",
        cal_models: "Модели",
        cal_reset: "Сбросить",
        cal_all_tag: "Все теги",
        cal_none: "В этот день пусто",
        cal_watched: "Просмотрено",
        cal_on_air: "По расписанию",
        cal_no_sched: "Расписание берётся из профилей избранных. Откройте «Избранное» и подождите несколько секунд.",
        cal_allday: "Весь день",
        cal_loaded: "Расписание загружено: {a} из {b}",
        cal_c_model: "Модель",
        cal_c_time: "Вход",
        cal_c_dur: "Длит.",
        cal_c_n: "Заходы",
        cal_total: "Итого"
    },
    EN: {
        w_new: "Not watched",
        w_seen: "Watched",
        w_all: "All",
        w_tip: "Watched — you were in the model's stream for 30 seconds or more",
        cal_title: "Calendar",
        cal_today: "Today",
        cal_hist: "History",
        cal_sched: "Schedule",
        cal_models: "Models",
        cal_reset: "Reset",
        cal_all_tag: "All tags",
        cal_none: "Nothing on this day",
        cal_watched: "Viewed",
        cal_on_air: "Scheduled",
        cal_no_sched: "The schedule is read from the profiles of your favorites. Open Favorites and wait a few seconds.",
        cal_allday: "All day",
        cal_loaded: "Schedule loaded: {a} of {b}",
        cal_c_model: "Model",
        cal_c_time: "Joined",
        cal_c_dur: "Duration",
        cal_c_n: "Visits",
        cal_total: "Total"
    },
    UK: {
        w_new: "Не переглянуто",
        w_seen: "Переглянуто",
        w_all: "Усі",
        w_tip: "Переглянуто — якщо ви були в ефірі моделі 30 секунд і більше",
        cal_title: "Календар",
        cal_today: "Сьогодні",
        cal_hist: "Перегляди",
        cal_sched: "Розклад",
        cal_models: "Моделі",
        cal_reset: "Скинути",
        cal_all_tag: "Усі теги",
        cal_none: "У цей день порожньо",
        cal_watched: "Переглянуто",
        cal_on_air: "За розкладом",
        cal_no_sched: "Розклад береться з профілів обраних. Відкрийте «Обране» і зачекайте кілька секунд.",
        cal_allday: "Увесь день",
        cal_loaded: "Розклад завантажено: {a} з {b}",
        cal_c_model: "Модель",
        cal_c_time: "Вхід",
        cal_c_dur: "Трив.",
        cal_c_n: "Заходи",
        cal_total: "Разом"
    },
    ES: {
        w_new: "No visto",
        w_seen: "Visto",
        w_all: "Todos",
        w_tip: "Visto: has estado en la emisión de la modelo 30 segundos o más",
        cal_title: "Calendario",
        cal_today: "Hoy",
        cal_hist: "Vistos",
        cal_sched: "Horario",
        cal_models: "Modelos",
        cal_reset: "Restablecer",
        cal_all_tag: "Todas las etiquetas",
        cal_none: "No hay nada este día",
        cal_watched: "Visto",
        cal_on_air: "Según horario",
        cal_no_sched: "El horario se toma de los perfiles de tus favoritos. Abre Favoritos y espera unos segundos.",
        cal_allday: "Todo el día",
        cal_loaded: "Horario cargado: {a} de {b}",
        cal_c_model: "Modelo",
        cal_c_time: "Entrada",
        cal_c_dur: "Dur.",
        cal_c_n: "Visitas",
        cal_total: "Total"
    },
    DE: {
        w_new: "Nicht gesehen",
        w_seen: "Gesehen",
        w_all: "Alle",
        w_tip: "Gesehen – du warst mindestens 30 Sekunden im Stream des Models",
        cal_title: "Kalender",
        cal_today: "Heute",
        cal_hist: "Verlauf",
        cal_sched: "Zeitplan",
        cal_models: "Models",
        cal_reset: "Zurücksetzen",
        cal_all_tag: "Alle Tags",
        cal_none: "An diesem Tag ist nichts",
        cal_watched: "Gesehen",
        cal_on_air: "Laut Zeitplan",
        cal_no_sched: "Der Zeitplan stammt aus den Profilen deiner Favoriten. Öffne die Favoriten und warte ein paar Sekunden.",
        cal_allday: "Ganztägig",
        cal_loaded: "Zeitplan geladen: {a} von {b}",
        cal_c_model: "Model",
        cal_c_time: "Eintritt",
        cal_c_dur: "Dauer",
        cal_c_n: "Besuche",
        cal_total: "Gesamt"
    },
    FR: {
        w_new: "Non vu",
        w_seen: "Vu",
        w_all: "Tous",
        w_tip: "Vu : vous êtes resté au moins 30 secondes dans le live du modèle",
        cal_title: "Calendrier",
        cal_today: "Aujourd'hui",
        cal_hist: "Historique",
        cal_sched: "Horaires",
        cal_models: "Modèles",
        cal_reset: "Réinitialiser",
        cal_all_tag: "Tous les tags",
        cal_none: "Rien ce jour-là",
        cal_watched: "Vu",
        cal_on_air: "Selon l’horaire",
        cal_no_sched: "Les horaires sont lus dans les profils de vos favoris. Ouvrez les favoris et patientez quelques secondes.",
        cal_allday: "Toute la journée",
        cal_loaded: "Horaires chargés : {a} sur {b}",
        cal_c_model: "Modèle",
        cal_c_time: "Entrée",
        cal_c_dur: "Durée",
        cal_c_n: "Visites",
        cal_total: "Total"
    },
    PT: {
        w_new: "Não visto",
        w_seen: "Visto",
        w_all: "Todos",
        w_tip: "Visto: você ficou na transmissão da modelo por 30 segundos ou mais",
        cal_title: "Calendário",
        cal_today: "Hoje",
        cal_hist: "Histórico",
        cal_sched: "Horários",
        cal_models: "Modelos",
        cal_reset: "Redefinir",
        cal_all_tag: "Todas as tags",
        cal_none: "Nada neste dia",
        cal_watched: "Visto",
        cal_on_air: "Pelo horário",
        cal_no_sched: "Os horários vêm dos perfis dos seus favoritos. Abra os Favoritos e aguarde alguns segundos.",
        cal_allday: "O dia todo",
        cal_loaded: "Horários carregados: {a} de {b}",
        cal_c_model: "Modelo",
        cal_c_time: "Entrada",
        cal_c_dur: "Dur.",
        cal_c_n: "Visitas",
        cal_total: "Total"
    },
    IT: {
        w_new: "Non visto",
        w_seen: "Visto",
        w_all: "Tutti",
        w_tip: "Visto: sei rimasto nella diretta della modella per almeno 30 secondi",
        cal_title: "Calendario",
        cal_today: "Oggi",
        cal_hist: "Cronologia",
        cal_sched: "Orari",
        cal_models: "Modelle",
        cal_reset: "Reimposta",
        cal_all_tag: "Tutti i tag",
        cal_none: "Niente in questo giorno",
        cal_watched: "Visto",
        cal_on_air: "Da programma",
        cal_no_sched: "Gli orari vengono letti dai profili dei tuoi preferiti. Apri i Preferiti e attendi qualche secondo.",
        cal_allday: "Tutto il giorno",
        cal_loaded: "Orari caricati: {a} su {b}",
        cal_c_model: "Modella",
        cal_c_time: "Ingresso",
        cal_c_dur: "Durata",
        cal_c_n: "Visite",
        cal_total: "Totale"
    },
    PL: {
        w_new: "Nieoglądane",
        w_seen: "Oglądane",
        w_all: "Wszystkie",
        w_tip: "Oglądane — byłeś na transmisji modelki co najmniej 30 sekund",
        cal_title: "Kalendarz",
        cal_today: "Dziś",
        cal_hist: "Historia",
        cal_sched: "Grafik",
        cal_models: "Modelki",
        cal_reset: "Resetuj",
        cal_all_tag: "Wszystkie tagi",
        cal_none: "Tego dnia nic nie ma",
        cal_watched: "Oglądane",
        cal_on_air: "Wg grafiku",
        cal_no_sched: "Grafik jest pobierany z profili ulubionych. Otwórz Ulubione i poczekaj kilka sekund.",
        cal_allday: "Cały dzień",
        cal_loaded: "Grafik wczytany: {a} z {b}",
        cal_c_model: "Modelka",
        cal_c_time: "Wejście",
        cal_c_dur: "Czas",
        cal_c_n: "Wejścia",
        cal_total: "Razem"
    },
    TR: {
        w_new: "İzlenmedi",
        w_seen: "İzlendi",
        w_all: "Tümü",
        w_tip: "İzlendi — modelin yayınında en az 30 saniye bulundunuz",
        cal_title: "Takvim",
        cal_today: "Bugün",
        cal_hist: "Geçmiş",
        cal_sched: "Program",
        cal_models: "Modeller",
        cal_reset: "Sıfırla",
        cal_all_tag: "Tüm etiketler",
        cal_none: "Bu gün boş",
        cal_watched: "İzlendi",
        cal_on_air: "Programa göre",
        cal_no_sched: "Program, favorilerinizin profillerinden alınır. Favoriler'i açın ve birkaç saniye bekleyin.",
        cal_allday: "Tüm gün",
        cal_loaded: "Program yüklendi: {a} / {b}",
        cal_c_model: "Model",
        cal_c_time: "Giriş",
        cal_c_dur: "Süre",
        cal_c_n: "Ziyaret",
        cal_total: "Toplam"
    },
    NL: {
        w_new: "Niet bekeken",
        w_seen: "Bekeken",
        w_all: "Alle",
        w_tip: "Bekeken — je zat minstens 30 seconden in de uitzending van het model",
        cal_title: "Kalender",
        cal_today: "Vandaag",
        cal_hist: "Geschiedenis",
        cal_sched: "Rooster",
        cal_models: "Modellen",
        cal_reset: "Resetten",
        cal_all_tag: "Alle tags",
        cal_none: "Niets op deze dag",
        cal_watched: "Bekeken",
        cal_on_air: "Volgens rooster",
        cal_no_sched: "Het rooster komt uit de profielen van je favorieten. Open Favorieten en wacht een paar seconden.",
        cal_allday: "Hele dag",
        cal_loaded: "Rooster geladen: {a} van {b}",
        cal_c_model: "Model",
        cal_c_time: "Binnenkomst",
        cal_c_dur: "Duur",
        cal_c_n: "Bezoeken",
        cal_total: "Totaal"
    },
    CS: {
        w_new: "Neshlédnuto",
        w_seen: "Shlédnuto",
        w_all: "Vše",
        w_tip: "Shlédnuto — byli jste ve vysílání modelky 30 sekund a déle",
        cal_title: "Kalendář",
        cal_today: "Dnes",
        cal_hist: "Historie",
        cal_sched: "Rozvrh",
        cal_models: "Modelky",
        cal_reset: "Obnovit",
        cal_all_tag: "Všechny štítky",
        cal_none: "V tento den nic není",
        cal_watched: "Shlédnuto",
        cal_on_air: "Podle rozvrhu",
        cal_no_sched: "Rozvrh se načítá z profilů oblíbených. Otevřete Oblíbené a chvíli počkejte.",
        cal_allday: "Celý den",
        cal_loaded: "Rozvrh načten: {a} z {b}",
        cal_c_model: "Modelka",
        cal_c_time: "Vstup",
        cal_c_dur: "Doba",
        cal_c_n: "Vstupy",
        cal_total: "Celkem"
    },
    RO: {
        w_new: "Nevăzut",
        w_seen: "Văzut",
        w_all: "Toate",
        w_tip: "Văzut — ai stat în transmisia modelului cel puțin 30 de secunde",
        cal_title: "Calendar",
        cal_today: "Azi",
        cal_hist: "Istoric",
        cal_sched: "Program",
        cal_models: "Modele",
        cal_reset: "Resetează",
        cal_all_tag: "Toate etichetele",
        cal_none: "Nimic în această zi",
        cal_watched: "Văzut",
        cal_on_air: "Conform programului",
        cal_no_sched: "Programul este preluat din profilurile favoritelor. Deschide Favorite și așteaptă câteva secunde.",
        cal_allday: "Toată ziua",
        cal_loaded: "Program încărcat: {a} din {b}",
        cal_c_model: "Model",
        cal_c_time: "Intrare",
        cal_c_dur: "Durată",
        cal_c_n: "Vizite",
        cal_total: "Total"
    },
    HU: {
        w_new: "Nem nézett",
        w_seen: "Nézett",
        w_all: "Mind",
        w_tip: "Nézett — legalább 30 másodpercig a modell adásában voltál",
        cal_title: "Naptár",
        cal_today: "Ma",
        cal_hist: "Előzmények",
        cal_sched: "Menetrend",
        cal_models: "Modellek",
        cal_reset: "Visszaállítás",
        cal_all_tag: "Minden címke",
        cal_none: "Ezen a napon nincs semmi",
        cal_watched: "Nézett",
        cal_on_air: "Menetrend szerint",
        cal_no_sched: "A menetrend a kedvencek profiljából töltődik be. Nyisd meg a Kedvenceket, és várj pár másodpercet.",
        cal_allday: "Egész nap",
        cal_loaded: "Menetrend betöltve: {a} / {b}",
        cal_c_model: "Modell",
        cal_c_time: "Belépés",
        cal_c_dur: "Idő",
        cal_c_n: "Alkalom",
        cal_total: "Összesen"
    },
    BG: {
        w_new: "Негледан",
        w_seen: "Гледан",
        w_all: "Всички",
        w_tip: "Гледан — били сте в ефира на модела поне 30 секунди",
        cal_title: "Календар",
        cal_today: "Днес",
        cal_hist: "История",
        cal_sched: "Разписание",
        cal_models: "Модели",
        cal_reset: "Нулиране",
        cal_all_tag: "Всички тагове",
        cal_none: "Няма нищо за този ден",
        cal_watched: "Гледан",
        cal_on_air: "По разписание",
        cal_no_sched: "Разписанието се взема от профилите на любимите. Отворете „Любими“ и изчакайте няколко секунди.",
        cal_allday: "Цял ден",
        cal_loaded: "Разписание заредено: {a} от {b}",
        cal_c_model: "Модел",
        cal_c_time: "Вход",
        cal_c_dur: "Прод.",
        cal_c_n: "Пъти",
        cal_total: "Общо"
    },
    EL: {
        w_new: "Δεν το είδα",
        w_seen: "Το είδα",
        w_all: "Όλα",
        w_tip: "Το είδα — ήσασταν στο live του μοντέλου για 30 δευτερόλεπτα ή περισσότερο",
        cal_title: "Ημερολόγιο",
        cal_today: "Σήμερα",
        cal_hist: "Ιστορικό",
        cal_sched: "Πρόγραμμα",
        cal_models: "Μοντέλα",
        cal_reset: "Επαναφορά",
        cal_all_tag: "Όλες οι ετικέτες",
        cal_none: "Τίποτα αυτή την ημέρα",
        cal_watched: "Προβλήθηκε",
        cal_on_air: "Βάσει προγράμματος",
        cal_no_sched: "Το πρόγραμμα λαμβάνεται από τα προφίλ των αγαπημένων. Ανοίξτε τα Αγαπημένα και περιμένετε λίγα δευτερόλεπτα.",
        cal_allday: "Όλη μέρα",
        cal_loaded: "Πρόγραμμα φορτώθηκε: {a} από {b}",
        cal_c_model: "Μοντέλο",
        cal_c_time: "Είσοδος",
        cal_c_dur: "Διάρκ.",
        cal_c_n: "Φορές",
        cal_total: "Σύνολο"
    },
    JA: {
        w_new: "未視聴",
        w_seen: "視聴済み",
        w_all: "すべて",
        w_tip: "視聴済み — モデルの配信に30秒以上いた場合",
        cal_title: "カレンダー",
        cal_today: "今日",
        cal_hist: "視聴履歴",
        cal_sched: "スケジュール",
        cal_models: "モデル",
        cal_reset: "リセット",
        cal_all_tag: "すべてのタグ",
        cal_none: "この日は何もありません",
        cal_watched: "視聴済み",
        cal_on_air: "スケジュール通り",
        cal_no_sched: "スケジュールはお気に入りのプロフィールから取得されます。お気に入りを開いて数秒お待ちください。",
        cal_allday: "終日",
        cal_loaded: "スケジュール取得済み:{a}/{b}",
        cal_c_model: "モデル",
        cal_c_time: "入室",
        cal_c_dur: "時間",
        cal_c_n: "回数",
        cal_total: "合計"
    },
    ZH: {
        w_new: "未观看",
        w_seen: "已观看",
        w_all: "全部",
        w_tip: "已观看——您在模特直播间停留了30秒及以上",
        cal_title: "日历",
        cal_today: "今天",
        cal_hist: "观看记录",
        cal_sched: "时间表",
        cal_models: "模特",
        cal_reset: "重置",
        cal_all_tag: "所有标签",
        cal_none: "这一天没有内容",
        cal_watched: "已观看",
        cal_on_air: "按时间表",
        cal_no_sched: "时间表来自收藏模特的个人资料。请打开“收藏”并稍等几秒。",
        cal_allday: "全天",
        cal_loaded: "已加载时间表:{a}/{b}",
        cal_c_model: "模特",
        cal_c_time: "进入",
        cal_c_dur: "时长",
        cal_c_n: "次数",
        cal_total: "合计"
    },
    KO: {
        w_new: "미시청",
        w_seen: "시청함",
        w_all: "전체",
        w_tip: "시청함 — 모델의 방송에 30초 이상 있었던 경우",
        cal_title: "캘린더",
        cal_today: "오늘",
        cal_hist: "시청 기록",
        cal_sched: "일정",
        cal_models: "모델",
        cal_reset: "초기화",
        cal_all_tag: "모든 태그",
        cal_none: "이날은 비어 있습니다",
        cal_watched: "시청함",
        cal_on_air: "일정 기준",
        cal_no_sched: "일정은 즐겨찾기 프로필에서 가져옵니다. 즐겨찾기를 열고 몇 초 기다려 주세요.",
        cal_allday: "종일",
        cal_loaded: "일정 불러옴: {a}/{b}",
        cal_c_model: "모델",
        cal_c_time: "입장",
        cal_c_dur: "시간",
        cal_c_n: "횟수",
        cal_total: "합계"
    },
    HE: {
        w_new: "לא נצפה",
        w_seen: "נצפה",
        w_all: "הכול",
        w_tip: "נצפה — היית בשידור של המודל 30 שניות ומעלה",
        cal_title: "לוח שנה",
        cal_today: "היום",
        cal_hist: "היסטוריה",
        cal_sched: "לוח זמנים",
        cal_models: "מודלים",
        cal_reset: "איפוס",
        cal_all_tag: "כל התגיות",
        cal_none: "אין דבר ביום זה",
        cal_watched: "נצפה",
        cal_on_air: "לפי לוח הזמנים",
        cal_no_sched: "לוח הזמנים נלקח מפרופילי המועדפים. פתחו את המועדפים והמתינו כמה שניות.",
        cal_allday: "כל היום",
        cal_loaded: "לוח הזמנים נטען: {a} מתוך {b}",
        cal_c_model: "מודל",
        cal_c_time: "כניסה",
        cal_c_dur: "משך",
        cal_c_n: "פעמים",
        cal_total: "סה״כ"
    },
    AR: {
        w_new: "لم تتم المشاهدة",
        w_seen: "تمت المشاهدة",
        w_all: "الكل",
        w_tip: "تمت المشاهدة — إذا بقيت في بث العارضة 30 ثانية أو أكثر",
        cal_title: "التقويم",
        cal_today: "اليوم",
        cal_hist: "السجل",
        cal_sched: "الجدول",
        cal_models: "العارضات",
        cal_reset: "إعادة ضبط",
        cal_all_tag: "كل الوسوم",
        cal_none: "لا شيء في هذا اليوم",
        cal_watched: "تمت المشاهدة",
        cal_on_air: "حسب الجدول",
        cal_no_sched: "يؤخذ الجدول من ملفات المفضلة. افتح المفضلة وانتظر بضع ثوانٍ.",
        cal_allday: "طوال اليوم",
        cal_loaded: "تم تحميل الجدول: {a} من {b}",
        cal_c_model: "العارضة",
        cal_c_time: "الدخول",
        cal_c_dur: "المدة",
        cal_c_n: "المرات",
        cal_total: "المجموع"
    },
    HI: {
        w_new: "नहीं देखा",
        w_seen: "देखा",
        w_all: "सभी",
        w_tip: "देखा — यदि आप मॉडल के प्रसारण में 30 सेकंड या उससे अधिक रहे",
        cal_title: "कैलेंडर",
        cal_today: "आज",
        cal_hist: "इतिहास",
        cal_sched: "शेड्यूल",
        cal_models: "मॉडल",
        cal_reset: "रीसेट",
        cal_all_tag: "सभी टैग",
        cal_none: "इस दिन कुछ नहीं है",
        cal_watched: "देखा",
        cal_on_air: "शेड्यूल के अनुसार",
        cal_no_sched: "शेड्यूल पसंदीदा की प्रोफ़ाइल से लिया जाता है। पसंदीदा खोलें और कुछ सेकंड प्रतीक्षा करें।",
        cal_allday: "पूरे दिन",
        cal_loaded: "शेड्यूल लोड हुआ: {a}/{b}",
        cal_c_model: "मॉडल",
        cal_c_time: "प्रवेश",
        cal_c_dur: "अवधि",
        cal_c_n: "बार",
        cal_total: "कुल"
    },
    ID: {
        w_new: "Belum ditonton",
        w_seen: "Ditonton",
        w_all: "Semua",
        w_tip: "Ditonton — Anda berada di siaran model selama 30 detik atau lebih",
        cal_title: "Kalender",
        cal_today: "Hari ini",
        cal_hist: "Riwayat",
        cal_sched: "Jadwal",
        cal_models: "Model",
        cal_reset: "Atur ulang",
        cal_all_tag: "Semua tag",
        cal_none: "Tidak ada apa pun di hari ini",
        cal_watched: "Ditonton",
        cal_on_air: "Sesuai jadwal",
        cal_no_sched: "Jadwal diambil dari profil favorit Anda. Buka Favorit dan tunggu beberapa detik.",
        cal_allday: "Sepanjang hari",
        cal_loaded: "Jadwal dimuat: {a} dari {b}",
        cal_c_model: "Model",
        cal_c_time: "Masuk",
        cal_c_dur: "Durasi",
        cal_c_n: "Kali",
        cal_total: "Total"
    },
    VI: {
        w_new: "Chưa xem",
        w_seen: "Đã xem",
        w_all: "Tất cả",
        w_tip: "Đã xem — bạn đã ở trong buổi phát của người mẫu từ 30 giây trở lên",
        cal_title: "Lịch",
        cal_today: "Hôm nay",
        cal_hist: "Lịch sử",
        cal_sched: "Lịch phát",
        cal_models: "Người mẫu",
        cal_reset: "Đặt lại",
        cal_all_tag: "Tất cả thẻ",
        cal_none: "Hôm nay không có gì",
        cal_watched: "Đã xem",
        cal_on_air: "Theo lịch",
        cal_no_sched: "Lịch phát lấy từ hồ sơ của mục yêu thích. Hãy mở Yêu thích và chờ vài giây.",
        cal_allday: "Cả ngày",
        cal_loaded: "Đã tải lịch: {a}/{b}",
        cal_c_model: "Người mẫu",
        cal_c_time: "Vào",
        cal_c_dur: "Thời lượng",
        cal_c_n: "Lần",
        cal_total: "Tổng"
    },
    TH: {
        w_new: "ยังไม่ได้ดู",
        w_seen: "ดูแล้ว",
        w_all: "ทั้งหมด",
        w_tip: "ดูแล้ว — คุณอยู่ในการถ่ายทอดสดของโมเดลตั้งแต่ 30 วินาทีขึ้นไป",
        cal_title: "ปฏิทิน",
        cal_today: "วันนี้",
        cal_hist: "ประวัติ",
        cal_sched: "ตารางเวลา",
        cal_models: "โมเดล",
        cal_reset: "รีเซ็ต",
        cal_all_tag: "แท็กทั้งหมด",
        cal_none: "ไม่มีรายการในวันนี้",
        cal_watched: "ดูแล้ว",
        cal_on_air: "ตามตาราง",
        cal_no_sched: "ตารางเวลาดึงมาจากโปรไฟล์ของรายการโปรด เปิดรายการโปรดแล้วรอสักครู่",
        cal_allday: "ทั้งวัน",
        cal_loaded: "โหลดตารางแล้ว: {a}/{b}",
        cal_c_model: "โมเดล",
        cal_c_time: "เข้า",
        cal_c_dur: "เวลา",
        cal_c_n: "ครั้ง",
        cal_total: "รวม"
    }
};
Object.keys(i18n).forEach(lg => {
    const pack = I18N_CAL[lg] || I18N_CAL.EN;
    Object.keys(I18N_CAL.EN).forEach(k => { if (i18n[lg] && i18n[lg][k] == null) i18n[lg][k] = pack[k] ?? I18N_CAL.EN[k]; });
});
const L = () => i18n[AppState.lang] || i18n.EN;
const fmtAgo = ts => {
    const l = L(), m = Math.max(0, Date.now() - ts) / 60000;
    if (m < 1) return l.seen_now;
    const n = m < 60 ? `${Math.floor(m)} ${l.u_m}` : m < 1440 ? `${Math.floor(m / 60)} ${l.u_h}` : `${Math.floor(m / 1440)} ${l.u_d}`;
    return l.ago.replace('{n}', n);
};

const CSS_UI = `:host{--th:${AppState.theme};pointer-events:none;position:fixed;left:0;right:0;bottom:0;top:auto;width:100%;height:0;z-index:2147483647;font-family:system-ui,-apple-system,sans-serif}*{box-sizing:border-box;margin:0;padding:0}.h-btn,.btn,.restore,.ghost,.vico,.z-btn,.bm-close,.bm-del,.bm-act-btn,.resize-handle{display:flex;align-items:center;justify-content:center}.panel{user-select:none;touch-action:none;position:absolute;width:304px;padding:12px;border-radius:16px;pointer-events:auto;background:rgba(15,15,18,.95);border:1px solid rgba(255,255,255,.1);box-shadow:0 10px 30px rgba(0,0,0,.7),inset 0 1px 1px rgba(255,255,255,.1);backdrop-filter:blur(24px) saturate(150%);transform-origin:top left;will-change:transform,left,top}.panel.mini{width:48px;height:48px;padding:0;background:transparent;border:none;box-shadow:none;backdrop-filter:none}.panel.hidden{display:none!important}.col{display:flex;flex-direction:column;gap:8px}.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:6px;margin-top:6px}.sep{height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.15),transparent);margin:2px 0}.hdr{display:flex;justify-content:space-between;align-items:center;background:rgba(0,0,0,.35);border-radius:10px;padding:6px 8px;margin-bottom:6px}.drag{flex:0 0 0;width:0;align-self:stretch;min-height:0;min-width:0;padding:0!important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:rgba(255,255,255,.6);font-size:9.5px;font-weight:600;letter-spacing:1px;text-transform:uppercase;cursor:grab;display:flex;align-items:center;justify-content:flex-start;padding-left:4px;user-select:none;touch-action:none!important;margin-right:auto}.drag:active{cursor:grabbing}.stats{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;background:rgba(0,0,0,.5);color:#fff;font-size:9px;min-width:30px;height:26px;padding:2px 4px;border-radius:6px;font-weight:bold;margin-right:2px;box-sizing:border-box;line-height:1;flex-shrink:0}.hdr-btns{display:flex;gap:5px;align-items:center;flex:1 1 auto;margin-left:0;justify-content:space-between}.h-btn{width:24px;height:24px;background:rgba(255,255,255,.05);border:none;border-radius:6px;color:#fff;cursor:pointer;font-size:12px;transition:.2s}.h-btn:hover{background:rgba(255,255,255,.2);transform:translateY(-1px)}.h-btn.close:hover{background:#e74c3c}.h-btn.lang{width:28px;font-weight:bold;background:rgba(255,255,255,.1);font-size:10px}.btn{color:#fff;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.05);border-radius:10px;padding:8px 2px 6px;font-size:18px;cursor:pointer;flex-direction:column;width:100%;transition:all .2s ease;outline:none}.btn:hover{background:rgba(255,255,255,.15);transform:translateY(-2px);border-color:rgba(255,255,255,.2)}.btn:active{transform:scale(.92)}.btn.on{background:var(--th);box-shadow:0 4px 10px rgba(0,0,0,.3);border-color:transparent}.btn sub{font-size:8px;font-weight:600;margin-top:4px;letter-spacing:.5px;text-transform:uppercase;opacity:.8;pointer-events:none;text-align:center;word-break:break-word;line-height:1}.restore{width:48px;height:48px;border-radius:24px;font-size:22px;background:var(--th);border:2px solid rgba(255,255,255,.3);display:none;cursor:pointer;pointer-events:auto;box-shadow:0 4px 15px rgba(0,0,0,.6);transition:.2s;touch-action:none!important}.restore:hover{transform:scale(1.05)}.ghost{position:absolute;bottom:80px;right:16px;width:44px;height:44px;border-radius:22px;font-size:20px;background:var(--th);border:2px solid rgba(255,255,255,.35);display:none;cursor:pointer;pointer-events:auto;box-shadow:0 4px 15px rgba(0,0,0,.6);transition:transform .2s,opacity .2s;touch-action:manipulation;z-index:2147483647}.ghost:hover,.ghost:active{transform:scale(1.1)}.v-cap{display:flex;align-items:center;gap:8px;background:rgba(0,0,0,.4);border-radius:12px;padding:8px 12px;border:1px solid rgba(255,255,255,.05)}.vico{color:#fff;font-size:16px;cursor:pointer;flex-shrink:0;filter:drop-shadow(0 2px 4px rgba(0,0,0,.5))}.vslider{-webkit-appearance:none;appearance:none;flex:1;height:3px;border-radius:2px;outline:none;cursor:pointer;background:linear-gradient(to right,var(--th) 0%,var(--th) var(--p,100%),rgba(255,255,255,.1) var(--p,100%),rgba(255,255,255,.1) 100%)}.vslider::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;border-radius:50%;background:#fff;box-shadow:0 0 5px rgba(0,0,0,.5);border:2px solid var(--th);cursor:pointer;transition:.2s}.vslider::-webkit-slider-thumb:hover{transform:scale(1.3)}.vval{font-size:10px;font-weight:600;color:#ccc;min-width:32px;text-align:right}.row-4{display:flex;align-items:center;justify-content:space-between;gap:8px}.scale-ctrl{display:flex;align-items:center;gap:4px;background:rgba(0,0,0,.3);border-radius:6px;padding:2px}.z-btn{width:20px;height:20px;background:rgba(255,255,255,.05);border:none;border-radius:4px;color:#fff;cursor:pointer;font-size:14px;transition:.2s;outline:none}.z-btn:hover{background:rgba(255,255,255,.2)}.s-val{font-size:9px;color:#ccc;min-width:24px;text-align:center;font-weight:bold}.hotkeys{font-size:9px;color:rgba(255,255,255,.4);text-align:center;font-weight:500;letter-spacing:.5px;padding-top:2px}.bm-overlay{position:fixed;inset:0;background:rgba(0,0,0,.8);display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:.3s;backdrop-filter:blur(5px);z-index:2147483647}.bm-overlay.open{opacity:1;pointer-events:auto}.bm-modal{width:370px;max-width:96vw;height:90vh;max-height:90vh;min-height:450px;background:rgb(20,20,25);border:1px solid rgba(255,255,255,.1);border-radius:16px;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 10px 40px rgba(0,0,0,.8)}.bm-hdr{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:rgba(0,0,0,.4);border-bottom:1px solid rgba(255,255,255,.05);flex-shrink:0}.bm-title{color:#fff;font-weight:bold;font-size:13px;white-space:nowrap;flex-shrink:0}.bm-close{background:none;border:none;color:#aaa;font-size:26px;cursor:pointer;padding:2px 8px;line-height:1;min-width:32px;min-height:32px}.bm-close:hover{color:#fff}.bm-list{flex:1;min-height:0;overflow-y:scroll;scrollbar-gutter:stable;padding:12px;display:flex;flex-direction:column;gap:10px}.bm-item{display:flex;flex-direction:column;gap:8px;padding:10px;background:rgba(255,255,255,.05);border-radius:12px;transition:.2s}.bm-item:hover{background:rgba(255,255,255,.08)}.bm-item-top{display:flex;align-items:center;justify-content:space-between;gap:10px}.bm-link{display:flex;align-items:center;gap:10px;text-decoration:none;color:#fff;flex:1;overflow:hidden}.bm-link:hover .bm-name{color:var(--th)}.bm-avatar{width:42px;height:42px;border-radius:50%;object-fit:cover;aspect-ratio:1/1;background:#333;border:1px solid rgba(255,255,255,.1);flex-shrink:0}.bm-name{font-size:15px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:.2s}.bm-del{width:30px;height:30px;border-radius:6px;background:rgba(231,76,60,.2);color:#e74c3c;border:none;cursor:pointer;transition:.2s;flex-shrink:0}.bm-del:hover{background:#e74c3c;color:#fff}.bm-del svg,.bm-modal .bm-del svg{width:14px;height:14px;margin:0!important;display:block;vertical-align:baseline}.bm-act-btn{height:28px;padding:0 8px;border-radius:6px;background:rgba(255,255,255,.06);color:#ccc;border:1px solid rgba(255,255,255,.08);gap:4px;cursor:pointer;font-size:11px;font-weight:600;transition:.2s}.bm-act-btn:hover{background:rgba(255,255,255,.15);color:#fff;border-color:rgba(255,255,255,.2)}.bm-act-btn svg{width:13px;height:13px;flex-shrink:0}.bm-note{width:100%;background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.1);color:#fff;border-radius:8px;padding:8px 10px;font-size:13px;font-family:inherit;outline:none;transition:.2s}.bm-note:focus{border-color:var(--th);background:rgba(0,0,0,.6);box-shadow:0 0 5px rgba(255,255,255,.1)}.bm-foot{padding:12px;display:grid;grid-template-columns:1fr 1fr;gap:8px;background:rgba(0,0,0,.4);border-top:1px solid rgba(255,255,255,.05);flex-shrink:0}.bm-add{grid-column:span 2;padding:12px;border-radius:8px;border:none;background:var(--th);color:#fff;font-weight:bold;cursor:pointer;font-size:14px;box-shadow:0 2px 10px rgba(0,0,0,.3);transition:.2s}.bm-add:hover{filter:brightness(1.2)}.bm-add:disabled{background:#555;cursor:not-allowed;opacity:.5}.bm-btn{padding:10px;border-radius:8px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.05);color:#ddd;font-size:13px;font-weight:600;cursor:pointer;transition:.2s}.bm-btn:hover{background:rgba(255,255,255,.15);color:#fff}.bm-empty{text-align:center;padding:30px 10px;color:#777;font-size:14px;grid-column:1 / -1}.bm-gallery-mode{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr));align-content:start;gap:10px;padding:10px}.bm-item{min-width:0}.bm-gallery-mode .bm-item{min-width:0;padding:10px;cursor:pointer;display:flex;flex-direction:column;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:12px;position:relative;gap:6px}.bm-gallery-mode .bm-item:hover{transform:translateY(-2px);z-index:10;border-color:var(--th);background:rgba(255,255,255,.08);box-shadow:0 4px 12px rgba(0,0,0,.5)}.bm-gallery-mode .bm-topic,.bm-gallery-mode .bm-note{display:none!important}.bm-gallery-mode .bm-item-top{display:contents}.bm-gallery-mode .bm-link{display:contents}.bm-gallery-mode .bm-link>div{order:1;display:flex;align-items:center;width:calc(100% - 32px);max-width:calc(100% - 32px);pointer-events:none}.bm-gallery-mode .bm-del{order:2;position:absolute;top:6px;right:6px;width:24px;height:24px;z-index:2;margin:0;border-radius:6px}.bm-gallery-mode .bm-avatar{order:3;width:100%!important;height:auto!important;aspect-ratio:16/9!important;border-radius:8px;object-fit:cover;object-position:center;border:1px solid rgba(0,0,0,.3);pointer-events:none;margin:0;display:block!important;filter:brightness(.75)}.bm-gallery-mode .bm-item:has(img[data-frame]) .bm-avatar{display:none!important}.bm-gallery-mode img[data-frame]{order:3;width:100%!important;height:auto!important;aspect-ratio:16/9!important;border-radius:8px;object-fit:cover;border:1px solid rgba(0,0,0,.3)!important;margin:0!important;pointer-events:none;display:block!important}.bm-gallery-mode .bm-actions-row{order:4;display:grid!important;width:100%;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:auto;padding-top:2px}.bm-gallery-mode .bm-act-btn{height:28px;padding:0;background:rgba(0,0,0,.4);border-radius:6px;border:1px solid rgba(255,255,255,.05)}.bm-gallery-mode .bm-act-btn span{display:none}.bm-gallery-mode .bm-act-btn svg{margin:0;width:14px;height:14px}.bm-gallery-mode .bm-name{font-size:12px;color:#eee;font-weight:bold;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (min-width:768px){.bm-modal{width:780px!important;max-width:92vw!important;height:85vh!important;max-height:85vh!important}.bm-list{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;align-content:start!important;gap:12px!important}.bm-gallery-mode{grid-template-columns:repeat(3,minmax(0,1fr))!important;gap:12px!important}}@media (min-width:1200px){.bm-modal{width:920px!important}.bm-gallery-mode{grid-template-columns:repeat(4,minmax(0,1fr))!important}}.bm-list::-webkit-scrollbar{width:6px}.bm-list::-webkit-scrollbar-thumb{background:rgba(255,255,255,.2);border-radius:3px}@keyframes pulseRec{0%,100%{background:rgba(255,255,255,.06);box-shadow:none}50%{background:#c0392b;box-shadow:0 2px 8px rgba(0,0,0,.5)}}.rec-active{animation:pulseRec 1.5s infinite!important;border-color:transparent!important}.resize-handle{position:absolute;right:2px;bottom:2px;width:16px;height:16px;cursor:nwse-resize;touch-action:none!important;opacity:.4;transition:opacity .2s;z-index:10}.resize-handle:hover{opacity:1}.resize-handle::after{content:none}.panel.mini .resize-handle{display:none!important}.rs-edge{position:absolute;z-index:9;touch-action:none!important}.rs-n{top:-5px;left:14px;right:14px;height:12px;cursor:ns-resize}.rs-s{bottom:-5px;left:14px;right:14px;height:12px;cursor:ns-resize}.rs-w{left:-5px;top:14px;bottom:14px;width:12px;cursor:ew-resize}.rs-e{right:-5px;top:14px;bottom:14px;width:12px;cursor:ew-resize}.rs-nw{top:-5px;left:-5px;width:18px;height:18px;cursor:nwse-resize}.rs-ne{top:-5px;right:-5px;width:18px;height:18px;cursor:nesw-resize}.rs-sw{bottom:-5px;left:-5px;width:18px;height:18px;cursor:nesw-resize}.panel.mini .rs-edge{display:none!important}@media(pointer:coarse){.rs-n,.rs-s{height:22px}.rs-n{top:-8px}.rs-s{bottom:-8px}.rs-w,.rs-e{width:22px}.rs-w{left:-8px}.rs-e{right:-8px}.rs-nw,.rs-ne,.rs-sw{width:28px;height:28px}.rs-nw{top:-8px;left:-8px}.rs-ne{top:-8px;right:-8px}.rs-sw{bottom:-8px;left:-8px}}.bm-prev:not([data-frame]){display:none!important}.bm-stat{width:8px;height:8px;border-radius:50%;background:#888;margin-right:8px;flex-shrink:0;box-shadow:0 0 4px rgba(0,0,0,.5);transition:.3s}.bm-nwrap{display:flex;align-items:center;min-width:0;flex:1}.bm-acts{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:4px}.bm-topic{font-size:11px;color:#ddd;background:rgba(0,0,0,.35);padding:6px 10px;border-radius:6px;margin:6px 0;word-break:break-word;white-space:pre-wrap;display:none;border:1px solid rgba(255,255,255,.08)}.bm-prev{width:100%;max-height:180px;object-fit:cover;border-radius:8px;margin-top:8px;display:none;border:1px solid rgba(255,255,255,.1);cursor:pointer}.bm-tbtn{display:flex;align-items:center;font-size:11px;font-weight:bold;padding:4px 10px;border-radius:12px;border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.05);color:#fff;cursor:pointer;transition:.2s;margin-right:4px;flex-shrink:0;box-sizing:border-box}.bm-tbtn.on{background:var(--th)}.bm-hbtn{font-size:11px;cursor:pointer;background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.15);color:#fff;border-radius:6px;display:flex;align-items:center;padding:3px 7px}.bm-sort-wrap{display:flex;align-items:center;gap:4px;margin-left:auto;margin-right:6px}.bm-tags-wrap{display:none;flex-wrap:wrap;gap:6px;padding:4px 12px 10px;background:rgba(0,0,0,.4);flex-shrink:0;border-bottom:1px solid rgba(255,255,255,.05)}.bm-modal button svg{vertical-align:middle}.bm-title svg{margin-right:4px;vertical-align:-2px}.bm-twrap{display:flex;align-items:center;gap:2px;flex:1}.bm-srch-in{margin-bottom:12px;font-size:18px;padding:12px;text-align:center;font-weight:bold}.bm-srch-btn{margin-bottom:8px;font-size:15px;padding:12px;transition:all .3s ease;border-left:4px solid transparent}.hd-sec{grid-column:1 / -1;color:#888;font-size:11px;font-weight:700;letter-spacing:1px;text-transform:uppercase;padding:6px 4px 0}.hd-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 12px;background:rgba(255,255,255,.05);border-radius:10px;color:#fff;font-size:13px;cursor:pointer;user-select:none;transition:.2s}.hd-row:hover{background:rgba(255,255,255,.09)}.hd-sw{position:relative;width:40px;height:22px;border-radius:11px;background:rgba(255,255,255,.15);flex-shrink:0;transition:.2s}.hd-sw::after{content:'';position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;transition:.2s}.hd-row.on .hd-sw{background:var(--th)}.hd-row.on .hd-sw::after{left:20px}.hd-rule{cursor:default}.hd-sel{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;color:#bbb;font-family:monospace}.hd-bulk{grid-column:1 / -1;display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.hd-bulk .bm-btn{padding:9px 4px;font-size:12px}.hd-txt{display:flex;flex-direction:column;gap:2px;min-width:0}.hd-txt b{font-weight:600}.hd-txt small{color:#999;font-size:11px;font-weight:400;line-height:1.25}.hd-row.na{opacity:1}.hd-na{color:#e0a040!important}.hd-hint{grid-column:1 / -1;color:#777;font-size:11px;padding:0 4px}.bm-overlay.peek{opacity:0!important;background:transparent!important;backdrop-filter:none!important;transition:opacity .12s!important}.hd-empty{grid-column:1 / -1;text-align:center;color:#777;font-size:13px;padding:10px}.pick-box{position:fixed;display:none;pointer-events:none;border:2px solid #e74c3c;background:rgba(231,76,60,.12);box-sizing:border-box;z-index:2147483646}.pick-bar{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);display:none;flex-direction:column;gap:8px;width:min(92vw,360px);padding:10px;background:rgba(15,15,18,.95);border:1px solid rgba(255,255,255,.15);border-radius:14px;box-shadow:0 8px 30px rgba(0,0,0,.7);pointer-events:auto;z-index:2147483647}.pick-bar.open{display:flex}.pick-info{color:#ddd;font-size:11px;font-family:monospace;word-break:break-all;max-height:56px;overflow:hidden}.pick-btns{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px}.bm-grp{width:100%;background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.1);color:#ddd;border-radius:8px;padding:7px 8px;font-size:12px;font-family:inherit;outline:none}.bm-grp option{background:#1b1b1f;color:#fff}.bm-gallery-mode .bm-grp{display:none!important}.bm-seen{flex-shrink:0;margin-left:8px;font-size:10px;color:#8a8a90;white-space:nowrap}.bm-modal.rs-modal{width:380px!important;max-width:94vw!important;height:auto!important;min-height:0!important;max-height:90vh!important}.rs-modal .bm-list{display:flex!important;flex-direction:column!important;flex:0 1 auto;overflow-y:auto;scrollbar-gutter:auto;gap:8px}.rs-qs{display:flex;flex-direction:column;gap:6px}.rs-qs .bm-btn{text-align:left}.rs-chips{display:flex;flex-wrap:wrap;gap:6px}.rs-chips .bm-tbtn{margin-right:0;padding:7px 12px;font-size:12px}.rs-info{font-size:12px;color:#ddd;min-height:16px;padding:2px 4px}.rs-note{font-size:11px;color:#8a8a90;padding:0 4px;line-height:1.35}.bm-btn.sel{background:var(--th);color:#fff;border-color:transparent}
.lp-modal .bm-list.lp-grid{display:grid!important;flex-direction:initial!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:8px!important;padding:12px!important}
.lp-btn{display:flex;align-items:center;justify-content:flex-start;gap:10px;min-height:46px;padding:8px 10px;border-radius:12px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.05);color:#ddd;font-size:13px;font-weight:600;text-align:left;cursor:pointer;transition:.2s;min-width:0}
.lp-btn .lp-code{flex:0 0 44px;width:44px;min-width:44px;box-sizing:border-box;height:26px;padding:0;font-variant-numeric:tabular-nums;display:flex;align-items:center;justify-content:center;border-radius:8px;background:rgba(255,255,255,.1);color:#fff;font-size:11px;font-weight:800;letter-spacing:.5px}
.lp-btn .lp-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lp-btn.lp-auto{grid-column:1/-1}
.lp-btn.sel{background:var(--th);color:#fff;border-color:transparent}
.lp-btn.sel .lp-code{background:rgba(0,0,0,.25)}

.bm-overlay.fav-ov{backdrop-filter:none;-webkit-backdrop-filter:none;background:rgba(0,0,0,.8);transition:opacity .18s ease}
.fav-modal{width:min(980px,96vw)!important;max-width:96vw!important;height:88vh!important;max-height:88vh!important;min-height:0!important;border-radius:20px;background:linear-gradient(180deg,rgba(30,30,37,.97),rgba(15,15,19,.98));border:1px solid rgba(255,255,255,.08);box-shadow:0 24px 70px rgba(0,0,0,.7)}
.fav-modal .bm-hdr{position:relative;flex-wrap:wrap;justify-content:flex-start;gap:8px;padding:14px 16px 12px;padding-inline-end:58px;background:rgba(255,255,255,.03);border-bottom:1px solid rgba(255,255,255,.06)}
.fav-modal .bm-title{display:flex;align-items:center;font-size:17px;font-weight:800;letter-spacing:.2px}
.fav-modal .bm-close{position:absolute;top:10px;inset-inline-end:12px;width:36px;height:36px;min-width:0;min-height:0;padding:0;border-radius:50%;background:rgba(255,255,255,.07);font-size:22px;color:#ccc}
.fav-modal .bm-close:hover{background:rgba(231,76,60,.85);color:#fff}
.fav-modal .bm-hdr>.bm-hbtn{margin-left:0!important}
.fav-modal .bm-hdr .bm-title{flex:1 1 auto;min-width:0}.fav-modal .bm-tools{order:3;flex:1 0 100%;display:flex;align-items:center;gap:8px;justify-content:center;justify-content:safe center;overflow-x:auto;scrollbar-width:none}.fav-modal .bm-tools::-webkit-scrollbar{display:none}.fav-modal .bm-tools>*{flex:0 0 auto;margin:0!important}.fav-modal .bm-tools .bm-hbtn{height:36px;min-width:40px;justify-content:center}.fav-modal .bm-tools .bm-hbtn.on{background:var(--th);border-color:transparent}.fav-modal .bm-tools .bm-sort-wrap .bm-hbtn.on{background:transparent}
.fav-modal .bm-hbtn{display:inline-flex;align-items:center;justify-content:center;line-height:1}.fav-modal .bm-hbtn svg{display:block;flex:none;margin:0!important}.fav-modal .bm-hdr{padding-inline-end:16px!important}.fav-modal .bm-grp-btn{display:flex!important;align-items:center;justify-content:space-between!important;gap:8px;width:100%;text-align:start!important}.fav-modal .bm-grp-btn>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fav-modal .bm-grp-arr{flex:none}.fav-modal .bm-tags-wrap{flex-direction:column!important;flex-wrap:nowrap!important;align-items:stretch;gap:10px!important;max-height:none!important;overflow:visible!important;padding:12px 16px!important}.fav-modal .bm-seg{display:flex;border:1px solid rgba(255,255,255,.12);border-radius:10px;overflow:hidden;background:rgba(255,255,255,.05)}.fav-modal .bm-seg .bm-tbtn{flex:1 1 0;min-width:0;height:36px;margin:0;padding:0 8px;border:0;border-radius:0;background:transparent;box-shadow:none;display:flex;align-items:center;justify-content:center;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fav-modal .bm-seg .bm-tbtn+.bm-tbtn{border-left:1px solid rgba(255,255,255,.12)}.fav-modal .bm-seg .bm-tbtn.on{background:var(--th)}.fav-modal .bm-seg svg{display:block;flex:none;margin:0;width:16px;height:16px}.fav-modal .bm-chips{display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;margin:0 -16px;padding:0 16px}.fav-modal .bm-chips::-webkit-scrollbar{display:none}.fav-modal .bm-chips .bm-tbtn{flex:none;padding:6px 14px}.fav-modal .bm-hdr .bm-title{padding-inline-end:48px;min-height:38px}.fav-modal .bm-hdr{row-gap:10px}.fav-modal .bm-tools{overflow:visible;gap:10px}.fav-modal .bm-tools>.bm-sort-wrap{flex:1 1 auto!important;display:flex}.fav-modal .bm-tools .bm-sort-wrap .bm-hbtn:first-child{flex:1 1 auto}.fav-modal .bm-tools .bm-sort-wrap .bm-hbtn:last-child{width:46px}.fav-modal .bm-setp{padding:2px 14px;gap:0;border:1px solid rgba(255,255,255,.08)}.fav-modal .bm-setrow+.bm-setrow{border-top:1px solid rgba(255,255,255,.06)}.fav-modal .bm-tools .bm-gear{width:48px;flex:none}
.fav-modal .bm-gear{width:48px;padding:0}.fav-modal .bm-gear svg{width:18px;height:18px}.fav-modal .bm-setp{display:none;flex:1 0 100%;order:4;flex-direction:column;gap:2px;padding:4px 10px;border-radius:12px;background:rgba(0,0,0,.28)}.fav-modal .bm-setp.open{display:flex}.fav-modal .bm-setrow{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:44px;font-size:14px;color:#ddd}.fav-modal .bm-sw{position:relative;flex:none;width:46px;height:26px;padding:0;border:0;border-radius:13px;background:rgba(255,255,255,.18);cursor:pointer;transition:.2s}.fav-modal .bm-sw::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;transition:.2s}.fav-modal .bm-sw.on{background:var(--th)}.fav-modal .bm-sw.on::after{left:23px}.fav-modal .bm-spd{height:30px;min-width:52px}.fav-modal.bm-no-topic .bm-topic{display:none!important}.fav-modal.bm-no-grp .bm-grp-btn{display:none!important}
.fav-modal .bm-sort-wrap{gap:0;margin:0;margin-inline-start:auto;border:1px solid rgba(255,255,255,.12);border-radius:10px;overflow:hidden;background:rgba(255,255,255,.05)}
.fav-modal .bm-hbtn{height:30px;padding:0 10px;gap:4px;border-radius:10px;font-weight:600;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);transition:.2s}
.fav-modal .bm-hbtn:hover{background:rgba(255,255,255,.14)}
.fav-modal .bm-sort-wrap .bm-hbtn{border:0;border-radius:0;background:transparent}
.fav-modal .bm-sort-wrap .bm-hbtn:hover{background:rgba(255,255,255,.1)}
.fav-modal .bm-sort-wrap .bm-hbtn+.bm-hbtn{border-left:1px solid rgba(255,255,255,.12)}
.fav-modal .bm-sort-wrap .bm-hbtn:last-child{padding:0 9px}
.fav-modal .bm-sort-wrap .bm-hbtn:last-child svg{margin:0}
.fav-modal .bm-tags-wrap{gap:6px;padding:10px 16px;max-height:92px;overflow-y:auto;background:transparent;border-bottom:1px solid rgba(255,255,255,.06)}
.fav-modal .bm-tbtn{margin:0;padding:6px 12px;border-radius:999px;font-size:12px;font-weight:600;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);transition:.2s}
.fav-modal .bm-tbtn:hover{background:rgba(255,255,255,.14)}
.fav-modal .bm-tbtn.on{background:var(--th);border-color:transparent;box-shadow:0 2px 10px rgba(0,0,0,.35)}
.fav-modal .bm-list{grid-template-columns:repeat(auto-fill,minmax(min(300px,100%),1fr))!important;gap:12px!important;padding:14px!important;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.2) transparent}
.fav-modal .bm-list.bm-gallery-mode{grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr))!important;gap:10px!important}
@media(min-width:760px){.fav-modal .bm-list.bm-gallery-mode{grid-template-columns:repeat(auto-fill,minmax(min(200px,100%),1fr))!important}}
.fav-modal .bm-item{position:relative;padding:12px 12px 12px 16px;gap:10px;border-radius:16px;background:linear-gradient(180deg,rgba(255,255,255,.065),rgba(255,255,255,.03));border:1px solid rgba(255,255,255,.08);transition:transform .2s,border-color .2s,background .2s,box-shadow .2s}
@media (hover:hover) and (pointer:fine){.fav-modal .bm-item:hover{background:linear-gradient(180deg,rgba(255,255,255,.09),rgba(255,255,255,.05));border-color:rgba(255,255,255,.18)}}
.fav-modal .bm-item,.fav-modal button{-webkit-tap-highlight-color:transparent}
.fav-modal .bm-item[data-st="0"]{--st:rgba(255,255,255,.14)}
.fav-modal .bm-item[data-st="1"]{--st:#2ecc71}
.fav-modal .bm-item[data-st="2"]{--st:#f39c12}
.fav-modal .bm-item[data-st="3"]{--st:#9b59b6}
.fav-modal .bm-item::before{content:"";position:absolute;left:0;top:14px;bottom:14px;width:3px;border-radius:0 3px 3px 0;background:var(--st,rgba(255,255,255,.14));transition:background .3s}
.fav-modal .bm-list:not(.bm-gallery-mode) .bm-avatar{box-sizing:border-box;width:48px;height:48px;padding:0;border:2px solid var(--st,rgba(255,255,255,.14));background-clip:padding-box;box-shadow:none}
.fav-modal .bm-avatar{transition:filter .3s,border-color .3s,box-shadow .3s}
.fav-modal .bm-item[data-st="0"] .bm-avatar{filter:grayscale(.8) brightness(.8)}
.fav-modal .bm-name{font-size:15px;font-weight:700;letter-spacing:.1px}
.fav-modal .bm-seen{font-size:11px;color:#9a9aa2}
.fav-modal .bm-list .bm-stat{display:none}
.fav-modal .bm-list:not(.bm-gallery-mode) .bm-act-btn{background:rgba(0,0,0,.4);border-color:rgba(255,255,255,.05)}
.fav-modal .bm-list:not(.bm-gallery-mode) .bm-act-btn:hover{background:rgba(0,0,0,.25);border-color:rgba(255,255,255,.15)}
.fav-modal .bm-list:not(.bm-gallery-mode) .bm-pin:not(.on),.fav-modal .bm-list:not(.bm-gallery-mode) .bm-del{background:rgba(0,0,0,.55);border-color:rgba(255,255,255,.1)}
.fav-modal .bm-list:not(.bm-gallery-mode) .bm-del:hover{background:#e74c3c}
.fav-modal .bm-list:not(.bm-gallery-mode) .bm-nwrap .bm-view:not(:empty){margin-inline-start:8px;padding:3px 6px;gap:3px;border-radius:9px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.06);color:#cfcfd6;font-size:11px}
.fav-modal .bm-stat{width:9px;height:9px}
.fav-modal .bm-del{width:32px;height:32px;border-radius:10px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);color:#d9707e}
.fav-modal .bm-del:hover{background:#e74c3c;border-color:transparent;color:#fff}
.fav-modal .bm-acts{gap:6px}
.fav-modal .bm-act-btn{height:32px;border-radius:10px;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.1);color:#d4d4da;font-size:12px}
.fav-modal .bm-act-btn:hover{background:var(--th);border-color:transparent;color:#fff}
.fav-modal .bm-note,.fav-modal .bm-grp{background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.08);border-radius:10px;padding:8px 10px;font-size:13px;color:#eee}
.fav-modal .bm-note:focus,.fav-modal .bm-grp:focus{border-color:var(--th);background:rgba(0,0,0,.5);box-shadow:0 0 0 3px rgba(255,255,255,.06)}
.fav-modal .bm-topic{margin:0;padding:8px 10px;border-radius:10px;border:1px solid rgba(255,255,255,.06);border-left:3px solid var(--th);background:rgba(0,0,0,.28);font-size:12px;line-height:1.4;color:#d0d0d6}
.fav-modal .bm-prev{margin-top:0;border-radius:12px;width:100%;aspect-ratio:16/9;max-height:none;object-fit:cover;background:rgba(255,255,255,.05)}
.fav-modal .bm-gallery-mode .bm-item{padding:8px;border-radius:16px;gap:8px}
.fav-modal .bm-gallery-mode .bm-item::before{display:none}
.fav-modal .bm-gallery-mode .bm-item[data-st="1"]{border-color:rgba(46,204,113,.55)}
.fav-modal .bm-gallery-mode .bm-item[data-st="2"]{border-color:rgba(243,156,18,.55)}
.fav-modal .bm-gallery-mode .bm-item[data-st="3"]{border-color:rgba(155,89,182,.6)}
.fav-modal .bm-gallery-mode .bm-avatar{border-radius:12px}
.fav-modal .bm-gallery-mode .bm-name{font-size:12.5px}
.fav-modal .bm-gallery-mode .bm-del{width:26px;height:26px;border-radius:8px;background:rgba(0,0,0,.55);border-color:rgba(255,255,255,.1)}
.fav-modal .bm-gallery-mode .bm-del:hover{background:#e74c3c}
.fav-modal .bm-gallery-mode .bm-act-btn{height:30px;padding:0;background:rgba(0,0,0,.4);border-radius:8px}
.fav-modal .bm-gallery-mode .bm-act-btn:hover{background:var(--th)}
.fav-modal .bm-foot{padding:12px 16px;background:rgba(255,255,255,.03);border-top:1px solid rgba(255,255,255,.06)}
.fav-modal .bm-add{padding:13px;border-radius:12px;font-size:14px;box-shadow:0 6px 18px rgba(0,0,0,.35)}
@supports(background:color-mix(in srgb,red,blue)){.fav-modal .bm-add{background:linear-gradient(135deg,var(--th),color-mix(in srgb,var(--th) 65%,#000))}}
.fav-modal .bm-add:disabled{background:rgba(255,255,255,.08);box-shadow:none;color:#8a8a90;opacity:1}
.fav-modal .bm-empty{padding:70px 12px;color:#8a8a90;font-size:15px}
.fav-modal .bm-empty::before{content:"★";display:block;font-size:44px;line-height:1;margin-bottom:10px;opacity:.35}
.fav-ov,.fav-modal,.fav-modal .bm-list,.fav-modal .hs-pane,.fav-modal .cal-pane,.fav-modal .bm-tags-wrap{overscroll-behavior:contain}
@media(max-width:520px){.fav-modal{width:100vw!important;max-width:100vw!important;height:100%!important;max-height:100%!important;border-radius:0;border:0}.fav-modal .bm-foot{padding-bottom:calc(12px + env(safe-area-inset-bottom,0px))}}
.panel:not(.mini){background:linear-gradient(180deg,rgba(30,30,37,.94),rgba(15,15,19,.96));border:1px solid rgba(255,255,255,.08);border-radius:20px;box-shadow:0 24px 70px rgba(0,0,0,.7),inset 0 1px 1px rgba(255,255,255,.08)}
.panel .hdr{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.06);border-radius:12px;padding:6px 8px;margin-bottom:8px}
.panel .drag{color:#9a9aa2;font-weight:700}
.panel .stats{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.08);border-radius:8px}.panel .stats circle{stroke:var(--th)}
.panel .h-btn{width:26px;height:26px;border-radius:50%;background:rgba(255,255,255,.07)}
.panel .h-btn.lang{width:30px;border-radius:10px;background:rgba(255,255,255,.1)}.hdr-btns .h-btn svg{width:19px!important;height:19px!important}.hdr-btns .h-btn.lang{border:1px solid var(--th)!important}.hdr-btns .stats{flex-direction:row!important;width:62px!important;min-width:62px!important;max-width:62px!important;flex:0 0 62px!important;justify-content:center!important;height:26px!important;gap:4px!important;padding:0 6px!important;font-size:12px!important;overflow:hidden!important}.hdr-btns .stats svg{width:15px!important;height:15px!important}.hdr-btns .stats span{font-size:12px!important;line-height:1!important}.row-2 .z-btn svg,.row-4 .z-btn svg{width:17px!important;height:17px!important}
.panel .h-btn:hover{background:rgba(255,255,255,.18)}
.panel .h-btn.close:hover{background:rgba(231,76,60,.9)}
.panel .btn{border-radius:12px;background:rgba(255,255,255,.065);border:1px solid rgba(255,255,255,.1);color:#e6e6ea}
.favnav{display:none;grid-template-columns:repeat(2,1fr);gap:6px;margin-top:6px}.favnav.on{display:grid}.favnav .btn{height:32px!important;min-height:0!important;padding:0!important}.favnav .btn sub{display:none!important}.favnav .btn svg{width:16px;height:16px}
.panel .btn:hover{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.2)}
.panel .btn.on{background:var(--th);border-color:transparent;color:#fff;box-shadow:0 4px 12px rgba(0,0,0,.35)}
@supports(background:color-mix(in srgb,red,blue)){.panel .btn.on{background:linear-gradient(135deg,var(--th),color-mix(in srgb,var(--th) 65%,#000))}}
.panel .btn.fav-on{position:relative;color:#ffc83d;border-color:rgba(255,200,61,.4)}
.panel .btn.fav-on sub{color:#e6e6ea}
.panel .v-cap{border-radius:12px;background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.08)}
.panel .z-btn{width:24px;height:24px;border-radius:8px;background:rgba(255,255,255,.1)}
.panel .z-btn:hover{background:rgba(255,255,255,.2)}
.panel:not(.mini)::before{content:'';position:absolute;top:-1px;left:16px;right:16px;height:2px;border-radius:0 0 2px 2px;background:linear-gradient(90deg,transparent,var(--th),transparent);pointer-events:none}
.panel .sep{background:linear-gradient(90deg,transparent,var(--th),transparent);opacity:.6}

.bm-overlay:not(.fav-ov){backdrop-filter:none;-webkit-backdrop-filter:none;background:rgba(0,0,0,.8);transition:opacity .18s ease}
.bm-modal:not(.fav-modal){border-radius:20px;background:linear-gradient(180deg,rgb(30,30,37),rgb(15,15,19))!important;border:1px solid rgba(255,255,255,.08);box-shadow:0 24px 70px rgba(0,0,0,.7)}
.bm-modal:not(.fav-modal) .bm-hdr{position:relative;gap:8px;padding:14px 16px 12px;padding-inline-end:58px;background:rgba(255,255,255,.03);border-bottom:1px solid rgba(255,255,255,.06)}
.bm-modal:not(.fav-modal) .bm-title{display:flex;align-items:center;gap:6px;font-size:17px;font-weight:800;letter-spacing:.2px}
.bm-modal:not(.fav-modal) .bm-close{position:absolute;top:50%;transform:translateY(-50%);inset-inline-end:12px;width:36px;height:36px;min-width:0;min-height:0;padding:0;border-radius:50%;background:rgba(255,255,255,.07);font-size:22px;color:#ccc;display:flex;align-items:center;justify-content:center;transition:.2s}
.bm-modal:not(.fav-modal) .bm-close:hover{background:rgba(231,76,60,.85);color:#fff}
.bm-modal:not(.fav-modal) .bm-hbtn{border-radius:10px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);transition:.2s}
.bm-modal:not(.fav-modal) .bm-list{padding:14px;gap:10px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.2) transparent}
.bm-modal:not(.fav-modal) .bm-btn{border-radius:12px;background:rgba(255,255,255,.065);border:1px solid rgba(255,255,255,.1);color:#e2e2e6}
.bm-modal:not(.fav-modal) .bm-btn:hover{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.18)}
.bm-modal:not(.fav-modal) .bm-btn:active{background:var(--th);border-color:transparent;color:#fff}
.bm-modal:not(.fav-modal) .bm-btn.sel,.bm-modal:not(.fav-modal) .bm-btn.sel:hover{background:var(--th);border-color:transparent;color:#fff}
.bm-modal:not(.fav-modal) .bm-tbtn{border-radius:999px;font-weight:600;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);transition:.2s}
.bm-modal:not(.fav-modal) .bm-tbtn.on{background:var(--th);border-color:transparent;box-shadow:0 2px 10px rgba(0,0,0,.35)}
.bm-modal:not(.fav-modal) .bm-note{background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.08);border-radius:10px}
.bm-modal:not(.fav-modal) .bm-note:focus{border-color:var(--th);background:rgba(0,0,0,.5);box-shadow:0 0 0 3px rgba(255,255,255,.06)}
.bm-modal:not(.fav-modal) .bm-srch-btn{border-radius:12px}
.bm-modal:not(.fav-modal) .hd-row{border-radius:12px;background:linear-gradient(180deg,rgba(255,255,255,.065),rgba(255,255,255,.03));border:1px solid rgba(255,255,255,.08);transition:.2s}
.bm-modal:not(.fav-modal) .hd-row:hover{border-color:rgba(255,255,255,.18)}
.bm-modal:not(.fav-modal) .hd-sec{color:#9a9aa2}
.bm-modal:not(.fav-modal) .lp-btn{border-radius:12px;background:rgba(255,255,255,.065);border-color:rgba(255,255,255,.1)}
.bm-modal:not(.fav-modal) .bm-foot{padding:12px 16px;background:rgba(255,255,255,.03);border-top:1px solid rgba(255,255,255,.06)}
@media(max-width:520px){.bm-modal:not(.fav-modal){border-radius:18px}}
.bm-modal .bm-close{display:flex;align-items:center;justify-content:center;padding:0!important;line-height:0;text-align:center}
.bm-modal .bm-close svg{display:block;flex:none;margin:0!important;width:16px;height:16px}
.bm-modal .bm-close.bm-back{inset-inline-end:56px!important}
.bm-modal:not(.fav-modal).has-back .bm-hdr{padding-inline-end:104px!important}
.fav-modal.has-back .bm-hdr .bm-title{padding-inline-end:96px!important}
:host([data-rtl]) .bm-back svg{transform:scaleX(-1)}
.bm-overlay.bm-nofade{transition:none!important}
.fav-modal .bm-search-wrap{display:none;padding:10px 16px 0;flex-shrink:0}
.fav-modal .bm-search-box{position:relative}
.fav-modal .bm-search-ico{position:absolute;inset-inline-start:12px;top:50%;transform:translateY(-50%);display:flex;color:#8a8a90;pointer-events:none}
.fav-modal .bm-search-ico svg{width:16px;height:16px}
.fav-modal .bm-search-in{width:100%;height:38px;padding:0 40px;border-radius:12px;background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.1);color:#f0f0f0;-webkit-text-fill-color:#f0f0f0;font-size:14px;font-family:inherit;outline:none;transition:.2s}
.fav-modal .bm-search-in:focus{border-color:var(--th);background:rgba(0,0,0,.5);box-shadow:0 0 0 3px rgba(255,255,255,.06)}
.fav-modal .bm-search-in::placeholder{color:#8a8a90}
.fav-modal .bm-hdr{padding:8px 12px 8px!important;padding-inline-end:50px!important;gap:6px!important;align-items:center}
.fav-modal .bm-title{font-size:16px!important;flex:0 0 auto!important}
.fav-modal .bm-close{top:9px!important;inset-inline-end:8px!important;width:32px!important;height:32px!important;font-size:20px!important}
.fav-modal .bm-title{flex:1 1 auto!important}
.fav-modal .bm-tools{order:2!important;flex:0 0 auto!important;gap:6px!important;justify-content:flex-end!important}
.fav-modal .bm-search-wrap{align-items:center;gap:8px}
.fav-modal .bm-search-box{flex:1 1 0;min-width:0}
.fav-modal .bm-search-wrap>.bm-sort-wrap{flex:0 0 auto!important;margin:0!important;height:34px}
.fav-modal .bm-search-wrap>.bm-sort-wrap .bm-hbtn{height:34px!important;padding:0 10px!important}
.fav-modal .bm-search-wrap>.bm-sort-wrap .bm-hbtn:last-child{width:38px!important;padding:0!important}
.fav-modal .bm-tools .bm-hbtn{height:32px!important;min-width:36px!important}
.fav-modal .bm-tools .bm-gear{width:38px!important}
.fav-modal .bm-tools>.bm-sort-wrap{min-width:0!important}
.fav-modal .bm-setp{order:4}
.fav-modal .bm-search-wrap{padding:6px 12px 0!important}
.fav-modal .bm-search-in{height:34px!important;font-size:13px!important}
.fav-modal .bm-tags-wrap{flex-direction:row!important;flex-wrap:wrap!important;align-items:center!important;gap:8px!important;padding:6px 12px!important;max-height:none!important;overflow:hidden!important}
.fav-modal .bm-seg{flex:1 1 100%;min-width:0;max-width:100%}
.fav-modal .bm-seg .bm-tbtn{height:30px!important;padding:0 12px!important;font-size:12px!important}
.fav-modal .bm-chips{flex:1 1 140px;min-width:0;margin:0!important;padding:0!important}
.fav-modal .bm-chips .bm-tbtn{padding:5px 12px!important}
.fav-modal .bm-hbtn svg,.fav-modal .bm-del svg,.fav-modal .bm-pin svg{display:block!important;margin:0 auto!important;flex:none}
.fav-modal .bm-act-btn svg{display:block!important;margin:0!important;flex:none}
.fav-modal .bm-act-btn{justify-content:center;text-align:center}
.fav-modal .bm-gear{display:inline-flex!important;align-items:center!important;justify-content:center!important;padding:0!important}
.fav-modal .bm-search-clr{position:absolute;inset-inline-end:6px;top:50%;transform:translateY(-50%);display:none;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:0;border-radius:50%;background:rgba(255,255,255,.1);color:#ddd;font-size:17px;line-height:1;cursor:pointer}
.fav-modal .bm-search-clr:hover{background:rgba(255,255,255,.2);color:#fff}
.fav-modal .bm-pin{display:flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;flex-shrink:0;border-radius:10px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);color:#9a9aa2;cursor:pointer;transition:.2s}
.fav-modal .bm-pin svg{width:15px;height:15px;margin:0;display:block;vertical-align:baseline}
.fav-modal .bm-pin:hover{background:rgba(245,197,24,.18);color:#f5c518}
.fav-modal .bm-pin.on{color:#f5c518;background:rgba(245,197,24,.14);border-color:rgba(245,197,24,.4)}
.fav-modal .bm-pin.on svg{fill:currentColor}
.fav-modal .bm-item.pinned{border-color:rgba(245,197,24,.3)}
.fav-modal .bm-gallery-mode .bm-pin{position:absolute;top:6px;right:38px;order:2;z-index:2;width:26px;height:26px;border-radius:8px;background:rgba(0,0,0,.55);border-color:rgba(255,255,255,.1)}
.fav-modal .bm-gallery-mode .bm-pin.on{border-color:rgba(245,197,24,.6)}
.fav-modal .bm-gallery-mode .bm-link>div{width:calc(100% - 66px);max-width:calc(100% - 66px)}
.fav-modal .bm-gallery-mode .bm-grp-btn{order:5;width:100%;padding:5px 8px;font-size:12px;min-width:0}
.fav-modal .bm-gallery-mode .bm-grp-btn>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stats,.panel .stats{width:42px;min-width:42px;max-width:42px;overflow:hidden;white-space:nowrap}
.bm-spd:disabled{cursor:default}
:host([data-rtl]) .bm-overlay{direction:rtl}
`;
const CSS_X = `.off{display:none!important}
:host([data-dfb]) :is(.bm-overlay,.cf-ov,.dlg-ov,.fr-ov){position:absolute!important;inset:auto 0 0 0!important;width:100%!important;height:100vh!important;height:100dvh!important}
.bm-modal.rs-modal.st-modal{width:460px!important}
.st-modal .bm-list>*{flex:none}
.st-row .bm-sw{position:relative;flex:none;width:46px;height:26px;padding:0;border:0;border-radius:13px;background:rgba(255,255,255,.18);cursor:pointer;transition:.2s}
.st-row .bm-sw::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;transition:.2s}
.st-row .bm-sw.on{background:var(--th)}
.st-row .bm-sw.on::after{left:23px}
.st-modal .bm-btn{flex:none}
.st-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:42px;padding:6px 12px;border-radius:10px;background:rgba(255,255,255,.05);color:#ddd;font-size:13px}
.st-lbl{flex:1;min-width:0}
.st-block{display:flex;flex-direction:column;gap:8px;padding:8px 12px 10px;border-radius:10px;background:rgba(255,255,255,.05);color:#ddd;font-size:13px}
.st-hint{color:#888;font-size:11px;line-height:1.35}
.st-ic{display:inline-flex;align-items:center;justify-content:center;flex:none;width:20px;height:20px;color:var(--th)}
.st-ic svg{width:18px;height:18px}
.hd-sec .st-ic{width:16px;height:16px}
.hd-sec .st-ic svg{width:14px;height:14px}
.hd-sec{display:flex;align-items:center;gap:6px}
.st-lbl{display:flex;align-items:center;gap:10px}
.st-pill{display:inline-flex;align-items:center;justify-content:center;gap:6px;flex:none;padding:7px 14px;border-radius:999px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.08);color:#e8e8ec;font-size:12px;font-weight:700;cursor:pointer;transition:.2s}
.st-pill:hover{background:rgba(255,255,255,.16)}
.st-pill svg{width:14px;height:14px}
.st-wide{display:flex;width:100%;padding:11px;border-radius:12px}
.st-tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}
.st-tile{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;min-height:60px;padding:7px 3px;border-radius:12px;border:1px solid rgba(255,255,255,.08);background:rgba(255,255,255,.03);color:#6d6d75;font-size:9.5px;font-weight:700;letter-spacing:.3px;text-transform:uppercase;line-height:1.1;text-align:center;cursor:pointer;transition:.2s}
.st-tile .st-ic{color:#fff}
.st-tile .st-tl{max-width:100%;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.st-tile.on{background:rgba(255,255,255,.09);border-color:var(--th);color:#fff}
.st-swatch.st-custom{background:conic-gradient(#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)}
.st-hsl{display:flex;flex-direction:column;gap:12px;padding-top:4px}
.st-hrow{display:flex;flex-direction:column;gap:6px;font-size:11px;color:#9a9aa2}
.st-hsl input,.st-range{-webkit-appearance:none;appearance:none;margin:0;outline:none;border-radius:8px}
.st-hsl input{width:100%;height:14px}
.st-range{width:150px;height:8px;background:rgba(255,255,255,.18)}
.st-hsl input::-webkit-slider-thumb,.st-range::-webkit-slider-thumb{-webkit-appearance:none;width:22px;height:22px;border-radius:50%;background:#fff;border:2px solid rgba(0,0,0,.45);box-shadow:0 1px 5px rgba(0,0,0,.55);cursor:pointer}
.st-hsl input::-moz-range-thumb,.st-range::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#fff;border:2px solid rgba(0,0,0,.45);cursor:pointer}
.st-prev{height:8px;border-radius:4px;background:var(--th)}
.cf-ov{position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;padding:20px;background:rgba(0,0,0,.75);pointer-events:auto}
.cf-card{width:320px;max-width:100%;padding:20px;border-radius:20px;background:linear-gradient(180deg,rgb(32,32,40),rgb(18,18,23));border:1px solid rgba(255,255,255,.1);box-shadow:0 20px 60px rgba(0,0,0,.7);color:#eee;font-size:14px;line-height:1.45}
.cf-txt{margin-bottom:16px}
.cf-btns{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.cf-btns button{padding:11px;border-radius:12px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.07);color:#eee;font-size:13px;font-weight:700;cursor:pointer}
.cf-btns .cf-yes{background:var(--th);border-color:transparent;color:#fff}
.st-chips{display:flex;flex-wrap:wrap;gap:6px}
.st-chips .bm-tbtn{flex:0 0 auto;height:auto;margin:0;padding:7px 12px;font-size:12px;border:1px solid rgba(255,255,255,.2);border-radius:12px;background:rgba(255,255,255,.05);white-space:normal;text-align:center}
.st-chips .bm-tbtn.on{background:var(--th)}
.st-sw-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.st-swatch{width:26px;height:26px;padding:0;border-radius:50%;border:2px solid transparent;cursor:pointer}
.st-swatch.sel{border-color:#fff}
.st-color{width:34px;height:26px;padding:0;border:0;background:none;cursor:pointer}
.st-val{min-width:42px;text-align:right;color:#aaa;font-size:12px}
.bm-view{display:inline-flex;align-items:center;gap:3px;margin-left:8px;font-size:11px;color:#aaa;flex-shrink:0}
.bm-view svg{width:12px;height:12px}
.hs-tools{display:flex;justify-content:flex-end}
.hs-tools .bm-btn{padding:8px 16px;font-size:12px}
.hs-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:12px;background:rgba(255,255,255,.05);cursor:pointer;transition:.2s}
.hs-row:hover{background:rgba(255,255,255,.09)}
.hs-ava{flex:none;width:42px;height:42px;border-radius:50%;object-fit:cover;background:rgba(255,255,255,.1)}
.hs-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.hs-name{color:#fff;font-size:14px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hs-meta{color:#9a9aa2;font-size:11.5px}
.hs-btn{flex:none;width:32px;height:32px;padding:0;border:0;border-radius:8px;background:rgba(255,255,255,.08);color:#ddd;cursor:pointer;display:flex;align-items:center;justify-content:center}
.hs-btn:hover{background:rgba(255,255,255,.18)}
.hs-btn.on{color:#ffc83d}
.hs-btn.on svg{fill:currentColor}
:where(.bm-modal) button{display:inline-flex;align-items:center;justify-content:center;gap:5px}
.bm-modal button svg{flex:none;margin:0}
.hs-btn svg,.bm-close svg,.bm-del svg,.bm-pin svg{display:block;margin:0!important}
.hs-btn svg{width:16px;height:16px}
.bm-btn,.bm-add{display:inline-flex;align-items:center;justify-content:center;gap:6px}
.fav-modal .bm-tabs{flex:0 1 auto;min-width:0;max-width:100%}
.fav-modal .bm-hdr .bm-title{padding-inline-end:0!important;flex:1 1 auto!important;min-width:0;min-height:0}
.fav-modal .bm-tools{order:2!important;flex:0 0 auto!important;margin-inline-start:auto!important;justify-content:flex-end!important;gap:6px!important}
.fav-modal .bm-tabs .bm-tbtn{height:34px!important;padding:0 12px!important;font-size:13px!important;font-weight:700;gap:6px;color:#aaa;flex:1 1 auto}
.fav-modal .bm-tabs .bm-tbtn.on{color:#fff}
.fav-modal .bm-tabs .bm-tbtn svg{width:15px;height:15px}
.fav-modal .bm-tools{order:3!important;flex:1 0 100%!important;justify-content:flex-end!important}
.fav-modal .bm-tools .bm-wseg-host{margin-inline-end:auto;display:flex;min-width:0}
.fav-modal.mode-hist .bm-search-wrap,.fav-modal.mode-hist .bm-tags-wrap,.fav-modal.mode-hist .bm-list,.fav-modal.mode-hist .bm-foot,.fav-modal.mode-hist .bm-tools,.fav-modal.mode-hist .bm-setp{display:none!important}
.fav-modal .hs-pane{display:none}
.fav-modal.mode-hist .hs-pane{display:flex;flex-direction:column;gap:8px;flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.2) transparent}
.hs-pane>*{flex:none}
.hs-btn.del{color:#e5616f;background:rgba(229,97,111,.12)}
.hs-btn.del:hover{background:#e74c3c;color:#fff}
.st-chips{align-items:center}
.st-chips .bm-tbtn.hs-clear{margin-inline-start:auto;display:inline-flex;align-items:center;gap:6px;color:#ff8591;background:rgba(229,97,111,.12);border-color:rgba(229,97,111,.45)}
.st-chips .bm-tbtn.hs-clear:hover{background:#e74c3c;border-color:transparent;color:#fff}
.st-chips .bm-tbtn.hs-clear svg{width:14px;height:14px;display:block;flex:none;margin:0}
.hs-sep{flex:none;width:1px;height:22px;margin:0 6px;background:rgba(255,255,255,.22);border-radius:1px}
.ch-box{padding:10px 12px;border-radius:12px;background:rgba(255,255,255,.05);margin-bottom:8px}
.ch-ttl{display:flex;justify-content:space-between;gap:8px;font-size:12px;color:rgba(255,255,255,.65);margin-bottom:8px}
.ch-ttl b{font-weight:600;color:#fff}
.ch-bars{display:flex;align-items:flex-end;gap:3px;height:84px;direction:ltr}
.ch-col{flex:1 1 0;min-width:0;height:100%;display:flex;align-items:flex-end}
.ch-bar{width:100%;min-height:2px;border-radius:4px 4px 0 0;background:var(--th)}
.ch-bar.zero{background:rgba(255,255,255,.12)}
.ch-axis{display:flex;gap:3px;margin-top:4px;font-size:9px;color:rgba(255,255,255,.5);direction:ltr}
.ch-axis span{flex:1 1 0;min-width:0;text-align:center;white-space:nowrap}
.ch-row{display:flex;align-items:center;gap:8px;font-size:12px;margin-top:6px}
.ch-name{flex:0 0 32%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ch-track{flex:1 1 auto;height:8px;border-radius:4px;background:rgba(255,255,255,.08);overflow:hidden}
.ch-fill{height:100%;border-radius:4px;background:var(--th)}
.ch-val{flex:0 0 auto;color:rgba(255,255,255,.65);font-variant-numeric:tabular-nums}
.bm-view{margin-left:0;margin-inline-start:8px}
:host([data-rtl]) .fav-modal .bm-gallery-mode .bm-pin{right:auto;left:auto;inset-inline-end:38px}
:host([data-rtl]) .bm-gallery-mode .bm-del{right:auto;left:6px}
:host([data-rtl]) .fav-modal .bm-gallery-mode .bm-pin{left:38px}
:host([data-rtl]) .fav-modal .bm-gallery-mode .bm-link>div{padding-inline:0}
:host([data-rtl]) .fav-modal .bm-item{padding:12px 16px 12px 12px}
:host([data-rtl]) .fav-modal .bm-gallery-mode .bm-item{padding:8px}
:host([data-rtl]) .fav-modal .bm-item::before{left:auto;right:0;border-radius:3px 0 0 3px}
:host([data-rtl]) .fav-modal .bm-topic{border-left:0;border-right:3px solid var(--th)}
:host([data-rtl]) .st-val{text-align:left}
:host([data-rtl]) .lp-btn{text-align:right}
:host([data-rtl]) .fav-modal .bm-sort-wrap .bm-hbtn+.bm-hbtn{border-left:0;border-right:1px solid rgba(255,255,255,.12)}
:host([data-rtl]) .fav-modal .bm-seg .bm-tbtn+.bm-tbtn{border-left:0;border-right:1px solid rgba(255,255,255,.12)}
.fav-modal .bm-seg .bm-tbtn{gap:6px}
.fav-modal .bm-chips .bm-tbtn svg{width:12px;height:12px;margin-inline-end:4px;vertical-align:-1px}
.fav-modal .bm-grp-btn svg{width:12px;height:12px;margin-inline-end:4px;vertical-align:-1px}
.dlg-txt{display:flex;align-items:center;gap:8px}
.dlg-txt svg{width:14px;height:14px;flex:none}
.fav-modal .bm-ptags{display:flex;flex-wrap:wrap;gap:4px;width:100%}
.fav-modal .bm-ptag{padding:2px 8px;border-radius:999px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.06);color:#cfcfd6;font-size:11px;font-family:inherit;cursor:pointer;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fav-modal .bm-ptag.on{background:var(--th);color:#fff;border-color:transparent}
.fav-modal .bm-ptag.more{cursor:default;opacity:.7}
.fav-modal .bm-gallery-mode .bm-ptags{order:6}
.fav-modal .bm-gallery-mode .bm-ptag{font-size:10px;padding:1px 6px}
.fav-modal .bm-list.bm-gallery-mode .bm-item .bm-grp-btn{display:none!important}
.fav-modal .bm-gallery-mode .bm-nwrap{flex-wrap:wrap;row-gap:2px;align-content:flex-start}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-stat{flex:none;margin:0 6px 0 0}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-name{flex:1 0 calc(100% - 16px);min-width:0}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-view{margin:0 8px 0 0}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-view:not(:empty),.fav-modal .bm-gallery-mode .bm-nwrap .bm-view:empty+.bm-seen{margin-inline-start:15px}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-seen{margin-left:0}
.fav-modal .bm-tabs .bm-tbtn{padding:0 8px!important;font-size:12.5px!important}
.fav-modal .cal-pane{display:none}
.fav-modal.mode-cal .cal-pane{display:flex;flex-direction:column;gap:10px;flex:1 1 auto;min-height:0;overflow-y:auto;padding:12px 14px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.2) transparent}
.fav-modal.mode-cal .bm-search-wrap,.fav-modal.mode-cal .bm-tags-wrap,.fav-modal.mode-cal .bm-list,.fav-modal.mode-cal .bm-foot,.fav-modal.mode-cal .bm-tools,.fav-modal.mode-cal .bm-setp,.fav-modal.mode-cal .hs-pane{display:none!important}
.fav-modal.mode-hist .cal-pane{display:none!important}
.cal-pane>*{flex:none}
.cal-pane{overflow-anchor:none}
.cal-head{display:flex;align-items:center;gap:8px}
.cal-title{flex:1;text-align:center;font-weight:700;font-size:15px}
.cal-nav svg{display:block;margin:auto}
.cal-nav,.cal-today{height:34px;min-width:34px;padding:0 10px;border-radius:10px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.06);color:#eee;font-size:16px;font-family:inherit;cursor:pointer}
.cal-today{font-size:12px}
.cal-filters{display:flex;flex-direction:column;gap:8px}
.cal-frow{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.cal-sel{flex:1 1 130px;min-width:0;height:34px;border-radius:10px;border:1px solid rgba(255,255,255,.12);background:rgba(0,0,0,.35);color:#eee;padding:0 8px;font:inherit;font-size:13px}
.cal-tl{display:inline-flex;align-items:center;gap:6px}
.cal-tl svg{width:14px;height:14px;flex:none}
.cal-pill{flex:1 1 100%;height:36px;padding:0 12px;text-align:center;border-radius:10px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.06);color:#ddd;font:inherit;font-size:13px;cursor:pointer}
.cal-pill.on{background:var(--th);color:#fff;border-color:transparent}
.cal-models{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;max-height:280px;overflow-y:auto;padding:8px;border-radius:12px;background:rgba(0,0,0,.28);border:1px solid rgba(255,255,255,.06);scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.2) transparent}
.cal-mrow{display:flex;align-items:center;justify-content:flex-start;gap:8px;min-width:0;height:42px;padding:0 10px 0 7px;border-radius:12px;border:1px solid rgba(255,255,255,.08);background:rgba(255,255,255,.05);color:#d4d4da;font:inherit;font-size:13px;font-weight:600;cursor:pointer;text-align:start}
.cal-mrow>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-mrow svg{width:14px;height:14px;flex:none}
.cal-mrow.on{background:var(--th);border-color:transparent;color:#fff}
.cal-mrow.reset{grid-column:1/-1;justify-content:center;height:34px;font-weight:500;color:#aaa}
.cal-mrow.reset>span{flex:none}
.cal-ava.sm{width:26px;height:26px}
.cal-dd{flex:1 1 130px;min-width:0;height:36px;display:flex;align-items:center;gap:8px;padding:0 12px;border-radius:10px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.06);color:#ddd;font:inherit;font-size:13px;cursor:pointer;text-align:start}
.cal-dd svg{width:14px;height:14px;flex:none;opacity:.8}
.cal-dd>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-dd::after,.cal-fold::after{content:'';flex:none;width:7px;height:7px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(45deg) translateY(-2px);opacity:.6;transition:transform .15s}
.cal-dd.open::after,.cal-fold.open::after{transform:rotate(225deg) translateY(-2px)}
.cal-dd.on{background:var(--th);color:#fff;border-color:transparent}
.cal-panel{display:flex;flex-wrap:wrap;gap:6px;max-height:230px;overflow-y:auto;padding:10px;border-radius:12px;background:rgba(0,0,0,.28);border:1px solid rgba(255,255,255,.06);scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.2) transparent}
.cal-panel .cal-sep{flex:1 1 100%;height:0;border-top:1px solid rgba(255,255,255,.08);margin:2px 0}
.cal-opt{display:inline-flex;align-items:center;gap:6px;max-width:100%;height:30px;padding:0 11px;border-radius:999px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.05);color:#cfcfd6;font:inherit;font-size:12.5px;cursor:pointer;white-space:nowrap}
.cal-opt svg{width:13px;height:13px;flex:none}
.cal-opt>span{overflow:hidden;text-overflow:ellipsis}
.cal-opt i{font-style:normal;font-size:10.5px;opacity:.55}
.cal-opt.all{font-weight:700}
.cal-opt.on{background:var(--th);color:#fff;border-color:transparent}
.cal-wsec{display:flex;flex-direction:column;gap:8px}
.cal-dtitle+.cal-wsec>.cal-fold{margin-top:0;padding-top:0;border-top:0}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:5px}
.cal-wd{text-align:center;font-size:11px;font-weight:600;color:#8a8a90;padding:2px 0;text-transform:capitalize;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-day{position:relative;min-height:54px;padding:7px 2px 5px;border-radius:12px;border:1px solid rgba(255,255,255,.07);background:rgba(255,255,255,.04);color:#e6e6ea;display:flex;flex-direction:column;align-items:center;justify-content:space-between;gap:4px;cursor:pointer;font:inherit;font-size:13px;font-weight:600;min-width:0;transition:background .15s}
.cal-day:hover{background:rgba(255,255,255,.09)}
.cal-day.blank{visibility:hidden;pointer-events:none}
.cal-day.past{color:#9a9aa2}
.cal-day.today{border-color:var(--th);box-shadow:inset 0 0 0 1px var(--th)}
.cal-day.sel{background:var(--th);color:#fff;border-color:transparent;box-shadow:0 2px 10px rgba(0,0,0,.35)}
.cal-n{line-height:1}
.cal-bs{display:flex;gap:3px;justify-content:center;align-items:center;min-height:15px}
.cal-b{font-style:normal;font-size:10px;font-weight:700;line-height:1;min-width:16px;padding:3px 4px;text-align:center;border-radius:999px;background:rgba(46,204,113,.22);color:#7ee2a8}
.cal-b.s{background:rgba(90,150,255,.22);color:#9cc0ff}
.cal-day.past .cal-b.s{opacity:.6}
.cal-day.sel .cal-b{background:rgba(0,0,0,.32);color:#fff}
.cal-det{display:flex;flex-direction:column;gap:8px;padding:12px;border-radius:14px;background:rgba(0,0,0,.28);border:1px solid rgba(255,255,255,.06)}
.cal-dtitle{font-weight:700;font-size:15px}
.cal-sec{font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:#8a8a90;margin-top:6px;padding-top:10px;border-top:1px solid rgba(255,255,255,.07)}
.cal-dtitle+.cal-sec{margin-top:0;padding-top:0;border-top:0}
.cal-tbl{display:flex;flex-direction:column;border-radius:12px;overflow:hidden;border:1px solid rgba(255,255,255,.07)}
.cal-trow{display:grid;grid-template-columns:minmax(0,1fr) 52px 78px 54px;align-items:center;gap:6px;padding:7px 10px;font-size:12.5px;font-variant-numeric:tabular-nums}
.cal-trow>span{text-align:end;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#cfcfd6}
.cal-trow+.cal-trow{border-top:1px solid rgba(255,255,255,.05)}
.cal-trow:nth-child(even){background:rgba(255,255,255,.03)}
.cal-thead{background:rgba(255,255,255,.08)!important;font-size:10px;font-weight:700;letter-spacing:.4px;text-transform:uppercase}
.cal-thead>span{color:#9a9aa2}
.cal-tfoot{background:rgba(255,255,255,.08)!important;font-weight:700}
.cal-tfoot>span{color:#fff}
.cal-tfoot>span:first-child{text-align:start}
.cal-who{display:flex;align-items:center;gap:8px;min-width:0}
.cal-who a{min-width:0;color:#fff;text-decoration:none;font-weight:600;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-thead>span:first-child{text-align:start}
.cal-trow>span:nth-child(2),.cal-trow>span:nth-child(3){text-align:center}
.cal-trow>span:nth-child(4){text-align:end}
.cal-axis{display:flex;justify-content:space-between;margin-left:38px;direction:ltr;font-size:10px;color:#6f6f76;font-variant-numeric:tabular-nums}
.cal-row{display:flex;align-items:center;gap:10px;min-width:0}
.cal-ava{flex:none;width:28px;height:28px;border-radius:50%;object-fit:cover;background:rgba(255,255,255,.08)}
.cal-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px}
.cal-line{display:flex;align-items:center;gap:6px;min-width:0;font-size:13px}
.cal-line a{flex:1;min-width:0;color:#fff;text-decoration:none;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-line a:hover{color:var(--th)}
.cal-t{flex:none;color:#aab;font-size:12px;font-variant-numeric:tabular-nums}
.cal-bar{position:relative;height:6px;border-radius:3px;background:rgba(255,255,255,.08);direction:ltr}
.cal-seg{position:absolute;top:0;bottom:0;border-radius:3px;background:#5a96ff}
.cal-now{position:absolute;top:-3px;bottom:-3px;width:2px;margin-left:-1px;border-radius:1px;background:#fff}
.cal-dot{flex:none;width:8px;height:8px;border-radius:50%;background:#2ecc71;box-shadow:0 0 6px #2ecc71}
.cal-muted{color:#8a8a90;font-size:12px}
.cal-fold{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;margin-top:6px;padding:10px 0 0;border:0;border-top:1px solid rgba(255,255,255,.07);background:none;font-family:inherit;cursor:pointer;text-align:start}
.cal-fold>span{flex:1;min-width:0}
.fav-modal .bm-list:not(.bm-gallery-mode) .bm-ptags{gap:5px;margin-top:4px;padding-top:8px;border-top:1px solid rgba(255,255,255,.06)}
.fav-modal .bm-ptags .bm-ptag{display:inline-flex;align-items:center;gap:5px;padding:2px 9px 2px 6px;border:0;border-radius:999px;background:rgba(255,255,255,.05);color:#9aa0b2;font-size:11.5px}
.fav-modal .bm-ptic{width:15px;height:15px;flex:none;object-fit:contain}
.fav-modal .bm-chips .bm-tbtn .bm-ptic{width:15px;height:15px;margin-inline-end:5px;vertical-align:-3px}
.cal-tic{width:16px;height:16px;flex:none;object-fit:contain}
.fav-modal .bm-ptags .bm-ptag.more{background:transparent;padding:2px 4px}
.fav-modal .bm-ptags .bm-ptag.on{background:var(--th);color:#fff}
.fav-modal.bm-no-ptags .bm-ptags{display:none!important}
.fav-modal.bm-no-note .bm-item .bm-note{display:none!important}
.fav-modal .bm-chips .bm-chips-sep{flex:none;width:1px;align-self:stretch;margin:4px 2px;background:rgba(255,255,255,.14)}
.fav-modal .bm-gallery-mode .bm-ptags{display:none!important}
.fav-modal .bm-gallery-mode .bm-link>div{width:100%;max-width:100%;pointer-events:auto}
.fav-modal .bm-gallery-mode .bm-link{position:relative}
.fav-modal .bm-gallery-mode .bm-nwrap{align-items:center;flex-wrap:nowrap;row-gap:0;min-height:26px;padding-inline-end:58px}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-stat{display:none}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-name{order:1;flex:1 1 auto;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-view,.fav-modal .bm-gallery-mode .bm-nwrap .bm-seen{position:absolute;bottom:55px;margin:0!important;padding:2px 7px;border-radius:999px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;line-height:1.3;white-space:nowrap;z-index:1;pointer-events:none}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-view{right:15px}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-seen{left:15px}
.fav-modal .bm-gallery-mode .bm-nwrap .bm-view:empty,.fav-modal .bm-gallery-mode .bm-nwrap .bm-seen:empty{display:none}
.fav-modal .bm-tools{margin-inline-end:-38px!important;justify-content:stretch!important}
.fav-modal .bm-tools>.bm-wseg-host{flex:2 1 0!important;margin-inline-end:0!important}
.fav-modal .bm-tools>.bm-hbtn{flex:1 1 0!important;width:auto!important;min-width:0!important}
.fav-modal .bm-seg.bm-wseg{flex:1 1 auto;width:100%;max-width:none}
.fav-modal .bm-seg.bm-wseg .bm-tbtn{flex:1 1 0;width:auto;padding:0!important;height:30px!important}
.fav-modal .bm-seg.bm-wseg svg{width:21px;height:21px}
.fav-modal .bm-tools .bm-prevbtn svg,.fav-modal .bm-tools .bm-colsbtn svg{width:18px;height:18px}
.fav-modal .bm-tools .bm-hbtn.bm-gear{border:1px solid var(--th)!important}
.panel .hdr-btns .h-btn{width:30px;height:30px}
.panel .hdr-btns .h-btn.lang{width:34px}
.panel .hdr-btns .h-btn svg{width:22px!important;height:22px!important}
.panel .hdr-btns{gap:3px;justify-content:flex-end;min-width:0}
.panel .hdr-btns .h-btn{position:relative}
.panel .hdr-btns{align-items:center}
.panel .hdr-btns .hsep{flex:0 0 1px;width:1px;height:16px;margin:0 2px;background:rgba(255,255,255,.16);pointer-events:none}
.panel .hdr-btns .stats+.hsep{margin-inline-start:0}
.panel .hdr-btns .stats.off+.hsep{display:none}
.fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-del,.fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-pin{top:5px;width:32px;height:32px;border-radius:10px}
.fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-del{right:8px}
.fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-pin{right:46px}
.fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-del svg,.fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-pin svg{width:18px!important;height:18px!important}
.fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-nwrap{padding-inline-end:86px}
:host([data-rtl]) .fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-del{right:auto;left:8px}
:host([data-rtl]) .fav-modal .bm-list.bm-c1.bm-gallery-mode .bm-pin{right:auto;inset-inline-end:auto;left:46px}
`;
const STAR_CSS = `.bcu-host{position:relative!important}
.bcu-star{box-sizing:border-box;padding:0;line-height:0;position:absolute;left:6px;bottom:6px;z-index:6;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:50%;background:rgba(0,0,0,.55);color:#fff;cursor:pointer;opacity:.92;transition:transform .15s,background .15s,color .15s;-webkit-tap-highlight-color:transparent;user-select:none;touch-action:manipulation}
a.thm_a>.bcu-star{left:auto;right:6px}
a.lst_link>.bcu-star{left:auto;right:6px;bottom:auto;top:50%;margin-top:-15px}
a[data-model-list-link]>.bcu-star{left:auto;right:6px;bottom:auto;top:50%;margin-top:-15px}
.bcu-star svg{display:block;flex:none;margin:0;width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linejoin:round;pointer-events:none}
.bcu-star:hover{transform:scale(1.12);background:rgba(0,0,0,.78)}
.bcu-star.on{color:#ffc83d}
.bcu-star.on svg{fill:currentColor}
.bcu-ring{display:none;position:absolute;inset:0;z-index:5;border:2px solid #ffc83d;border-radius:inherit;box-sizing:border-box;pointer-events:none}
.bcu-fav>.bcu-ring{display:block}
`;

class Helpers {
    static getModelSecretData() {
        try {
            for (const el of document.querySelectorAll('script[type="application/json"]')) {
                const t = el.textContent;
                if (!/chatHost|chatHeaderOptions|chatLocalData/.test(t)) continue;
                if (this._secretSrc === t) return this._secretData;
                this._secretSrc = t;
                this._secretData = null;
                return (this._secretData = JSON.parse(t));
            }
        } catch {}
        return null;
    }
    static createElement(tag, className = '') {
        const el = document.createElement(tag);
        if (className) el.className = className;
        return el;
    }
    static createButton(iconHTML, label, className = '') {
        const b = this.createElement('button', `btn ${className}`.trim());
        b.innerHTML = `<span>${iconHTML}</span><sub>${label}</sub>`;
        return b;
    }
    static formatTime(s) {
        const p = n => String(n | 0).padStart(2, '0');
        return `${p(s / 60)}:${p(s % 60)}`;
    }
    static getTimestamp() {
        const d = new Date(), p = n => String(n).padStart(2, '0');
        return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}_${p(d.getHours())}-${p(d.getMinutes())}-${p(d.getSeconds())}`;
    }
    static download(blob, filename) {
        const url = URL.createObjectURL(blob), a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = String(filename).replace(/[\\/:*?"<>|]+/g, '_');
        document.body.appendChild(a);
        a.click();
        setTimeout(() => { a.remove(); URL.revokeObjectURL(url); }, 60000);
    }
    static bindLongPress(el, onClick, onHold, ms = 400) {
        let timer = 0, fired = false, active = false;
        const clear = () => { clearTimeout(timer); timer = 0; };
        el.oncontextmenu = e => e.preventDefault();
        el.onpointerdown = e => {
            if (!isPrimaryPress(e)) return;
            active = true;
            fired = false;
            clear();
            timer = setTimeout(() => { fired = true; timer = 0; onHold(e); }, ms);
        };
        el.onpointerup = e => {
            if (!active) return;
            active = false;
            clear();
            const wasHold = fired;
            fired = false;
            if (!wasHold) onClick(e);
        };
        el.onpointercancel = el.onpointerleave = () => { active = false; fired = false; clear(); };
    }
    static trackDrag(e, { onMove, onEnd, minDist = 2 }) {
        const el = e.target, sX = e.clientX, sY = e.clientY;
        try { el.setPointerCapture(e.pointerId); } catch {}
        let moved = false;
        const move = ev => {
            const dx = ev.clientX - sX, dy = ev.clientY - sY;
            if (!moved && Math.hypot(dx, dy) > minDist) moved = true;
            if (moved) onMove(dx, dy, ev);
        };
        const end = ev => {
            try { el.releasePointerCapture(ev.pointerId); } catch {}
            window.removeEventListener('pointermove', move);
            window.removeEventListener('pointerup', end);
            window.removeEventListener('pointercancel', end);
            onEnd?.(moved, ev);
        };
        window.addEventListener('pointermove', move, { passive: false });
        window.addEventListener('pointerup', end);
        window.addEventListener('pointercancel', end);
    }
    static copy(text, ok, err) {
        text = String(text);
        const legacy = () => {
            try {
                const ta = document.createElement('textarea');
                ta.value = text;
                ta.setAttribute('readonly', '');
                ta.style.cssText = 'position:fixed;top:0;left:0;opacity:0;pointer-events:none';
                (document.body || document.documentElement).appendChild(ta);
                ta.select();
                ta.setSelectionRange(0, text.length);
                const done = document.execCommand('copy');
                ta.remove();
                return done;
            } catch { return false; }
        };
        const fail = e => { if (legacy()) ok?.(); else err?.(e); };
        try {
            if (navigator.clipboard?.writeText) navigator.clipboard.writeText(text).then(() => ok?.(), fail);
            else fail();
        } catch (e) { fail(e); }
    }
    static flashBtn(btn, ok) {
        const orig = btn.innerHTML;
        btn.innerHTML = ok ? icons.ok : '<span style="color:#e74c3c">ERR</span>';
        setTimeout(() => { if (btn.isConnected) btn.innerHTML = orig; }, 1000);
    }
}

const mk = (tag, className) => Helpers.createElement(tag, className);
const isPrimaryPress = e => e.button === 0 || e.pointerType !== 'mouse';
const swallow = e => { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); };
const bindEscape = close => {
    const onKey = e => { if (e.key === 'Escape') { e.preventDefault(); e.stopPropagation(); close(); } };
    document.addEventListener('keydown', onKey, true);
    return () => document.removeEventListener('keydown', onKey, true);
};
const onRemoteChange = (key, handler) => {
    if (typeof GM_addValueChangeListener !== 'function') return;
    try { GM_addValueChangeListener(key, (n, o, v, remote) => { if (remote) handler(v); }); } catch {}
};

const openGroupDialog = (ui, { current, groups, onPick }) => {
    const shadow = ui.shadow;
    if (!shadow._dlgCss) {
        shadow._dlgCss = true;
        const st = document.createElement('style');
        st.textContent = `
.bm-grp-btn{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;text-align:start;cursor:pointer;font-family:inherit}
.bm-grp-arr{opacity:.6;font-size:12px}
.dlg-ov{pointer-events:auto;position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;padding:16px;background:rgba(0,0,0,.55);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);animation:dlgIn .15s ease}
@keyframes dlgIn{from{opacity:0}to{opacity:1}}
.dlg-card{width:min(340px,100%);max-height:80%;display:flex;flex-direction:column;background:#1c1c20;border:1px solid rgba(255,255,255,.1);border-radius:16px;box-shadow:0 18px 50px rgba(0,0,0,.6);overflow:hidden;color:#eee;font-size:15px}
.dlg-list{overflow-y:auto;padding:6px}
.dlg-row{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;padding:13px 12px;border:0;border-radius:10px;background:transparent;color:#eee;font:inherit;text-align:start;cursor:pointer}
.dlg-row:active{background:rgba(255,255,255,.08)}
.dlg-row.on{background:rgba(255,255,255,.07)}
.dlg-dot{flex:none;width:18px;height:18px;border-radius:50%;border:2px solid rgba(255,255,255,.35)}
.dlg-row.on .dlg-dot{border-color:var(--th,#4aa3ff);background:radial-gradient(circle,var(--th,#4aa3ff) 0 45%,transparent 50%)}
.dlg-txt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dlg-new{display:flex;gap:8px;padding:10px;border-top:1px solid rgba(255,255,255,.08)}
.dlg-in{flex:1;min-width:0;height:40px;padding:0 12px;border-radius:10px;background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.12);color:#f0f0f0;-webkit-text-fill-color:#f0f0f0;font:inherit;outline:none}
.dlg-in:focus{border-color:var(--th,#4aa3ff)}
.dlg-ok{flex:none;height:40px;padding:0 14px;border:0;border-radius:10px;background:var(--th,#4aa3ff);color:#fff;font:inherit;font-weight:600;cursor:pointer}
`;
        shadow.appendChild(st);
    }
    const ov = mk('div', 'dlg-ov');
    const card = mk('div', 'dlg-card');
    const list = mk('div', 'dlg-list');
    const unbindEsc = bindEscape(() => close());
    const close = () => { ov.remove(); unbindEsc(); };
    const pick = v => { close(); if (v !== current) onPick(v); };

    const row = (label, value) => {
        const r = mk('button', 'dlg-row' + (value === current ? ' on' : ''));
        r.type = 'button';
        const t = mk('span', 'dlg-txt'); t.innerHTML = `${icons.folder}<span>${escHTML(label)}</span>`;
        r.append(t, mk('span', 'dlg-dot'));
        r.onclick = e => { e.stopPropagation(); pick(value); };
        return r;
    };
    list.append(row(L().grp_none, ''), ...groups.map(g => row(g, g)));

    const nw = mk('div', 'dlg-new');
    const inp = mk('input', 'dlg-in');
    inp.type = 'text'; inp.maxLength = 40; inp.placeholder = L().grp_new.replace(/^\+\s*/, '').replace(/…$/, '') + '…';
    inp.autocomplete = 'off'; inp.spellcheck = false;
    const ok = mk('button', 'dlg-ok'); ok.type = 'button'; ok.textContent = '+';
    const submit = () => { const v = inp.value.trim().slice(0, 40); if (v) pick(v); else inp.focus(); };
    ok.onclick = e => { e.stopPropagation(); submit(); };
    inp.onkeydown = e => { e.stopPropagation(); if (e.key === 'Enter') { e.preventDefault(); submit(); } };
    inp.onkeyup = e => e.stopPropagation();
    nw.append(inp, ok);

    card.append(list, nw);
    card.onclick = e => e.stopPropagation();
    ov.onclick = close;
    ov.append(card);
    shadow.appendChild(ov);
};

const openFrameView = (ui, b) => {
    const shadow = ui.shadow;
    if (!shadow._frCss) {
        shadow._frCss = true;
        const st = document.createElement('style');
        st.textContent = `.fr-ov{pointer-events:auto;position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;padding:16px;background:rgba(0,0,0,.8);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}.fr-card{max-width:100%;max-height:100%;display:flex;align-items:center;justify-content:center}.fr-img{max-width:100%;max-height:90vh;border-radius:14px;box-shadow:0 18px 50px rgba(0,0,0,.6);display:block}.fr-msg{color:#eee;font-size:15px;text-align:center;padding:18px 22px;border-radius:14px;background:#1c1c20;border:1px solid rgba(255,255,255,.1)}`;
        shadow.appendChild(st);
    }
    const ov = mk('div', 'fr-ov');
    const card = mk('div', 'fr-card');
    const msg = mk('div', 'fr-msg');
    msg.textContent = '…';
    let closed = false, timer = 0;
    const img = mk('img', 'fr-img');
    img.onload = () => { if (!closed && !img.isConnected) card.replaceChildren(img); };
    const unbindEsc = bindEscape(() => close());
    const close = () => { closed = true; clearTimeout(timer); ov.remove(); unbindEsc(); };
    ov.onclick = close;
    card.append(msg);
    ov.append(card);
    shadow.appendChild(ov);
    const fail = () => { if (!closed) { msg.textContent = L().fr_none; card.replaceChildren(msg); } };
    const loadFrame = url => new Promise(res => {
        const t = new Image();
        t.onload = () => res(url);
        t.onerror = async () => res(await gmImgData(url, true));
        t.src = url;
    });
    const live = (frame, onFirstFail) => {
        const base = frame.split('?')[0];
        const tick = async () => {
            if (closed) return;
            const url = `${base}?t=${Date.now()}`;
            const d = await loadFrame(url);
            if (closed) return;
            if (d) {
                img.src = d;
                if (d === url) b._lastImg = url;
            } else if (!img.isConnected) {
                return onFirstFail();
            }
            timer = setTimeout(tick, Store.get('bc_prev_spd', 1000));
        };
        tick();
    };
    const viaProfile = async () => {
        const h = await requestProfile(b);
        if (closed) return;
        const info = h ? parseProfile(h, urlSite(b.url), modelSlug(b.url)) : null;
        const fr = info && info.status ? info.frame : '';
        if (!fr) return fail();
        live(fr, fail);
    };
    if (b.frame && (b.status ?? 0) !== 0) {
        if (b._lastImg) img.src = b._lastImg;
        live(b.frame, viaProfile);
    } else viaProfile();
};

const copyHls = (u, cb) => u ? Helpers.copy(u, () => cb(true), () => cb(false)) : cb(false);
const shareHls = (u, title, cb) => (u && navigator.share) ? navigator.share({ title, url: u }).catch(() => {}) : cb(false);

const largestVideo = () => {
    let best = null, max = 0;
    for (const cur of document.querySelectorAll('video')) {
        const area = (cur.videoWidth * cur.videoHeight) || (cur.offsetWidth * cur.offsetHeight) || 0;
        if (area > max) { max = area; best = cur; }
    }
    return best;
};
const selectorVideo = () => currentSite.videoSelectors.map(s => document.querySelector(s)).find(el => el?.tagName === 'VIDEO');
const safeClosest = (el, sel) => { try { return el.closest(sel); } catch { return null; } };
const safeQuery = sel => { try { return document.querySelector(sel); } catch { return null; } };
const isQualityShown = q => q.style.display === 'block' || (!q.classList.contains('__hidden') && q.offsetWidth > 0);
const jq = () => window.unsafeWindow?.$ || window.$ || window.jQuery;
const fsActive = () => document.fullscreenElement || document.webkitFullscreenElement;
const fsRequest = el => (el.requestFullscreen || el.webkitRequestFullscreen)?.call(el);
const fsExit = () => (document.exitFullscreen || document.webkitExitFullscreen)?.call(document);
const containerOf = v => currentSite.containerSelectors.map(s => safeClosest(v, s)).find(Boolean) || v.parentElement;
const isTyping = e => {
    try { const t = e.composedPath()[0]; return !!(t?.matches?.('input, textarea') || t?.isContentEditable); } catch { return false; }
};
const volIcon = (vol, muted) => muted ? icons.mute : vol < 0.4 ? icons.volLow : vol < 0.75 ? icons.volMed : icons.vol;
const VOL_STEP = { ArrowUp: 0.1, ArrowDown: -0.1 };
const VJS_UI = '.vjs-control-bar,.vjs-control,.vjs-button,.vjs-menu,.vjs-menu-item,.vjs-menu-content,[role="menu"],[role="menuitem"],[role="button"],[role="slider"],button,a';

class VideoController {
    constructor(uiController) {
        this.ui = uiController;
        this.cachedVideo = null;
        this.lastVolume = 1;
        this.isTheater = false;
        this.theaterWrap = null;
        this._anc = null;
        this.bindEvents();
        this._findTimer = setInterval(() => { if (!document.hidden) this.findVideo(); }, 2000);
        onPageEvent('visibilitychange', () => { if (!realHidden()) this.findVideo(); });
    }

    bindEvents() {
        const actions = {
            KeyM: () => this.toggleMute(),
            KeyF: () => this.toggleFullscreen(),
            KeyP: () => this.cachedVideo && this.togglePiP(),
            KeyT: () => this.toggleTheater(),
            KeyS: () => this.takeScreenshot(),
            KeyH: () => this.ui.toggleHide(!AppState.isHidden)
        };
        const hasMod = e => e.ctrlKey || e.altKey || e.metaKey;
        window.addEventListener('keydown', e => {
            if (isTyping(e) || hasMod(e)) return;
            const act = actions[e.code];
            if (act) { e.preventDefault(); act(); return; }
            const step = VOL_STEP[e.code];
            if (e.shiftKey && step && this.cachedVideo) {
                e.preventDefault();
                this.setVolume(this.cachedVideo.volume + step);
            }
        });
    }

    findVideo() {
        if (this.cachedVideo?.isConnected) return;
        if (this.cachedVideo) {
            if (this.isTheater) this.toggleTheater();
            this.cachedVideo = this.theaterWrap = null;
        }
        const v = largestVideo() || selectorVideo() || null;
        if (v !== this.cachedVideo) {
            this.cachedVideo = v;
            if (v) this.attachInteractions(v);
        }
    }

    attachInteractions(v) {
        if (v._bcBound) return;
        v._bcBound = true;

        this._vcEvts = this._vcEvts || (e => {
            const cv = this.cachedVideo;
            if (e?.type === 'volumechange' && AppState.gmute && cv && (!cv.muted || cv.volume > 0)) {
                cv.muted = true; cv.volume = 0;
            }
            this.syncUI();
        });
        ['volumechange', 'pause', 'play'].forEach(ev => v.addEventListener(ev, this._vcEvts, { passive: true }));

        if (AppState.gmute) {
            v.muted = true;
            v.volume = 0;
        }

        v.style.setProperty('z-index', '9999', 'important');
        v.parentElement?.style.setProperty('z-index', '9999', 'important');
        const target = containerOf(v);
        if (target && !target._bcTouchBound) {
            target._bcTouchBound = true;
            this.bindWheel(target);
            this.bindDoubleClick(target);
        }
        this.syncUI();
    }

    bindWheel(target) {
        let pending = false;
        target.addEventListener('wheel', e => {
            if (safeClosest(e.target, '.vjs-control-bar, .vjs-menu, [role="slider"], [role="menu"]')) return;
            if (!this.isTheater && !document.fullscreenElement && !document.webkitFullscreenElement && !e.shiftKey) return;
            e.preventDefault();
            if (pending) return;
            pending = true;
            requestAnimationFrame(() => {
                pending = false;
                const cv = this.cachedVideo;
                if (cv) this.setVolume(cv.volume + (e.deltaY < 0 ? 0.05 : -0.05));
            });
        }, { passive: false });
    }

    bindDoubleClick(target) {
        let clicks = 0, timer = null, sX = 0, sY = 0;
        target.addEventListener('pointerdown', e => { sX = e.clientX; sY = e.clientY; }, { passive: true, capture: true });
        target.addEventListener('click', e => {
            if (safeClosest(e.target, VJS_UI)) return;
            if (Math.abs(e.clientX - sX) > 10 || Math.abs(e.clientY - sY) > 10) return;
            if (++clicks === 1) { timer = setTimeout(() => { clicks = 0; }, 250); return; }
            swallow(e);
            clearTimeout(timer);
            clicks = 0;
            this.toggleFullscreen();
        }, true);
    }

    setVolume(val) {
        const v = this.cachedVideo;
        if (!v) return;
        val = clamp(val, 0, 1);
        if (val > 0 && AppState.gmute) setGMute(false);
        v.volume = val;
        if (val > 0) {
            v.muted = false;
            this.lastVolume = val;
        }
        this.syncUI();
    }

    clickSiteUnmute() {
        try {
            const sb = document.querySelector('.stream_muted_button');
            if (sb && sb.offsetParent !== null) sb.click();
        } catch {}
    }

    toggleMute() {
        const v = this.cachedVideo;
        if (!v) return;
        const isMuted = v.muted || v.volume === 0;
        if (isMuted && AppState.gmute) setGMute(false);
        if (isMuted) this.clickSiteUnmute();
        v.muted = !isMuted;
        if (isMuted) v.volume = this.lastVolume || 1;
        else this.lastVolume = v.volume || 1;
        this.syncUI();
    }

    async togglePiP() {
        const v = this.cachedVideo;
        if (!v) return;
        try {
            if (document.pictureInPictureElement) await document.exitPictureInPicture();
            else if (document.pictureInPictureEnabled && v.requestPictureInPicture) {
                v.removeAttribute('disablePictureInPicture');
                await v.requestPictureInPicture();
            } else this.ui.flash(this.ui.elements.bPip, 'ERR');
            this.ui?.elements?.bPip?.classList.toggle('on', !!document.pictureInPictureElement);
        } catch { this.ui.flash(this.ui.elements.bPip, 'ERR'); }
    }

    toggleFullscreen() {
        const t = currentSite.containerSelectors.map(s => safeQuery(s)).find(Boolean) || this.cachedVideo;
        if (!t) return;
        try { fsActive() ? fsExit() : fsRequest(t); } catch {}
    }

    enterTheater(v) {
        this.theaterWrap = containerOf(v);
        this.theaterWrap?.classList.add('bc-thtr-wrap');
        v.classList.add('bc-thtr-video');
        this._anc = [];
        for (let e = v.parentElement; e && !isRootEl(e); e = e.parentElement) {
            e.classList.add('bc-thtr-anc');
            this._anc.push(e);
        }
        window.scrollTo(0, 0);
    }

    leaveTheater(v) {
        this.theaterWrap?.classList.remove('bc-thtr-wrap');
        v?.classList.remove('bc-thtr-video');
        this._anc?.forEach(e => e.classList.remove('bc-thtr-anc'));
        this._anc = null;
        this.theaterWrap = null;
    }

    toggleTheater() {
        const v = this.cachedVideo, on = !this.isTheater;
        if (on && !v) return;
        this.isTheater = on;
        this.ui?.elements?.bThtr?.classList.toggle('on', on);
        document.body.classList.toggle('bc-theater-mode', on);
        document.documentElement.classList.toggle('bc-theater-html', on);
        on ? this.enterTheater(v) : this.leaveTheater(v);
        window.dispatchEvent(new Event('resize'));
    }

    takeScreenshot() {
        const v = this.cachedVideo;
        if (!v) return;
        try {
            const c = document.createElement('canvas');
            c.width = v.videoWidth || 1280; c.height = v.videoHeight || 720;
            c.getContext('2d').drawImage(v, 0, 0);
            c.toBlob(b => {
                if (!b) return this.ui.flash(this.ui.elements.bShot, 'ERR');
                Helpers.download(b, `${currentSite.getName() || 'Cam'}_${Helpers.getTimestamp()}.jpg`);
                this.ui.flash(this.ui.elements.bShot, 'OK');
            }, 'image/jpeg', 0.95);
        } catch { this.ui.flash(this.ui.elements.bShot, 'ERR'); }
    }

    paintMuteBtn(btn, muted, gMute) {
        const sub = btn.querySelector('sub');
        if (sub) sub.textContent = gMute ? 'LOCK' : L().sound;
        btn.firstChild.innerHTML = muted ? icons.mute : icons.vol;
        btn.classList.toggle('on', muted);
        btn.style.boxShadow = gMute ? 'inset 0 0 0 2px #e74c3c' : '';
    }

    syncUI() {
        const v = this.cachedVideo, ui = this.ui, el = ui.elements;
        if (!v || !el.bMute) return;
        const vol = v.muted ? 0 : v.volume;
        const muted = v.muted || vol === 0;
        const gMute = AppState.gmute;
        const key = `${vol}|${muted}|${gMute}`;
        if (ui._volKey === key) return;
        ui._volKey = key;

        this.paintMuteBtn(el.bMute, muted, gMute);
        el.vSlider.value = String(vol);
        el.vSlider.style.setProperty('--p', `${Math.round(vol * 100)}%`);
        el.vIco.innerHTML = volIcon(vol, muted);
        el.vVal.textContent = `${Math.round(vol * 100)}%`;
    }
}

const WEBM_HEAD = 8192;
const vintReader = head => (p, raw) => {
    const f = head[p];
    if (!f) return null;
    const len = Math.clz32(f) - 23;
    if (len > 8 || p + len > head.length) return null;
    const mask = 0xFF >> len;
    let v = raw ? f : (f & mask), ones = (f & mask) === mask;
    for (let i = 1; i < len; i++) { v = v * 256 + head[p + i]; if (head[p + i] !== 0xFF) ones = false; }
    return { v, len, unknown: ones };
};
const webmSegmentStart = rd => {
    const ebml = rd(0, true);
    if (!ebml || ebml.v !== 0x1A45DFA3) return -1;
    const es = rd(ebml.len, false);
    if (!es) return -1;
    const p = ebml.len + es.len + es.v;
    const seg = rd(p, true);
    if (!seg || seg.v !== 0x18538067) return -1;
    const ss = rd(p + seg.len, false);
    return ss?.unknown ? p + seg.len + ss.len : -1;
};
const webmInfoScale = (rd, head, ds, de) => {
    let q = ds, scale = 1e6;
    while (q < de) {
        const cid = rd(q, true);
        const csz = cid && rd(q + cid.len, false);
        if (!csz || cid.v === 0x4489) return null;
        const cs = q + cid.len + csz.len;
        if (cid.v === 0x2AD7B1) { scale = 0; for (let i = 0; i < csz.v; i++) scale = scale * 256 + head[cs + i]; }
        q = cs + csz.v;
    }
    return scale;
};
const webmWithDuration = (blob, head, p, idLen, ds, de, durationMs, scale) => {
    const dur = new Uint8Array(11);
    dur.set([0x44, 0x89, 0x88]);
    new DataView(dur.buffer).setFloat64(3, durationMs * 1e6 / scale);
    const size8 = new Uint8Array(8);
    size8[0] = 0x01;
    new DataView(size8.buffer).setUint32(4, (de - ds) + dur.length);
    return new Blob([
        head.subarray(0, p), head.subarray(p, p + idLen), size8,
        head.subarray(ds, de), dur, head.subarray(de),
        blob.slice(WEBM_HEAD)
    ], { type: blob.type });
};
const webmElement = (rd, p) => {
    const id = rd(p, true);
    const sz = id && rd(p + id.len, false);
    if (!sz || sz.unknown) return null;
    const ds = p + id.len + sz.len;
    return { id, ds, de: ds + sz.v };
};
const fixWebmDuration = async (blob, durationMs) => {
    const head = new Uint8Array(await blob.slice(0, WEBM_HEAD).arrayBuffer());
    const rd = vintReader(head);
    let p = webmSegmentStart(rd);
    while (p >= 0 && p < head.length) {
        const el = webmElement(rd, p);
        if (!el) break;
        if (el.id.v === 0x1549A966) {
            const scale = el.de > head.length ? null : webmInfoScale(rd, head, el.ds, el.de);
            return scale === null ? blob : webmWithDuration(blob, head, p, el.id.len, el.ds, el.de, durationMs, scale);
        }
        p = el.de;
    }
    return blob;
};

const REC_MIME_TYPES = ['video/webm;codecs=vp9,opus', 'video/webm;codecs=vp8,opus', 'video/webm', 'video/mp4;codecs=avc1,mp4a.40.2', 'video/mp4'];

class MediaRecorderManager {
    constructor(videoController, uiController) {
        this.vc = videoController;
        this.ui = uiController;

        this.mRec = null;
        this.chunks = [];
        this.interval = null;
        this.seconds = 0;
        this.totalSize = 0;
        this.savedBytes = 0;
        this.cfg = recCfg();
        this.partNum = 1;
        this.partStart = 0;
        this.recStartTime = '';
        this.splitRequested = false;
        this.wakeLock = null;
        this.currentStream = null;
        this._onTrackEnded = () => this.stopActive();

        onPageEvent('visibilitychange', () => {
            if (!realHidden() && this.mRec && this.mRec.state === 'recording') this.acquireWakeLock();
        });
        window.addEventListener('beforeunload', e => {
            if (this.mRec && this.mRec.state === 'recording') {
                e.preventDefault();
                e.returnValue = '';
            }
        });
    }

    getStream(v) {
        return v.captureStream?.(30) ?? v.mozCaptureStream?.(30) ?? null;
    }

    acquireWakeLock() {
        if (!('wakeLock' in navigator) || this.wakeLock || this._wlPending) return;
        this._wlPending = true;
        navigator.wakeLock.request('screen').then(wl => {
            this._wlPending = false;
            if (!(this.mRec && this.mRec.state !== 'inactive')) { wl.release().catch(() => {}); return; }
            this.wakeLock = wl;
            wl.addEventListener('release', () => { if (this.wakeLock === wl) this.wakeLock = null; });
        }).catch(() => { this._wlPending = false; });
    }

    stopActive() {
        if (this.mRec && this.mRec.state !== 'inactive') {
            this.splitRequested = false;
            try { this.mRec.stop(); } catch {}
        }
    }

    cleanupSession(btn, sub) {
        clearInterval(this.interval);
        btn.classList.remove('on', 'rec-active');
        if (sub) sub.textContent = L().rec;
        if (this.wakeLock) { this.wakeLock.release().catch(() => {}); this.wakeLock = null; }
        try { this.currentStream?.getTracks().forEach(t => t.stop()); } catch {}
    }

    async saveBlob(blob, ext, durationMs, name) {
        try { if (ext === 'webm') blob = await fixWebmDuration(blob, durationMs); } catch {}
        Helpers.download(blob, name);
    }

    updateInfo() {
        const el = this._rs?.info;
        if (!el || !el.isConnected) return;
        const l = L(), on = this.mRec && this.mRec.state !== 'inactive';
        el.textContent = on ? `${l.rs_now}: ${l.rs_p} ${fmtBytes(this.totalSize)} · ${l.rs_t} ${fmtBytes(this.savedBytes + this.totalSize)}` : '';
    }

    openSettings() {
        if (!this._rs) {
            const overlay = mk('div', 'bm-overlay');
            const modal = mk('div', 'bm-modal rs-modal');
            const hdr = mk('div', 'bm-hdr');
            const title = mk('span', 'bm-title');
            const closeBtn = mk('button', 'bm-close');
            closeBtn.innerHTML = '×';
            hdr.append(title, closeBtn);
            const body = mk('div', 'bm-list');
            modal.append(hdr, body);
            overlay.appendChild(modal);
            this.ui.shadow.appendChild(overlay);
            const close = () => { overlay.classList.remove('open'); clearInterval(this._rsTimer); overlay._fromSt = false; overlay._bk?.(); };
            closeBtn.onclick = close;
            overlay.onclick = e => { if (e.target === overlay && Date.now() - (this._rsAt || 0) > 400) close(); };
            this._rs = { overlay, title, body, close, info: null };
        }
        const { overlay, title, body } = this._rs;
        const render = () => {
            const l = L(), cfg = this.cfg = recCfg();
            title.innerHTML = `${icons.rec} ${escHTML(l.rs_title)}`;
            const set = patch => { Store.set('bc_rec', { ...recCfg(), ...patch }); render(); };
            const chip = (txt, on, fn) => { const b = mk('button', `bm-tbtn${on ? ' on' : ''}`); b.textContent = txt; b.onclick = fn; return b; };
            const size = v => v >= 1024 ? `${v / 1024} ${l.u_gb}` : `${v} ${l.u_mb}`;

            const qs = mk('div', 'rs-qs');
            Object.keys(REC_Q).forEach(q => {
                const mb = (REC_Q[q][0] + REC_Q[q][1]) / 8 * 60 / 1048576;
                const b = mk('button', `bm-btn${cfg.q === q ? ' sel' : ''}`);
                b.textContent = `${REC_RES[q]} · ${l['rs_q_' + q]} · ${l.rs_upto} ${Math.round(mb)} ${l.rs_mbmin} (${(mb * 60 / 1024).toFixed(1)} ${l.rs_gbh})`;
                b.onclick = () => set({ q });
                qs.append(b);
            });
            const parts = mk('div', 'rs-chips');
            REC_PART.forEach(v => parts.append(chip(size(v), cfg.part === v, () => set({ part: v }))));
            const totals = mk('div', 'rs-chips');
            REC_TOTAL.forEach(v => totals.append(chip(v ? size(v) : l.rs_off, cfg.total === v, () => set({ total: v }))));
            const info = mk('div', 'rs-info');
            this._rs.info = info;
            const vid = (typeof largestVideo === 'function' && largestVideo()) || null;
            const res = vid && vid.videoHeight ? `${vid.videoWidth}×${vid.videoHeight}` : '—';
            const resEl = textEl('rs-note', `${l.rs_cur} ${res}`);
            const resNote = textEl('rs-note', l.rs_resnote);
            body.replaceChildren(
                textEl('hd-sec', l.rs_quality), qs,
                textEl('hd-sec', l.rs_part), parts,
                textEl('hd-sec', l.rs_total), totals,
                info,
                resEl, resNote,
                textEl('rs-note', l.rs_hint),
                textEl('rs-note', l.rs_next)
            );
            this.updateInfo();
        };
        render();
        this._rsAt = Date.now();
        overlay.classList.add('open');
        clearInterval(this._rsTimer);
        this._rsTimer = setInterval(() => {
            if (!overlay.classList.contains('open')) return clearInterval(this._rsTimer);
            this.updateInfo();
        }, 1000);
    }

    toggle() {
        const v = this.vc.cachedVideo;
        const btn = this.ui.elements.bRec;
        const sub = btn.querySelector('sub');
        if (!v) return this.ui.flash(btn, `! ${L().no_vid}`);
        if (this.mRec && this.mRec.state !== 'inactive') return this.stop(btn, sub);
        try { this.start(v, btn, sub); } catch { this.ui.flash(btn, `! ${L().err}`); }
    }

    stop(btn, sub) {
        this.splitRequested = false;
        try { this.mRec.stop(); } catch { this.currentStream?.getTracks().forEach(t => t.stop()); }
        this.cleanupSession(btn, sub);
    }

    start(v, btn, sub) {
        const s = this.getStream(v);
        if (!s) throw new Error('no stream');
        this.currentStream = s;
        if (!s.getAudioTracks().length) this.ui.flash(btn, '! AUD');

        const mt = REC_MIME_TYPES.find(t => MediaRecorder.isTypeSupported(t)) || 'video/webm';
        this.recStartTime = Helpers.getTimestamp();
        this.partNum = 1;
        this.seconds = 0;
        this.savedBytes = 0;
        this.cfg = recCfg();
        this.startNewRecord(s, mt, mt.includes('mp4') ? 'mp4' : 'webm', btn, sub);
        btn.classList.add('on', 'rec-active');
        const label = () => `${Helpers.formatTime(this.seconds)} | ${fmtShort(this.savedBytes + this.totalSize)}`;
        if (sub) sub.textContent = label();
        clearInterval(this.interval);
        const t0 = Date.now();
        this.interval = setInterval(() => {
            this.seconds = Math.floor((Date.now() - t0) / 1000);
            if (sub) sub.textContent = label();
        }, 1000);
    }

    startNewRecord(stream, mimeType, ext, btn, sub) {
        this.chunks = [];
        this.totalSize = 0;
        this.mRec = null;
        const [vBps, aBps] = REC_Q[this.cfg.q] || REC_Q.hi;
        for (const opts of [{ mimeType, videoBitsPerSecond: vBps, audioBitsPerSecond: aBps }, { mimeType }, undefined]) {
            try { this.mRec = new MediaRecorder(stream, opts); break; } catch {}
        }
        if (!this.mRec) throw new Error('MediaRecorder init failed');

        stream.getTracks().forEach(t => t.addEventListener('ended', this._onTrackEnded));

        const stopRec = () => { try { this.mRec.stop(); } catch {} };
        const savePart = (chunks, dur) => {
            const suffix = (this.partNum > 1 || this.splitRequested) ? `_PT${this.partNum}` : '';
            const name = `${currentSite.getName() || 'REC'}_${this.recStartTime}${suffix}.${ext}`;
            this.saveBlob(new Blob(chunks, { type: mimeType.split(';')[0] }), ext, dur, name);
        };
        const continueSplit = () => {
            this.partNum++;
            this.splitRequested = false;
            const v = this.vc.cachedVideo;
            const nextStream = (!stream.active && v ? this.getStream(v) : null) || stream;
            this.currentStream = nextStream;
            try { this.startNewRecord(nextStream, mimeType, ext, btn, sub); return true; } catch { return false; }
        };

        this.mRec.ondataavailable = e => {
            if (!(e.data?.size > 0)) return;
            this.chunks.push(e.data);
            this.totalSize += e.data.size;
            const limTotal = this.cfg.total * 1048576;
            if (limTotal && this.savedBytes + this.totalSize >= limTotal) { this.splitRequested = false; return stopRec(); }
            if (this.totalSize >= this.cfg.part * 1048576 && !this.splitRequested) { this.splitRequested = true; stopRec(); }
        };
        this.mRec.onerror = () => this.stopActive();
        this.mRec.onstop = () => {
            const chunks = this.chunks;
            this.chunks = [];
            const dur = performance.now() - this.partStart;
            if (chunks.length > 0) savePart(chunks, dur);
            this.savedBytes += this.totalSize;
            if (this.splitRequested && continueSplit()) return;
            this.cleanupSession(btn, sub);
        };

        try {
            this.partStart = performance.now();
            this.mRec.start(1000);
            this.acquireWakeLock();
        } catch {
            this.ui.flash(btn, `! ${L().err}`);
        }
    }
}

const STATUS_RULES = [
    [/"is(?:Full)?PrivateChat"\s*:\s*true/i, 3, 'st_private'],
    [/"isGroupChat"\s*:\s*true/i, 3, 'st_group'],
    [/"isVipShow"\s*:\s*true/i, 3, 'st_vip'],
    [/"isAway"\s*:\s*true/i, 2, 'st_away'],
    [/"showType"\s*:\s*"(?:private|full_?private|voyeur)"/i, 3, 'st_private'],
    [/"showType"\s*:\s*"group"/i, 3, 'st_group'],
    [/"showType"\s*:\s*"vip"/i, 3, 'st_vip'],
    [/__page_profile|"isOnline"\s*:\s*false|"online"\s*:\s*false|"isOffline"\s*:\s*true|"room_status"\s*:\s*["']offline["']|"isChatShowPaused"\s*:\s*true/i, 0],
    [/"isOnline"\s*:\s*true|"online"\s*:\s*true|"showType"\s*:\s*"public"|"isOffline"\s*:\s*false|"room_status"\s*:\s*["'](?:public|free|chat|group|private)["']/i, 1]
];
const STATUS_RULES_SITE = {
    sc: [
        [/"status"\s*:\s*"(?:private|p2p|p2pVoice|virtualPrivate|spy)"/i, 3, 'st_private'],
        [/"isInPrivate"\s*:\s*true|"isInP2p"\s*:\s*true/i, 3, 'st_private'],
        [/"status"\s*:\s*"(?:group|groupShow|ticketShow)"|"isInGroupShow"\s*:\s*true/i, 3, 'st_group'],
        [/"status"\s*:\s*"public"|"isLive"\s*:\s*true|"isBroadcasting"\s*:\s*true/i, 1],
        [/"status"\s*:\s*"(?:off|offline|idle)"|"isLive"\s*:\s*false|"isOnline"\s*:\s*false/i, 0]
    ],
    cb: [
        [/(?:"|\\u0022)room_status(?:"|\\u0022)\s*:\s*(?:"|\\u0022)(?:private|hidden|password protected)/i, 3, 'st_private'],
        [/(?:"|\\u0022)room_status(?:"|\\u0022)\s*:\s*(?:"|\\u0022)group/i, 3, 'st_group'],
        [/(?:"|\\u0022)room_status(?:"|\\u0022)\s*:\s*(?:"|\\u0022)away/i, 2, 'st_away'],
        [/(?:"|\\u0022)room_status(?:"|\\u0022)\s*:\s*(?:"|\\u0022)public/i, 1],
        [/(?:"|\\u0022)room_status(?:"|\\u0022)\s*:\s*(?:"|\\u0022)offline/i, 0]
    ]
};
const SC_JSON_STATUS = [
    [/^(?:private|p2p|p2pVoice|virtualPrivate|spy)$/i, 3, 'st_private'],
    [/^(?:group|groupShow|ticketShow)$/i, 3, 'st_group']
];
const scJsonUser = h => {
    try {
        const u = JSON.parse(h)?.user?.user;
        return u && typeof u.status === 'string' ? u : null;
    } catch { return null; }
};
const scJsonStatus = h => {
    if (!h || h.charCodeAt(0) !== 123) return null;
    const u = scJsonUser(h);
    if (!u) return null;
    const hit = SC_JSON_STATUS.find(([re]) => re.test(u.status));
    if (hit) return [hit[1], hit[2]];
    return /^public$/i.test(u.status) && u.isLive !== false ? [1, ''] : [0, ''];
};
const parseStatus = (h, site) => {
    if (site === 'sc') { const j = scJsonStatus(h); if (j) return j; }
    const rule = h && (STATUS_RULES_SITE[site] || STATUS_RULES).find(([re]) => re.test(h));
    if (!rule) return [0, ''];
    const [, st, lk] = rule;
    return [st, lk || ''];
};

const decodeJson = s => { try { return JSON.parse(`"${s}"`); } catch { return s; } };
const jsonField = (h, re) => { const m = h.match(re); return m?.[1] ? decodeJson(m[1]) : ''; };
const TOPIC_RE = /"currentTopic"\s*:\s*"((?:[^"\\]|\\.)*)"/i;
const FRAME_RE = /"frame"\s*:\s*"((?:[^"\\]|\\.)*)"/i;
const htmlDec = x => { try { return new DOMParser().parseFromString(x, 'text/html').documentElement.textContent || ''; } catch { return x; } };
const metaContent = (h, prop) => {
    const m = h.match(new RegExp(`(?:property|name)=["']${prop}["'][^>]*?content=["']([^"']*)["']`, 'i')) || h.match(new RegExp(`content=["']([^"']*)["'][^>]*?(?:property|name)=["']${prop}["']`, 'i'));
    return m ? htmlDec(m[1]) : '';
};
const intField = (h, re) => { const m = h.match(re); return m ? +m[1] : null; };
const siteProfile = {
    cb: (h, status, slug) => {
        if (!status) return { topic: '', frame: '' };
        const v = intField(h, /(?:"|\\u0022)num_users(?:"|\\u0022)\s*:\s*(\d+)/i) ?? intField(h, /(?:"|\\u0022)num_viewers(?:"|\\u0022)\s*:\s*(\d+)/i);
        return {
            topic: (jsonField(h, /"room_title"\s*:\s*"((?:[^"\\]|\\.)*)"/i) || metaContent(h, 'og:description')).trim(),
            frame: slug ? `https://thumb.live.mmcdn.com/ri/${encodeURIComponent(slug.toLowerCase())}.jpg` : '',
            ...(v != null ? { viewers: v } : {})
        };
    },
    sc: (h, status) => {
        if (!status) return { topic: '', frame: '' };
        const v = intField(h, /"(?:viewersCount|usersCount|viewers)"\s*:\s*(\d+)/i);
        const fr = jsonField(h, /"(?:previewUrlThumbBig|previewUrlThumbSmall|previewUrl)"\s*:\s*"((?:[^"\\]|\\.)*)"/i).replace(/^\/\//, 'https://');
        return {
            topic: (jsonField(h, /"(?:topic|goalMessage)"\s*:\s*"((?:[^"\\]|\\.)*)"/i) || metaContent(h, 'og:description')).trim(),
            frame: fr.startsWith('https://') ? fr : '',
            ...(v != null ? { viewers: v } : {})
        };
    }
};
const stripTags = s => String(s).replace(/<[^>]+>/g, ' ').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\s+/g, ' ').trim();
const ptIcoUrl = p => (isStr(p) && /^[a-z0-9_\/-]{1,60}$/i.test(p) ? `https://i.bgicdn.com/images/tags/${p}/18/2x/img.png` : '');
const ptIcoMap = () => {
    const m = new Map();
    for (const b of AppState.bookmarks) {
        if (!isObj(b) || !Array.isArray(b.ptags) || !Array.isArray(b.ptic)) continue;
        b.ptags.forEach((x, i) => { const u = ptIcoUrl(b.ptic[i]), k = String(x).toLowerCase(); if (u && !m.has(k)) m.set(k, u); });
    }
    return m;
};
const ptImg = (u, cls) => (u ? `<img class="${cls}" src="${escHTML(u)}" alt="" decoding="sync" referrerpolicy="no-referrer">` : '');
const pilgSection = (h, cls) => {
    const i = h.indexOf(cls);
    if (i < 0) return '';
    const j = h.indexOf('pilg_section', i + cls.length);
    return h.slice(i, j < 0 ? i + 12000 : j);
};
const parsePilgTags = ts => {
    const tags = [], icos = [];
    const add = raw => {
        const x = stripTags(raw);
        if (x && x.length <= 40 && tags.length < 30 && !tags.includes(x)) {
            tags.push(x);
            const im = String(raw).match(/images\/tags\/([a-z0-9_\/-]{1,60}?)\/\d+\/(?:\d+x\/)?img\./i);
            icos.push(im ? im[1] : '');
        }
    };
    for (const m of ts.matchAll(/<a\b[^>]*\/tags\/[^"'\/?#>\s]+[^>]*>([\s\S]*?)<\/a>/gi)) add(m[1]);
    if (!tags.length) for (const m of ts.matchAll(/class=["']stl_item["'][^>]*>([\s\S]*?)<\/div>/gi)) add(m[1]);
    return tags.length ? { ptags: tags, ptic: icos.some(Boolean) ? icos : [] } : null;
};
const parsePilgRow = row => {
    const rng = [];
    for (const x of row.matchAll(/pilgs_badge[^>]*>([^<]*)</g)) {
        const m = x[1].match(/(\d{1,2}):(\d{2})\s*[-\u2013\u2014]\s*(\d{1,2}):(\d{2})/);
        if (m && !(+m[1] === +m[3] && m[2] === m[4])) rng.push(`${m[1].padStart(2, '0')}:${m[2]}-${m[3].padStart(2, '0')}:${m[4]}`);
    }
    return rng.join(',');
};
const parsePilgSchedule = ss => {
    let hi = -1;
    const days = ss.split('pilg_shelf').slice(1).map((row, i) => {
        if (hi < 0 && row.indexOf('__highlight') >= 0) hi = i;
        return parsePilgRow(row);
    });
    if (days.length !== 7) return null;
    const sh = hi < 0 ? 0 : (((new Date().getDay() + 6) % 7) - hi + 7) % 7;
    return days.map((_, i) => days[(i - sh + 7) % 7]);
};
const bcProfileUrl = b => {
    const slug = modelSlug(b.url);
    if (urlSite(b.url) !== 'bc' || !slug) return '';
    try { return `${new URL(b.url).origin}/profile/${encodeURIComponent(slug)}/`; } catch { return ''; }
};
const parseBcExtra = h => {
    const out = {};
    if (!h || h.indexOf('pilg_section') < 0) return out;
    const ts = pilgSection(h, 'pilg_section __tags');
    const tg = ts && parsePilgTags(ts);
    if (tg) Object.assign(out, tg);
    const ss = pilgSection(h, 'pilg_section __schedule');
    const sch = ss && parsePilgSchedule(ss);
    if (sch) out.sch = sch;
    return out;
};
const bcViewers = h => {
    const m = h && h.match(/class=["'][^"']*\boc_count\b[^"']*["'][^>]*>\s*(\d[\d\s,.\u00a0]*)\s*</i);
    const n = m ? parseInt(m[1].replace(/\D/g, ''), 10) : NaN;
    return Number.isFinite(n) && n < 10000000 ? n : null;
};
const parseProfile = (h, site = 'bc', slug = '') => {
    const [status, lk] = parseStatus(h, site);
    if (siteProfile[site]) return { status, lk, ...siteProfile[site](h, status, slug) };
    const frame = jsonField(h, FRAME_RE).replace(/^\/\//, 'https://');
    const vn = bcViewers(h);
    return {
        status, lk,
        topic: status ? jsonField(h, TOPIC_RE).trim() : '',
        frame: frame.startsWith('https://') ? frame : '',
        ...(vn != null ? { viewers: vn } : {}),
        ...(site === 'bc' ? parseBcExtra(h) : {})
    };
};

const withBackoff = async (fn, { tries = 2, base = 500, signal } = {}) => {
    for (let i = 0; ; i++) {
        const res = await fn();
        if (res !== null || i >= tries - 1 || signal?.aborted) return res;
        await new Promise(r => setTimeout(r, base * 2 ** i * (0.75 + Math.random() * 0.5)));
    }
};
const MOBILE_UA = 'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36';
const requestOnce = (url, extra, signal) => new Promise(resolve => {
    if (signal?.aborted) return resolve(null);
    let headers = {};
    if (/\/api\//.test(url)) {
        headers = { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json, text/plain, */*' };
        try { headers.Referer = `${new URL(url).origin}/`; } catch {}
    }
    if (extra) headers = { ...headers, ...extra };
    if (typeof GM_xmlhttpRequest === 'function') {
        const req = GM_xmlhttpRequest({
            method: 'GET',
            url,
            headers,
            timeout: 6000,
            onload: res => resolve(res.status >= 500 ? null : (res.responseText || '')),
            onerror: () => resolve(null),
            ontimeout: () => resolve(null)
        });
        signal?.addEventListener('abort', () => { try { req?.abort?.(); } catch {} resolve(null); }, { once: true });
    } else {
        const ctrl = new AbortController();
        const to = setTimeout(() => ctrl.abort(), 6000);
        signal?.addEventListener('abort', () => ctrl.abort(), { once: true });
        fetch(url, { cache: 'no-store', signal: ctrl.signal, headers })
            .then(r => (r.status >= 500 ? null : r.text()))
            .then(resolve)
            .catch(() => resolve(null))
            .finally(() => clearTimeout(to));
    }
});
const requestHtml = async (url, signal) => (await withBackoff(() => requestOnce(url, undefined, signal), { signal })) ?? '';
const STATUS_KEY = /room_status|"status"\s*:|"isLive"|"isOnline"/i;
const profileUrls = b => {
    const slug = modelSlug(b.url), site = urlSite(b.url);
    if (!slug) return [b.url];
    try {
        if (site === 'cb') return [`https://chaturbate.com/api/chatvideocontext/${encodeURIComponent(slug)}/`, b.url];
        if (site === 'sc') {
            const o = new URL(b.url).origin, e = encodeURIComponent(slug);
            return [...new Set([`${o}/api/front/v2/models/username/${e}/cam`, `https://stripchat.com/api/front/v2/models/username/${e}/cam`])].concat(b.url);
        }
    } catch {}
    return [b.url];
};
const requestProfile = async (b, signal) => {
    for (const u of profileUrls(b)) {
        const h = await requestHtml(u, signal);
        if (h && (u === b.url || STATUS_KEY.test(h))) return h;
    }
    return '';
};

const applyProfile = (b, { frame, ...info }) => {
    const same = (x, y) => (Array.isArray(x) || Array.isArray(y)) ? JSON.stringify(x) === JSON.stringify(y) : x === y;
    const changed = Object.keys(info).some(k => !same(b[k], info[k])) || !!(frame && b.frame !== frame);
    if (info.viewers != null) b.vts = Date.now();
    Object.assign(b, info);
    if (frame) b.frame = frame;
    return changed;
};
const AVATAR_RES = [
    /(?:property=["']og:image["']|name=["']og:image["'])[^>]*?content=["']([^"']+)["']/i,
    /content=["']([^"']+)["'][^>]*?property=["']og:image["']/i,
    /"(?:profileImage|avatarUrl)"\s*:\s*"([^"]+)"/i
];
const extractAvatar = html => {
    for (const re of AVATAR_RES) {
        const m = html.match(re);
        if (m?.[1]) return toHttps(m[1].replace(/\\/g, ''));
    }
    return '';
};
const ogImage = () => toHttps(document.querySelector('meta[property="og:image"]')?.content);
const bcAvatar = name => {
    const sd = Helpers.getModelSecretData();
    const own = (sd?.chatHost?.username || '').toLowerCase() === name.toLowerCase();
    return toHttps(own ? sd?.chatHeaderOptions?.profileImage : '')
        || toHttps(document.querySelector('.chat-info-avatar img, .chat-header-avatar img, .profile-photo img')?.src);
};
const scAvatar = () => toHttps(document.querySelector('img.image-background--round[src*="avatars"]')?.src) || ogImage();
const cbAvatar = name => name ? `https://thumb.live.mmcdn.com/ri/${encodeURIComponent(name.toLowerCase())}.jpg` : ogImage();
const AVATAR_BY_SITE = new Map([['bc', bcAvatar], ['cb', cbAvatar]]);
const pageAvatar = name => (AVATAR_BY_SITE.get(SITE) || scAvatar)(name);

const GM_IMG = new Map();
const gmImgData = (url, fresh) => {
    if (!url || /^data:/.test(url) || typeof GM_xmlhttpRequest !== 'function') return Promise.resolve('');
    if (!fresh && GM_IMG.has(url)) return GM_IMG.get(url);
    const p = new Promise(resolve => {
        try {
            GM_xmlhttpRequest({
                method: 'GET', url, responseType: 'blob', timeout: 12000,
                onload: r => {
                    if (r.status < 200 || r.status >= 300 || !r.response) return resolve('');
                    const fr = new FileReader();
                    fr.onload = () => resolve(typeof fr.result === 'string' ? fr.result : '');
                    fr.onerror = () => resolve('');
                    fr.readAsDataURL(r.response);
                },
                onerror: () => resolve(''), ontimeout: () => resolve('')
            });
        } catch { resolve(''); }
    });
    if (fresh) return p;
    GM_IMG.set(url, p);
    if (GM_IMG.size > 80) GM_IMG.delete(GM_IMG.keys().next().value);
    p.then(d => { if (!d) GM_IMG.delete(url); });
    return p;
};
const tryGm = (img, u, fail) => {
    if (!u || /^data:/.test(u) || img._gm === u || typeof GM_xmlhttpRequest !== 'function') return false;
    img._gm = u;
    gmImgData(u).then(d => { if (d && img.isConnected !== false && (!img.classList.contains('bm-prev') || img.hasAttribute('data-frame'))) img.src = d; else if (fail) fail(); });
    return true;
};

const frameFail = img => {
    const b = img._bRef;
    const giveUp = () => {
        img._gen = (img._gen || 0) + 1;
        img._isUpdating = false;
        img.removeAttribute('data-frame');
        img.style.display = 'none';
    };
    if (!b || !img.isConnected) return giveUp();
    if (img._rec && Date.now() - img._rec < 60000) return giveUp();
    img._rec = Date.now();
    requestProfile(b).then(h => {
        const info = h ? parseProfile(h, urlSite(b.url), modelSlug(b.url)) : null;
        const fr = info && info.status ? info.frame : '';
        if (!fr || !img.isConnected) return giveUp();
        b.frame = fr;
        const next = `${fr.split('?')[0]}?t=${Date.now()}`;
        const tmp = new Image();
        tmp.onload = () => {
            if (!img.isConnected) return;
            img.setAttribute('data-frame', fr);
            img._u = next; b._lastImg = next; img._gm = null;
            img.src = next; img.style.display = 'block';
        };
        tmp.onerror = () => gmImgData(next, true).then(d => {
            if (d && img.isConnected) { img.setAttribute('data-frame', fr); img._u = next; b._lastImg = next; img.src = d; img.style.display = 'block'; }
            else giveUp();
        });
        tmp.src = next;
    }).catch(giveUp);
};

const refreshFrame = img => {
    const url = img?.getAttribute('data-frame');
    if (!url || img._isUpdating) return;
    img._isUpdating = true;
    const gen = img._gen = (img._gen || 0) + 1;
    const next = `${url.split('?')[0]}?t=${Date.now()}`;
    const tmp = new Image();
    const alive = () => img.isConnected && img._gen === gen && img.getAttribute('data-frame') === url;
    const done = () => { if (img._gen === gen) img._isUpdating = false; };
    const guard = setTimeout(() => { tmp.onload = tmp.onerror = null; done(); }, 20000);
    tmp.onload = () => {
        clearTimeout(guard);
        if (alive()) { img._u = next; img.src = next; img.style.display = 'block'; if (img._bRef) img._bRef._lastImg = next; }
        done();
    };
    tmp.onerror = () => {
        clearTimeout(guard);
        gmImgData(next, true).then(d => {
            if (d && alive()) { img._u = next; img.src = d; img.style.display = 'block'; if (img._bRef) img._bRef._lastImg = next; }
            else if (alive() && !(img.complete && img.naturalWidth > 0)) frameFail(img);
            done();
        });
    };
    tmp.src = next;
};


const initialsAva = name => {
    const s = String(name || '?'), t = (s.replace(/[^\p{L}\p{N}]/gu, '').slice(0, 2) || '?').toUpperCase();
    let h = 0; for (const ch of s) h = (h * 31 + ch.charCodeAt(0)) >>> 0;
    const svg = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${h % 360},50%,42%)'/><text x='32' y='41' font-size='26' font-weight='700' text-anchor='middle' fill='#fff' font-family='sans-serif'>${t}</text></svg>`;
    return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
};
const bindAvatar = (img, name, getList, onFail) => {
    let i = 0, list = null;
    const next = () => {
        list ||= [...new Set(getList().filter(Boolean))];
        while (i < list.length) {
            const u = list[i++];
            if (u) { img._cur = u; img.src = u; return; }
        }
        img.onerror = null;
        img._fb = 1;
        img.src = initialsAva(name);
        onFail?.();
    };
    img._fb = 0;
    img.onerror = () => { if (img._fb === 0 && tryGm(img, img._cur, next)) return; next(); };
    next();
};

const STATUS_COLORS = { 0: '#e74c3c', 1: '#2ecc71', 2: '#f39c12', 3: '#9b59b6' };
const bmLive = b => +((b.status ?? 0) > 0);
const bmGroups = () => [...new Set(AppState.bookmarks.map(b => b.g).filter(Boolean))].sort((a, b) => a.localeCompare(b));
const bmLabel = (b, l) => b.name + (b.lk && l[b.lk] ? ` (${l[b.lk]})` : '');
const bmSeen = (b, st) => st === 0 && b.seen ? fmtAgo(b.seen) : '';
const bmViews = b => (b.status > 0 && b.vts && Date.now() - b.vts < 7200000) ? (b.viewers || 0) : 0;
const WMARKS = [[0, 'eyeNo', 'w_new'], [1, 'eyeOk', 'w_seen']];
const bmWatch = (b, hist) => (((hist || histLoad()).m[bmKey(b.url)]?.s || 0) >= 30 ? 1 : 0);
const BM_CMP = {
    date: (x, y) => x.i - y.i,
    name: (x, y) => x.b.name.localeCompare(y.b.name),
    online: (x, y) => (bmLive(y.b) - bmLive(x.b)) || (x.i - y.i),
    last: (x, y) => (bmLive(y.b) - bmLive(x.b)) || ((y.b.seen || 0) - (x.b.seen || 0)) || (x.i - y.i),
    viewers: (x, y) => (bmLive(y.b) - bmLive(x.b)) || (bmViews(y.b) - bmViews(x.b)) || (x.i - y.i)
};

const ST_FILTERS = [
    ['hidePrivate', 'bc_bm_hide_priv', 'st_private', 'bm_priv'],
    ['hideGroup', 'bc_bm_hide_group', 'st_group', 'st_group'],
    ['hideVip', 'bc_bm_hide_vip', 'st_vip', 'st_vip'],
    ['hideAway', 'bc_bm_hide_away', 'st_away', 'st_away']
];
const bmStatusKey = b => {
    const st = b.status ?? 0;
    return b.lk || (st === 3 ? 'st_private' : st === 2 ? 'st_away' : '');
};

class BookmarkManager {
    constructor(uiController) {
        this.ui = uiController;
        this.overlay = null;
        this.list = null;
        if (!Store.get('bc_mig_stf1', false)) {
            if (Store.get('bc_bm_hide_priv', false)) { Store.set('bc_bm_hide_group', true); Store.set('bc_bm_hide_vip', true); }
            Store.set('bc_mig_stf1', true);
        }
        ST_FILTERS.forEach(([prop, key]) => { this[prop] = Store.get(key, false); });
        this.hideOffline = Store.get('bc_bm_hide_off', false);
        { const wf = Store.get('bc_bm_wf', -1); this.wFilter = [0, 1].includes(wf) ? wf : null; }
        this._els = new WeakMap();
        this._lang = AppState.lang;
        this.build();
        this._xTimer = setInterval(() => { this.bgExtra(); }, 8000);
        this._statusTimer = setInterval(() => {
            if (!document.hidden && this.isOpen()) this.checkStatuses();
        }, 60000);
        onPageEvent('visibilitychange', () => {
            if (!realHidden() && this.isOpen()) this.checkStatuses();
        });
    }

    applyRemote(json) {
        try {
            const arr = JSON.parse(json);
            if (!Array.isArray(arr)) return;
            const editing = this.ui.shadow.activeElement?.matches?.('textarea');
            if (!mergeRemoteBookmarks(arr, editing ? ['note'] : [])) return;
            if (this.isOpen() && !editing) this.render();
        } catch {}
    }

    async checkStatuses() {
        if (!AppState.bookmarks?.length) return;
        this._abortCtrl?.abort();
        this._abortCtrl = new AbortController();
        const { signal } = this._abortCtrl;
        const sortType = Store.get('bc_bm_sort_type', 'date');
        const now = Date.now();
        const queue = AppState.bookmarks.filter(b => isSafeUrl(b.url) && (!b._chk || now - b._chk > 55000));
        let changedAny = false;

        const mark = () => { changedAny = true; };
        const worker = async () => {
            while (queue.length && !signal.aborted) {
                try { await this.refreshOne(queue.shift(), signal, sortType, mark); } catch {}
            }
        };
        await Promise.all(Array.from({ length: Math.min(6, queue.length) }, worker));
        if (changedAny) saveBookmarks();
    }

    async loadExtra(b, signal) {
        const pu = bcProfileUrl(b);
        if (!pu) return {};
        for (const hd of [{ 'User-Agent': MOBILE_UA }, null]) {
            const h = await requestOnce(pu, hd, signal);
            if (signal?.aborted) break;
            const ex = h ? parseBcExtra(h) : {};
            if (ex.sch || ex.ptags) return ex;
        }
        return {};
    }

    async bgExtra(force) {
        if (this._xBusy || (!force && document.hidden)) return 'busy';
        const now = Date.now();
        const b = AppState.bookmarks.find(x => isObj(x) && isStr(x.url) && isSafeUrl(x.url) && urlSite(x.url) === 'bc' && (!x._pf || (!x.sch && now - x._pf > 600000)));
        if (!b) return 'none';
        this._xBusy = true;
        b._pf = now;
        let changed = false;
        try {
            const ex = await this.loadExtra(b);
            if (applyProfile(b, ex)) {
                changed = true;
                saveBookmarks();
                if (this.isOpen() && this.mode !== 'cal') this.render();
            }
        } catch {}
        this._xBusy = false;
        return changed;
    }

    async refreshOne(b, signal, sortType, mark) {
        const h = await requestProfile(b, signal);
        if (signal.aborted || !h) return;
        b._chk = Date.now();
        const info = parseProfile(h, urlSite(b.url), modelSlug(b.url));
        if (this.needsExtra(b, info)) {
            b._mob = Date.now();
            Object.assign(info, await this.loadExtra(b, signal));
        }
        if (info.status === 0 && b._live && Date.now() - b._live < 90000) info.status = 1;
        if (info.status > 0) this.touchSeen(b, mark);
        if (!applyProfile(b, info)) return;
        mark();
        this.onStatusChange(b, sortType);
    }

    needsExtra(b, info) {
        return urlSite(b.url) === 'bc' && !info.sch && (!b._mob || Date.now() - b._mob > 600000);
    }

    touchSeen(b, mark) {
        b.seen = Date.now();
        if (b._sv && b.seen - b._sv <= 300000) return;
        b._sv = b.seen;
        mark();
    }

    isOpen() { return !!this.overlay?.classList.contains('open'); }

    onStatusChange(b, sortType) {
        if (!this.isOpen()) return;
        b._updateItemDOM?.();
        if (RESORT_SORTS.has(sortType) || this.hideOffline || ST_FILTERS.some(([prop]) => this[prop])) {
            clearTimeout(this._resortTimer);
            const tick = () => {
                if (!this.overlay.classList.contains('open')) return;
                if (this.ui.shadow.activeElement?.matches?.('textarea,select')) { this._resortTimer = setTimeout(tick, 1000); return; }
                this.render();
            };
            this._resortTimer = setTimeout(tick, 600);
        }
    }

    build() {
        this.overlay = mk('div', 'bm-overlay fav-ov');
        this.overlay.onclick = e => { if (e.target === this.overlay && Date.now() - (this._opAt || 0) > 500) this.hide(); };
        this.overlay.addEventListener('touchmove', e => {
            for (const n of e.composedPath()) {
                if (n === this.overlay) break;
                if (!(n instanceof Element)) continue;
                const cs = getComputedStyle(n);
                if ((/(auto|scroll)/.test(cs.overflowY) && n.scrollHeight > n.clientHeight + 1) || (/(auto|scroll)/.test(cs.overflowX) && n.scrollWidth > n.clientWidth + 1)) return;
            }
            if (e.cancelable) e.preventDefault();
        }, { passive: false });

        const modal = mk('div', 'bm-modal fav-modal');
        this.modal = modal;
        this.mode = 'fav';
        const hdr = mk('div', 'bm-hdr');
        this.title = mk('span', 'bm-title');
        this.tabFav = mk('button', 'bm-tbtn on');
        this.tabHist = mk('button', 'bm-tbtn');
        this.tabFav.onclick = () => this.setMode('fav');
        this.tabHist.onclick = () => this.setMode('hist');
        const tabs = mk('div', 'bm-seg bm-tabs');
        this.tabCal = mk('button', 'bm-tbtn');
        this.tabCal.onclick = () => this.setMode('cal');
        tabs.append(this.tabFav, this.tabHist, this.tabCal);
        this.title.append(tabs);

        const closeBtn = mk('button', 'bm-close');
        closeBtn.innerHTML = '×';
        closeBtn.onclick = () => this.hide();

        const btnTogglePrev = mk('button', 'bm-hbtn bm-prevbtn');
        const btnSpeed = mk('button', 'bm-hbtn bm-spd');
        btnSpeed.style.fontWeight = 'bold';
        if (!Store.get('bc_mig_prev1', false)) { Store.set('bc_previews', true); Store.set('bc_mig_prev1', true); }
        this.prevEn = Store.get('bc_previews', true) !== false;
        this.updatePrevUI = () => {
            btnTogglePrev.classList.toggle('on', !!this.prevEn);
            btnTogglePrev.innerHTML = this.prevEn ? icons.eye : icons.eyeOff;
            btnTogglePrev.title = L().st_prev;
            btnSpeed.disabled = !this.prevEn;
            btnSpeed.style.opacity = this.prevEn ? '' : '.4';
            btnSpeed.textContent = Store.get('bc_prev_spd', 1000) === 500 ? '0.5s' : '1.0s';
        };
        this.updatePrevUI();
        btnTogglePrev.onclick = () => {
            this.prevEn = !this.prevEn;
            Store.set('bc_previews', this.prevEn);
            this.updatePrevUI();
            this.render();
        };
        btnSpeed.onclick = () => {
            Store.set('bc_prev_spd', Store.get('bc_prev_spd', 1000) === 500 ? 1000 : 500);
            this.updatePrevUI();
            this.stopPreviews();
            this.render();
        };
        const btnFavNav = mk('button', 'bm-sw');
        this.updateFavNavUI = () => {
            btnFavNav.classList.toggle('on', FavNav.on);
        };
        this.updateFavNavUI();
        btnFavNav.onclick = () => { FavNav.set(!FavNav.on); this.updateFavNavUI(); };
        const btnHideTopic = mk('button', 'bm-sw');
        const btnHideGrp = mk('button', 'bm-sw');
        const btnHidePT = mk('button', 'bm-sw');
        const btnHideNote = mk('button', 'bm-sw');
        const applyHide = () => {
            const t = Store.get('bc_bm_hide_topic', false) === true;
            const g = Store.get('bc_bm_hide_grp', false) === true;
            btnHideTopic.classList.toggle('on', t);
            btnHideGrp.classList.toggle('on', g);
            modal.classList.toggle('bm-no-topic', t);
            modal.classList.toggle('bm-no-grp', g);
            const pt = Store.get('bc_bm_hide_ptags', false) === true;
            btnHidePT.classList.toggle('on', pt);
            modal.classList.toggle('bm-no-ptags', pt);
            const hn = Store.get('bc_bm_hide_note', false) === true;
            btnHideNote.classList.toggle('on', hn);
            modal.classList.toggle('bm-no-note', hn);
        };
        applyHide();
        btnHideTopic.onclick = () => { Store.set('bc_bm_hide_topic', !(Store.get('bc_bm_hide_topic', false) === true)); applyHide(); };
        btnHideGrp.onclick = () => { Store.set('bc_bm_hide_grp', !(Store.get('bc_bm_hide_grp', false) === true)); applyHide(); };
        btnHideNote.onclick = () => { Store.set('bc_bm_hide_note', !(Store.get('bc_bm_hide_note', false) === true)); applyHide(); };
        btnHidePT.onclick = () => { Store.set('bc_bm_hide_ptags', !(Store.get('bc_bm_hide_ptags', false) === true)); applyHide(); this.render(); };
        const sortWrap = mk('div', 'bm-sort-wrap');
        this.btnSortType = mk('button', 'bm-hbtn');
        this.btnSortDir = mk('button', 'bm-hbtn');

        this.updateSortUI = () => {
            const type = Store.get('bc_bm_sort_type', 'date');
            const isRev = Store.get('bc_bm_sort_rev', false);
            const l = L();
            const map = { date: [icons.clock, l.sort_date], name: [icons.name, l.sort_name], online: [icons.dot, l.sort_live], last: [icons.eye, l.sort_last], viewers: [icons.eye, l.sort_viewers] };
            const [icon, label] = map[type] || map.date;
            this.btnSortType.innerHTML = icon + label;
            this.btnSortDir.innerHTML = isRev ? icons.arrowUp : icons.arrowDown;
        };

        this.btnSortType.onclick = () => {
            const types = ['date', 'name', 'online', 'last', 'viewers'];
            const cur = Store.get('bc_bm_sort_type', 'date');
            Store.set('bc_bm_sort_type', types[(types.indexOf(cur) + 1) % types.length]);
            this.updateSortUI();
            this.render();
        };

        this.btnSortDir.onclick = () => {
            Store.set('bc_bm_sort_rev', !Store.get('bc_bm_sort_rev', false));
            this.updateSortUI();
            this.render();
        };

        this.updateSortUI();
        sortWrap.append(this.btnSortType, this.btnSortDir);
        const btnCols = mk('button', 'bm-hbtn bm-colsbtn');
        const colsIcons = [
            pSvg('<rect x="4" y="5" width="16" height="14" rx="2.5"/>', 18),
            pSvg('<rect x="3" y="5" width="7.5" height="14" rx="2"/><rect x="13.5" y="5" width="7.5" height="14" rx="2"/>', 18)
        ];
        const colsKey = 'bc_bm_cols_g';
        this.applyCols = () => {
            const n = Store.get(colsKey, 1) === 2 ? 2 : 1;
            this.list.style.setProperty('grid-template-columns', `repeat(${n},minmax(0,1fr))`, 'important');
            this.list.classList.toggle('bm-c1', n === 1);
            btnCols.innerHTML = colsIcons[n - 1];
            btnCols.title = L().st_cols;
        };
        btnCols.onclick = () => {
            Store.set(colsKey, Store.get(colsKey, 1) === 2 ? 1 : 2);
            this.applyCols();
        };
        const btnAv = mk('button', 'bm-hbtn bm-spd');
        btnAv.textContent = '↻';
        let avBusy = false;
        btnAv.onclick = async () => {
            if (avBusy) return;
            avBusy = true;
            btnAv.disabled = true;
            const queue = AppState.bookmarks.slice(), total = queue.length;
            let done = 0;
            const upd = () => { btnAv.textContent = `${done}/${total}`; };
            upd();
            const worker = async () => {
                while (queue.length) {
                    const b = queue.shift();
                    try { await this.fetchAvatar(b); } catch {}
                    done++;
                    upd();
                }
            };
            await Promise.all([worker(), worker(), worker()]);
            btnAv.textContent = '✓';
            setTimeout(() => { btnAv.textContent = '↻'; btnAv.disabled = false; avBusy = false; }, 1500);
        };
        const row = (label, ctl) => { const r = mk('div', 'bm-setrow'); const t = mk('span'); t.textContent = label; r.append(t, ctl); return r; };
        const setPanel = mk('div', 'bm-setp');
        setPanel.append(
            row(L().st_favnav, btnFavNav),
            row(L().st_hide_topic, btnHideTopic),
            row(L().st_hide_grp, btnHideGrp),
            row(L().st_ptags || i18n.EN.st_ptags, btnHidePT),
            row(L().st_hide_note || i18n.EN.st_hide_note, btnHideNote),
            row(L().st_prev_spd, btnSpeed),
            row(L().st_av_refresh, btnAv)
        );
        const btnGear = mk('button', 'bm-hbtn bm-gear');
        btnGear.innerHTML = icons.gear;
        btnGear.onclick = () => { const o = setPanel.classList.toggle('open'); btnGear.classList.toggle('on', o); };
        const tools = mk('div', 'bm-tools');
        this.wsegHost = mk('div', 'bm-wseg-host');
        tools.append(this.wsegHost, btnTogglePrev, btnCols, btnGear);
        hdr.append(this.title, closeBtn, tools, setPanel);

        this.query = '';
        this.searchWrap = mk('div', 'bm-search-wrap');
        const sBox = mk('div', 'bm-search-box');
        const sIco = mk('span', 'bm-search-ico');
        sIco.innerHTML = icons.search;
        this.searchIn = mk('input', 'bm-search-in');
        this.searchIn.type = 'text';
        this.searchIn.enterKeyHint = 'search';
        this.searchIn.autocomplete = 'off';
        this.searchIn.spellcheck = false;
        this.searchIn.setAttribute('autocapitalize', 'off');
        this.searchClr = mk('button', 'bm-search-clr');
        this.searchClr.textContent = '×';
        let sTimer = 0;
        const onQuery = () => {
            const v = this.searchIn.value;
            this.query = v.trim().toLowerCase();
            this.searchClr.style.display = v ? 'flex' : 'none';
            clearTimeout(sTimer);
            sTimer = setTimeout(() => this.render(), 120);
        };
        this.searchIn.oninput = onQuery;
        this.searchIn.onkeydown = e => {
            e.stopPropagation();
            if (e.key === 'Escape' && this.searchIn.value) { e.preventDefault(); this.searchIn.value = ''; onQuery(); }
        };
        this.searchClr.onclick = () => { this.searchIn.value = ''; onQuery(); this.searchIn.focus(); };
        sBox.append(sIco, this.searchIn, this.searchClr);
        this.searchWrap.append(sBox, sortWrap);

        this.tagsWrap = mk('div', 'bm-tags-wrap');
        this.list = mk('div', 'bm-list');
        this.applyCols?.();
        window.addEventListener('bc_hls', () => {
            if (this.isOpen()) this.list.querySelectorAll('.bm-item').forEach(i => i._syncHls?.());
        });
        this._observer = new IntersectionObserver(entries => entries.forEach(e => e.target._inView = e.isIntersecting), { root: this.list, threshold: 0.05 });

        const foot = mk('div', 'bm-foot');
        this.btnAdd = mk('button', 'bm-add');
        this.btnAdd.onclick = () => this.add();

        foot.append(this.btnAdd);
        modal.append(hdr, this.searchWrap, this.tagsWrap, this.list, foot);
        this.overlay.appendChild(modal);
        this.ui.shadow.appendChild(this.overlay);
    }

    hide() {
        this.overlay.classList.remove('open');
    }

    setMode(m, fromOpen) {
        this.mode = m === 'hist' ? 'hist' : m === 'cal' ? 'cal' : 'fav';
        const h = this.mode === 'hist', c = this.mode === 'cal';
        this.modal.classList.toggle('mode-hist', h);
        this.modal.classList.toggle('mode-cal', c);
        this.tabFav.classList.toggle('on', !h && !c);
        this.tabHist.classList.toggle('on', h);
        this.tabCal.classList.toggle('on', c);
        if (h) { this.stopPreviews?.(); this.ui.historyManager?.show(); }
        else if (c) { this.stopPreviews?.(); this.ui.calendarManager?.show(); }
        else if (!fromOpen) { this.render(); this.checkStatuses(); }
    }

    updateLabels() {
        this.tabFav.innerHTML = `${icons.star} ${escHTML(L().bm_title)}`;
        this.tabHist.innerHTML = `${icons.clock} ${escHTML(L().hist_title)}`;
        this.tabCal.innerHTML = `${icons.cal} ${escHTML(L().cal_title)}`;
        if (this.ui.calendarManager?.isOpen()) this.ui.calendarManager.render();
        this.searchIn.placeholder = L().bm_find;
        this.updateSortUI?.(); this.updatePrevUI?.(); this.applyCols?.();
    }

    open(mode) {
        syncBookmarks();
        this.updateLabels();
        this.query = '';
        this.searchIn.value = '';
        this.searchClr.style.display = 'none';
        this.setMode(mode, true);
        if (this.mode === 'fav') {
            this.render();
            this.list.scrollTop = 0;
            this.checkStatuses();
        }
        this._opAt = Date.now();
        this.overlay.classList.add('open');
    }

    statusSeg(l) {
        const toggle = (prop, key) => () => { this[prop] = !this[prop]; Store.set(key, this[prop]); this.render(); };
        const seg = mk('div', 'bm-seg');
        seg.append(
            bmTbtn(l.bm_online, this.hideOffline, toggle('hideOffline', 'bc_bm_hide_off'), l.bm_online_t),
            ...ST_FILTERS.map(([prop, key, lk, label]) => bmTbtn(l[label], this[prop], toggle(prop, key), l[lk]))
        );
        return seg;
    }

    watchSeg(l) {
        const setW = v => () => { this.wFilter = this.wFilter === v ? null : v; Store.set('bc_bm_wf', this.wFilter == null ? -1 : this.wFilter); this.render(); };
        const wseg = mk('div', 'bm-seg bm-wseg');
        wseg.append(
            ...WMARKS.map(([v, ic, key]) => bmTbtn(icons[ic], this.wFilter === v, setW(v), l[key]))
        );
        return wseg;
    }

    appendGroupChips(chips, l) {
        const groups = bmGroups();
        if (this.currentGroup && !groups.includes(this.currentGroup)) this.currentGroup = null;
        if (!groups.length) return;
        const setGrp = g => () => { this.currentGroup = this.currentGroup === g ? null : g; this.render(); };
        chips.append(
            bmTbtn(`${icons.folder}${escHTML(l.grp_all)}`, !this.currentGroup, () => { this.currentGroup = null; this.render(); }),
            ...groups.map(g => bmTbtn(`${icons.folder}${escHTML(g)}`, this.currentGroup === g, setGrp(g)))
        );
    }

    appendTagChips(chips, l) {
        const allTags = new Set(AppState.bookmarks.flatMap(b => noteHashTags(b).map(t => t.toLowerCase())));
        const ptc = new Map();
        AppState.bookmarks.forEach(b => (b.ptags || []).forEach(t => countInto(ptc, t)));
        const hidePT = Store.get('bc_bm_hide_ptags', false) === true;
        const ptop = hidePT ? [] : [...ptc.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, 30).map(e => e[0]);
        if (this.currentTagFilter && !allTags.has(this.currentTagFilter) && (hidePT || !ptc.has(this.currentTagFilter))) this.currentTagFilter = null;
        if (!allTags.size && !ptop.length) { this.currentTagFilter = null; return; }
        const setTag = tag => () => { this.currentTagFilter = this.currentTagFilter === tag ? null : tag; this.render(); };
        const pim = ptIcoMap();
        chips.append(
            bmTbtn(l.bm_all, !this.currentTagFilter, () => { this.currentTagFilter = null; this.render(); }),
            ...[...allTags].sort().map(tag => bmTbtn(tag, this.currentTagFilter === tag, setTag(tag))),
            ...(allTags.size && ptop.length ? [mk('span', 'bm-chips-sep')] : []),
            ...ptop.map(tag => bmTbtn(`${ptImg(pim.get(tag), 'bm-ptic') || icons.tag}${escHTML(tag)}`, this.currentTagFilter === tag, setTag(tag)))
        );
    }

    renderTags() {
        if (!this.tagsWrap) return;
        const l = L();
        const chips = mk('div', 'bm-chips');
        this.tagsWrap.replaceChildren(this.statusSeg(l));
        this.wsegHost && this.wsegHost.replaceChildren(this.watchSeg(l));
        this.tagsWrap.style.display = 'flex';
        this.appendGroupChips(chips, l);
        this.appendTagChips(chips, l);
        if (chips.children.length) this.tagsWrap.append(chips);
    }

    renderItem(b) {
        const cached = this._els.get(b);
        if (cached) {
            cached.fillGrp();
            cached.apply();
            cached.item._syncNote?.();
            cached.item._syncHls?.();
            b._updateItemDOM = cached.apply;
            return cached.item;
        }
        const item = mk('div', 'bm-item');
        const top = mk('div', 'bm-item-top');
        const link = mk('a', 'bm-link');
        link.href = isSafeUrl(b.url) ? b.url : '#';

        const img = mk('img', 'bm-avatar');
        const applyAva = () => {
            const k = b.avatar || '';
            if (img._k === k) return;
            img._k = k;
            bindAvatar(img, b.name, () => [
                toHttps(b.avatar),
                toHttps(histLoad().m[bmKey(b.url)]?.a)
            ], () => { if (!b._avFix) { b._avFix = 1; this.fetchAvatar(b); } });
        };
        applyAva();

        const stat = mk('span', 'bm-stat');
        const nameWrap = mk('div', 'bm-nwrap');
        const nameEl = mk('span', 'bm-name');
        nameEl.textContent = b.name;
        const seenEl = mk('span', 'bm-seen');
        const viewEl = mk('span', 'bm-view');
        nameWrap.append(stat, nameEl, viewEl, seenEl);
        link.append(img, nameWrap);
        let lpT = 0, lpDone = false, lpArmed = false, lpX = 0, lpY = 0, lpType = 'mouse';
        const lpClear = () => { clearTimeout(lpT); lpT = 0; };
        const lpOk = e => !e.target.closest('button, textarea, select, input, a.tp-btn, .bm-nwrap');
        item.addEventListener('pointerdown', e => {
            lpClear();
            lpDone = false;
            lpArmed = false;
            if (e.pointerType === 'mouse' && e.button !== 0) return;
            if (!lpOk(e)) return;
            lpArmed = true;
            lpType = e.pointerType;
            lpX = e.clientX;
            lpY = e.clientY;
            lpT = setTimeout(() => { lpT = 0; lpDone = true; openFrameView(this.ui, b); }, 450);
        });
        item.addEventListener('pointermove', e => { if (lpT && Math.hypot(e.clientX - lpX, e.clientY - lpY) > 10) lpClear(); });
        ['pointerup', 'pointercancel', 'pointerleave'].forEach(t => item.addEventListener(t, lpClear));
        item.addEventListener('click', e => { if (lpDone) { lpDone = false; e.preventDefault(); e.stopImmediatePropagation(); } }, true);
        item.addEventListener('contextmenu', e => { if (lpArmed && (lpType !== 'mouse' || lpDone)) e.preventDefault(); });
        img.draggable = false;
        img.style.webkitTouchCallout = 'none';

        let cpT = 0, cpDone = false, cpX = 0, cpY = 0;
        nameWrap.style.userSelect = nameWrap.style.webkitUserSelect = nameWrap.style.webkitTouchCallout = 'none';
        const cpClear = () => { clearTimeout(cpT); cpT = 0; };
        const cpFlash = ok => {
            nameEl.textContent = ok ? '✓' : 'ERR';
            setTimeout(() => { nameEl.textContent = b.name; }, 800);
        };
        nameWrap.addEventListener('pointerdown', e => {
            if (e.pointerType === 'mouse' && e.button !== 0) return;
            cpClear();
            cpDone = false;
            cpX = e.clientX;
            cpY = e.clientY;
            cpT = setTimeout(() => { cpT = 0; cpDone = true; Helpers.copy(b.name, () => cpFlash(true), () => cpFlash(false)); }, 450);
        });
        nameWrap.addEventListener('pointermove', e => { if (cpT && Math.hypot(e.clientX - cpX, e.clientY - cpY) > 10) cpClear(); });
        ['pointerup', 'pointercancel', 'pointerleave'].forEach(t => nameWrap.addEventListener(t, cpClear));
        nameWrap.addEventListener('click', e => { if (cpDone) { cpDone = false; e.preventDefault(); e.stopImmediatePropagation(); } }, true);
        nameWrap.addEventListener('contextmenu', e => e.preventDefault());

        const delBtn = mk('button', 'bm-del');
        delBtn.innerHTML = icons.del;
        delBtn.title = L().bm_del;
        delBtn.onclick = e => {
            e.preventDefault(); e.stopPropagation();
            dropBookmark(b);
            this.render();
        };
        const pinBtn = mk('button', 'bm-pin');
        pinBtn.innerHTML = icons.star;
        pinBtn.onclick = e => {
            e.preventDefault(); e.stopPropagation();
            if (b.pin) delete b.pin; else b.pin = true;
            saveBookmarks();
            this.render();
        };
        top.append(link, pinBtn, delBtn);

        const makeAct = (html, fn, onHold) => {
            const btn = mk('button', 'bm-act-btn');
            btn.innerHTML = html;
            if (onHold) Helpers.bindLongPress(btn, () => fn(btn), onHold);
            else btn.onclick = e => { e.preventDefault(); e.stopPropagation(); fn(btn); };
            return btn;
        };
        const getHls = () => (String(b.name).toLowerCase() === String(currentSite.getName()).toLowerCase() && urlSite(b.url) === siteKey(location.hostname)) ? getStreamUrl() : null;
        const actionsRow = mk('div', 'bm-actions-row bm-acts');
        actionsRow.append(
            makeAct(`${icons.search} <span>${L().search}</span>`, () => { noFade(this.overlay, this.ui.searchManager?.overlay); this.overlay.classList.remove('open'); this.ui.searchManager?.open(b.name, true); }),
            makeAct(`${icons.hls} <span>HLS</span>`,
                btn => copyHls(getHls(), ok => Helpers.flashBtn(btn, ok)),
                () => shareHls(getHls(), `${b.name} Stream`, () => Helpers.flashBtn(actionsRow.children[1], false))
            ),
            makeAct(`${icons.copy} <span>${L().copy}</span>`, btn => {
                Helpers.copy(linkFor(b.url), () => Helpers.flashBtn(btn, true), () => Helpers.flashBtn(btn, false));
            })
        );
        const hlsBtn = actionsRow.children[1];
        item._syncHls = () => {
            hlsBtn.style.opacity = getHls() ? '' : '.4';
            hlsBtn.title = 'HLS';
        };
        item._syncHls();

        const noteInput = mk('textarea', 'bm-note');
        noteInput.rows = '1';
        noteInput.style.cssText = 'resize:none;overflow:hidden;min-height:36px;white-space:pre-wrap;word-break:break-word;';
        noteInput.placeholder = L().note_ph;
        noteInput.value = b.note || '';
        item._syncNote = () => {
            const v = b.note || '';
            if (document.activeElement !== noteInput && noteInput.value !== v) { noteInput.value = v; requestAnimationFrame(autoResize); }
        };
        const autoResize = () => { noteInput.style.height = 'auto'; noteInput.style.height = `${Math.max(36, noteInput.scrollHeight)}px`; };
        requestAnimationFrame(autoResize);

        let noteT = 0;
        noteInput.oninput = e => {
            requestAnimationFrame(autoResize);
            b.note = e.target.value.trim();
            clearTimeout(noteT);
            noteT = setTimeout(saveBookmarks, 400);
        };
        noteInput.onblur = () => { if (noteT) { clearTimeout(noteT); noteT = 0; saveBookmarks(); } };
        noteInput.onchange = () => { clearTimeout(noteT); noteT = 0; saveBookmarks(); this.ui.flash(this.btnAdd, 'OK'); this.render(); };
        noteInput.onkeydown = e => e.stopPropagation();

        const topicEl = mk('div', 'bm-topic');

        const grpSel = mk('button', 'bm-grp bm-grp-btn');
        grpSel.type = 'button';
        const groupList = () => {
            const gs = [...new Set(AppState.bookmarks.map(x => x.g).filter(Boolean))].sort((x, y) => x.localeCompare(y));
            if (b.g && !gs.includes(b.g)) gs.push(b.g);
            return gs;
        };
        const fillGrp = () => {
            const label = b.g || L().grp_none;
            if (grpSel._lbl === label) return;
            grpSel._lbl = label;
            grpSel.innerHTML = `<span>${icons.folder}${escHTML(label)}</span><span class="bm-grp-arr">▾</span>`;
        };
        fillGrp();
        grpSel.onclick = e => {
            e.stopPropagation();
            openGroupDialog(this.ui, {
                current: b.g || '',
                groups: groupList(),
                onPick: v => { b.g = v; saveBookmarks(); this.render(); }
            });
        };
        grpSel.onkeydown = e => e.stopPropagation();

        const updateTopicDOM = txt => {
            const key = `${txt}|${!!b._topicExp}|${AppState.lang}`;
            if (topicEl._k === key) return;
            topicEl._k = key;
            if (!txt) { topicEl.style.display = 'none'; return; }
            topicEl.style.display = 'block';
            if (txt.length > 55) {
                const txtMore = L().tp_more;
                const txtLess = L().tp_less;
                topicEl.innerHTML = `<span>${escHTML(b._topicExp ? txt : txt.slice(0, 55) + '...')} </span><a class="tp-btn" style="color:var(--th);cursor:pointer;font-weight:bold;text-decoration:underline;">${escHTML(b._topicExp ? txtLess : txtMore)}</a>`;
                topicEl.querySelector('.tp-btn')?.addEventListener('click', ev => {
                    ev.preventDefault();
                    b._topicExp = !b._topicExp;
                    updateTopicDOM(txt);
                });
            } else topicEl.textContent = txt;
        };

        const applyW = () => { item.dataset.w = String(bmWatch(b, this._hist || (this._hist = histLoad()))); };
        const ptagsEl = mk('div', 'bm-ptags');
        const applyPT = () => {
            const tg = Array.isArray(b.ptags) ? b.ptags : [], cf = this.currentTagFilter || '';
            const key = `${tg.join('|')}#${(Array.isArray(b.ptic) ? b.ptic : []).join('|')}#1`;
            const syncOn = () => ptagsEl.querySelectorAll('.bm-ptag[data-t]').forEach(c => c.classList.toggle('on', c.dataset.t === cf));
            if (ptagsEl._k === key) { syncOn(); return; }
            ptagsEl._k = key;
            ptagsEl.replaceChildren();
            ptagsEl.style.display = tg.length ? 'flex' : 'none';
            const max = 3;
            tg.slice(0, max).forEach((t, ix) => {
                const c = mk('button', `bm-ptag${cf === t.toLowerCase() ? ' on' : ''}`);
                c.type = 'button';
                c.dataset.t = t.toLowerCase();
                const u = ptIcoUrl(Array.isArray(b.ptic) ? b.ptic[ix] : '');
                if (u) {
                    const im = mk('img', 'bm-ptic');
                    im.alt = '';
                    im.decoding = 'sync';
                    im.referrerPolicy = 'no-referrer';
                    im.onerror = () => im.remove();
                    im.src = u;
                    c.append(im);
                }
                c.append(document.createTextNode(t));
                c.onclick = e => {
                    e.preventDefault(); e.stopPropagation();
                    this.currentTagFilter = this.currentTagFilter === t.toLowerCase() ? null : t.toLowerCase();
                    this.render();
                };
                ptagsEl.append(c);
            });
            if (tg.length > max) { const more = mk('span', 'bm-ptag more'); more.textContent = `+${tg.length - max}`; ptagsEl.append(more); }
        };

        const previewImg = mk('img', 'bm-prev');
        previewImg.onerror = () => {
            if (!previewImg.hasAttribute('data-frame')) { previewImg.style.display = 'none'; return; }
            if (/^data:/.test(previewImg.src) || !tryGm(previewImg, previewImg._u, () => frameFail(previewImg))) frameFail(previewImg);
        };

        item.onclick = e => { if (isSafeUrl(b.url) && !e.target.closest('button, textarea, select, a.tp-btn')) location.href = linkFor(b.url); };
        item.append(top, actionsRow, ptagsEl, topicEl, grpSel, noteInput, previewImg);

        const showImg = on => {
            const d = on ? 'block' : 'none';
            if (previewImg.style.display !== d) previewImg.style.display = d;
        };
        const applyPreview = st => {
            if (!(this.prevEn && b.frame && st !== 0)) {
                previewImg.removeAttribute('data-frame');
                previewImg._gen = (previewImg._gen || 0) + 1;
                previewImg._isUpdating = false;
                return showImg(false);
            }
            previewImg.setAttribute('data-frame', b.frame);
            showImg(true);
            previewImg._bRef = b;
            b._lastImg ||= `${b.frame.split('?')[0]}?t=${Date.now()}`;
            if (previewImg._u !== b._lastImg) { previewImg._u = b._lastImg; previewImg.src = b._lastImg; }
        };
        const applyStatus = () => {
            const l = L(), st = b.status ?? 0, col = STATUS_COLORS[st] || '#888';
            link.href = isSafeUrl(b.url) ? linkFor(b.url) : '#';
            applyAva();
            img.title = l.fr_hold;
            item.classList.toggle('pinned', !!b.pin);
            pinBtn.classList.toggle('on', !!b.pin);
            pinBtn.title = b.pin ? l.bm_unpin : l.bm_pin;
            item.dataset.st = String(st);
            stat.style.background = col;
            stat.style.boxShadow = st ? `0 0 8px ${col}` : '0 0 4px rgba(0,0,0,0.5)';
            nameEl.textContent = bmLabel(b, l);
            seenEl.textContent = bmSeen(b, st);
            seenEl.title = l.seen_tip;
            const vw = bmViews(b), vwTxt = vw ? String(vw) : '';
            if (viewEl._t !== vwTxt) { viewEl._t = vwTxt; viewEl.innerHTML = vwTxt ? `${icons.eye}${vwTxt}` : ''; }
            viewEl.title = l.viewers_tip;
            updateTopicDOM(b.topic || '');
            applyW();
            applyPT();
            applyPreview(st);
        };
        applyStatus();
        b._updateItemDOM = applyStatus;
        this._observer?.observe(item);
        this._els.set(b, { item, fillGrp, apply: applyStatus, resize: () => requestAnimationFrame(autoResize) });
        return item;
    }

    scanPage() {
        if (!IS_BC) return false;
        const key = pageKey();
        if (!key) return false;
        const b = AppState.bookmarks.find(x => isObj(x) && isStr(x.url) && bmKey(x.url) === key);
        if (!b) return false;
        const info = parseBcExtra(document.documentElement.outerHTML);
        if (!info.ptags && !info.sch) return false;
        if (applyProfile(b, info)) {
            saveBookmarks();
            if (this.isOpen()) this.render();
        }
        return true;
    }

    markLive(key, known) {
        const b = known || AppState.bookmarks.find(x => bmKey(x.url) === key);
        if (!b) return;
        b._live = Date.now();
        b.seen = b._live;
        if ((b.status ?? 0) !== 0) return;
        b.status = 1;
        clearTimeout(this._vwSave);
        this._vwSave = setTimeout(saveBookmarks, 3000);
        if (this.isOpen()) this.onStatusChange(b, Store.get('bc_bm_sort_type', 'date'));
    }

    setViewers(key, n, known) {
        const b = known || AppState.bookmarks.find(x => bmKey(x.url) === key);
        if (!b || !(n >= 0)) return;
        const changed = b.viewers !== n;
        b.viewers = n;
        b.vts = Date.now();
        if (!changed) return;
        clearTimeout(this._vwSave);
        this._vwSave = setTimeout(saveBookmarks, 3000);
        if (this.isOpen()) this.onStatusChange(b, Store.get('bc_bm_sort_type', 'date'));
    }

    addEntry({ name, url, avatar, viewers }) {
        syncBookmarks();
        if (!isSafeUrl(url) || isFavKey(bmKey(url))) return false;
        const bm = { name: clip(name, 100) || modelSlug(url), url: normUrl(url), avatar: toHttps(avatar), note: '' };
        if (viewers > 0) { bm.viewers = viewers; bm.vts = Date.now(); }
        AppState.bookmarks.push(bm);
        saveBookmarks();
        if (this.isOpen()) this.render();
        this.checkStatuses();
        if (!bm.avatar) this.fetchAvatar(bm);
        return true;
    }

    removeKey(key, after) {
        syncBookmarks();
        const ex = AppState.bookmarks.find(b => isObj(b) && isStr(b.url) && bmKey(b.url) === key);
        if (!ex) return false;
        const run = () => {
            dropBookmark(ex);
            if (this.isOpen()) this.render();
            if (after) after();
        };
        if (ex.note || ex.g) askConfirm(this.ui, L().star_del_q, run); else run();
        return true;
    }

    updateAddBtn() {
        const name = currentSite.getName(), l = L();
        this.btnAdd.disabled = !name || isFavName(name);
        this.btnAdd.textContent = !name ? l.no_model : isFavName(name) ? l.bm_dup : `${l.bm_add} (${name})`;
    }

    passesFilters(b) {
        const st = b.status ?? 0, lk = bmStatusKey(b);
        return !(this.hideOffline && st === 0) && !ST_FILTERS.some(([prop,, key]) => this[prop] && key === lk) && this.matchesText(b)
            && (this.wFilter == null || bmWatch(b, this._hist) === this.wFilter);
    }

    matchesText(b) {
        const tag = this.currentTagFilter, q = this.query, g = this.currentGroup;
        const note = b.note || '', grp = b.g || '';
        return bmTagMatch(b, tag)
            && (!g || grp === g)
            && (!q || `${b.name} ${note} ${grp} ${(b.ptags || []).join(' ')}`.toLowerCase().includes(q));
    }

    syncList(els) {
        const keep = new Set(els);
        Array.from(this.list.children).forEach(c => { if (!keep.has(c)) c.remove(); });
        els.forEach((el, i) => {
            const cur = this.list.children[i];
            if (cur !== el) this.list.insertBefore(el, cur || null);
        });
    }

    sortedFiltered() {
        const dir = Store.get('bc_bm_sort_rev', false) ? -1 : 1;
        const cmp = BM_CMP[Store.get('bc_bm_sort_type', 'date')] || BM_CMP.date;
        return AppState.bookmarks.map((b, i) => ({ b, i }))
            .sort((x, y) => (!!y.b.pin - !!x.b.pin) || dir * cmp(x, y))
            .filter(({ b }) => this.passesFilters(b));
    }

    render() {
        this.ui.thumbStars?.schedule();
        this._hist = histLoad();
        if (this._lang !== AppState.lang) { this._els = new WeakMap(); this._lang = AppState.lang; }
        const keepScroll = this.list.scrollTop;
        this.searchWrap.style.display = AppState.bookmarks.length ? 'flex' : 'none';
        AppState.bookmarks.forEach(b => { if (b?._updateItemDOM) b._updateItemDOM = null; });
        this.updateAddBtn();

        if (!AppState.bookmarks.length) {
            this.stopPreviews();
            this.list.innerHTML = `<div class="bm-empty">${L().bm_empty}</div>`;
            if (this.tagsWrap) { this.tagsWrap.replaceChildren(); this.tagsWrap.style.display = 'none'; }
            this.wsegHost?.replaceChildren();
            return;
        }

        this.renderTags();
        this.list.classList.add('bm-gallery-mode');
        this.applyCols?.();

        const sortedList = this.sortedFiltered();

        if (!sortedList.length) {
            this.list.innerHTML = `<div class="bm-empty">${L().bm_nomatch}</div>`;
            return;
        }

        this.syncList(sortedList.map(({ b }) => this.renderItem(b)));
        this.list.scrollTop = keepScroll;

        if (!this._previewTimer && this.prevEn) {
            this._previewTimer = setInterval(() => this.tickPreviews(), Store.get('bc_prev_spd', 1000));
        }
    }

    stopPreviews() {
        clearInterval(this._previewTimer);
        this._previewTimer = null;
    }

    tickPreviews() {
        if (!this.overlay.classList.contains('open') || !this.prevEn) return this.stopPreviews();
        if (document.hidden) return;
        this.list.querySelectorAll('.bm-item').forEach(item => {
            if (item._inView) refreshFrame(item.querySelector('img[data-frame]'));
        });
    }

    add() {
        syncBookmarks();
        const name = currentSite.getName();
        if (!name) return;
        if (isFavName(name)) return this.ui.flash(this.btnAdd, L().bm_dup);

        const bm = { name, url: normUrl(location.href), avatar: pageAvatar(name), note: '' };
        const vn = parseCount(readViewers());
        if (vn > 0) { bm.viewers = vn; bm.vts = Date.now(); }
        AppState.bookmarks.push(bm);
        saveBookmarks();
        this.render();
        this.ui.flash(this.btnAdd, 'OK');
        this.checkStatuses();
        if (!bm.avatar) this.fetchAvatar(bm);
    }

    async fetchAvatar(bm) {
        const avatar = extractAvatar((await withBackoff(() => requestOnce(bm.url))) || '');
        if (!avatar) return;
        if (avatar === bm.avatar) return;
        bm.avatar = avatar;
        saveBookmarks();
        if (this.isOpen()) this.render();
    }
}

const pageHasError = (url, res) => {
    const raw = res.responseText || '', txt = raw.toLowerCase();
    const title = txt.match(/<title[^>]*>(.*?)<\/title>/i)?.[1] || '';
    return [
        () => res.status === 404 || res.status >= 500,
        () => ['not found', '404', 'error'].some(t => title.includes(t)),
        () => /no\s*(?:videos?|results?)\s*found|does\s*not\s*exist|\b0\s*results?\b/i.test(txt),
        () => url.includes('camshowrecordings') && !raw.includes('class="h1modelpage"'),
        () => url.includes('pornolab.net') && (/не найден[оа]/.test(txt) || !txt.includes('tlink'))
    ].some(check => check());
};

class SearchManager {
    constructor(uiController) {
        this.ui = uiController;

        this.overlay = null;
        this.input = null;
        this.btns = [];
        this._live = new Set();
        this._sched = [];
        this._gen = 0;
        this.build();
    }

    build() {
        this.overlay = mk('div', 'bm-overlay');
        this.overlay.onclick = e => { if (e.target === this.overlay && Date.now() - (this._opAt || 0) > 500) this.overlay.classList.remove('open'); };

        const modal = mk('div', 'bm-modal');
        this.modal = modal;
        const hdr = mk('div', 'bm-hdr');
        this.title = mk('span', 'bm-title');

        this.btnBack = mk('button', 'bm-close bm-back');
        this.btnBack.innerHTML = icons.back;
        this.btnBack.style.display = 'none';
        this.btnBack.onclick = () => { noFade(this.overlay, this.ui.bookmarkManager?.overlay); this.overlay.classList.remove('open'); if (this.ui.bookmarkManager) this.ui.bookmarkManager.open(); };

        const titleWrap = mk('div', 'bm-twrap');
        titleWrap.append(this.title);

        const closeBtn = mk('button', 'bm-close');
        closeBtn.innerHTML = '×';
        closeBtn.onclick = () => this.overlay.classList.remove('open');

        hdr.append(titleWrap, this.btnBack, closeBtn);

        const list = mk('div', 'bm-list');
        this.input = mk('input', 'bm-note bm-srch-in');
        this.input.type = 'text';
        this.input.onkeydown = e => e.stopPropagation();

        const ENGINES = [
            ['PornoLab', 'https://pornolab.net/forum/tracker.php?nm=%s'],
            ['BestCam.tv', 'https://bestcam.tv/model/%s'],
            ['CamShowRecordings', 'https://www.camshowrecordings.com/?s=%s'],
            ['LiveCamsRip', 'https://www.livecamsrip.com/%s/profile'],
            ['CamDownload', 'https://camdownload.net/performer/%s'],
            ['CamShow.cc', 'https://camshow.cc/streamer/%s'],
            ['SimpCity', 'https://simpcity.cr/search/?q=%s&o=date', true],
            ['CamsClips', 'https://www.camsclips.com/search/%s/', true]
        ];
        list.append(this.input, ...ENGINES.map(([txt, tmpl, skipCheck]) => {
            const urlFn = v => tmpl.replace('%s', encodeURIComponent(v));
            const btn = mk('button', 'bm-btn bm-srch-btn');
            btn.textContent = txt;
            btn.onclick = () => {
                const v = this.input.value.trim();
                if (v) window.open(urlFn(v), '_blank');
                else this.ui.flash(btn, 'ERR');
            };
            this.btns.push({ btn, urlFn, skipCheck: !!skipCheck });
            return btn;
        }));

        let debounceTimer;
        this.input.oninput = () => {
            clearTimeout(debounceTimer);
            debounceTimer = setTimeout(() => {
                this._resetRequests();
                const v = this.input.value.trim();
                this.btns.forEach((item, index) => {
                    if (!v) {
                        item.btn.style.borderLeft = '4px solid transparent';
                        item.btn.style.opacity = '1';
                    } else if (item.skipCheck) {
                        item.btn.style.borderLeft = '4px solid #888';
                        item.btn.style.opacity = '1';
                    } else {
                        this._sched.push(setTimeout(() => this.checkPage(item.urlFn(v), item.btn), index * 150));
                    }
                });
            }, 600);
        };

        modal.append(hdr, list);
        this.overlay.appendChild(modal);
        this.ui.shadow.appendChild(this.overlay);
    }

    _resetRequests() {
        this._gen++;
        if (this._sched) { this._sched.forEach(clearTimeout); this._sched = []; }
        this._live.forEach(r => { try { r.abort(); } catch {} });
        this._live.clear();
    }

    checkPage(url, btn) {
        if (!btn.isConnected) return;
        btn.style.borderLeft = '4px solid orange';
        btn.style.opacity = '0.8';
        const gen = this._gen;
        const stale = () => gen !== this._gen || !btn.isConnected;
        const markErr = () => { if (!stale()) { btn.style.borderLeft = '4px solid #ef4444'; btn.style.opacity = '0.5'; } };
        const req = GM_xmlhttpRequest({
            method: 'GET',
            url,
            timeout: 8000,
            onload: res => {
                this._live.delete(req);
                if (stale()) return;
                if (pageHasError(url, res)) return markErr();
                btn.style.borderLeft = '4px solid #10b981';
                btn.style.opacity = '1';
            },
            onerror: () => { this._live.delete(req); markErr(); },
            ontimeout: () => { this._live.delete(req); markErr(); }
        });
        this._live.add(req);
    }

    open(customName, fromFavs = false) {
        if (this._resetRequests) this._resetRequests();
        if (this.btnBack) this.btnBack.style.display = fromFavs ? 'flex' : 'none';
        this.modal?.classList.toggle('has-back', !!fromFavs);
        this.title.innerHTML = `${icons.search} ${L().search}`;
        const name = (typeof customName === 'string') ? customName : (currentSite.getName() || '');
        this.input.value = name;
        this._opAt = Date.now();
        this.overlay.classList.add('open');
        if (name) {
            this.btns.forEach((item, index) => {
                item.btn.style.opacity = '1';
                if (item.skipCheck) {
                    item.btn.style.borderLeft = '4px solid #888';
                } else {
                    item.btn.style.borderLeft = '4px solid transparent';
                    const t = setTimeout(() => this.checkPage(item.urlFn(name), item.btn), 200 + (index * 150));
                    this._sched.push(t);
                }
            });
        }
    }
}

class PickManager {
    constructor(uiController, onDone) {
        this.ui = uiController;
        this.onDone = onDone;
        this.active = false;
        this.cur = null;
        this._sx = 0;
        this._sy = 0;
        this.box = mk('div', 'pick-box');
        this.bar = mk('div', 'pick-bar');
        this.info = mk('div', 'pick-info');
        const btns = mk('div', 'pick-btns');
        this.btnUp = mk('button', 'bm-btn');
        this.btnOk = mk('button', 'bm-btn');
        this.btnNo = mk('button', 'bm-btn');
        btns.append(this.btnUp, this.btnOk, this.btnNo);
        this.bar.append(this.info, btns);
        this.ui.shadow.append(this.box, this.bar);

        this.btnUp.onclick = () => {
            const p = this.cur?.parentElement;
            if (p && p !== document.body && p !== document.documentElement) this.setTarget(p);
        };
        this.btnOk.onclick = () => this.confirm();
        this.btnNo.onclick = () => this.stop();

        this._events = ['pointerdown', 'pointerup', 'mousedown', 'mouseup', 'click', 'touchend'];
        this._handler = e => {
            if (e.composedPath().includes(this.ui.host)) return;
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            if (e.type === 'pointerdown') {
                this._sx = e.clientX;
                this._sy = e.clientY;
            } else if (e.type === 'pointerup' && Math.hypot(e.clientX - this._sx, e.clientY - this._sy) < 10) {
                this.pickAt(e.clientX, e.clientY);
            }
        };
        this._sync = () => this.placeBox();
    }

    start() {
        if (this.active) return;
        this.active = true;
        this.cur = null;
        this.box.style.display = 'none';
        this.btnUp.textContent = `↑ ${L().pk_up}`;
        this.btnOk.textContent = L().pk_ok;
        this.btnNo.textContent = L().pk_cancel;
        this.info.textContent = L().pk_hint;
        this.bar.classList.add('open');
        this._events.forEach(ev => window.addEventListener(ev, this._handler, { capture: true, passive: false }));
        window.addEventListener('scroll', this._sync, { capture: true, passive: true });
        window.addEventListener('resize', this._sync, { passive: true });
    }

    stop() {
        if (!this.active) return;
        this.active = false;
        this.cur = null;
        this._events.forEach(ev => window.removeEventListener(ev, this._handler, true));
        window.removeEventListener('scroll', this._sync, true);
        window.removeEventListener('resize', this._sync);
        this.box.style.display = 'none';
        this.bar.classList.remove('open');
        this.onDone?.();
    }

    pickAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el || el === document.body || el === document.documentElement || el === this.ui.host) return;
        this.setTarget(el);
    }

    placeBox() {
        if (!this.cur || !this.cur.isConnected) return;
        const r = this.cur.getBoundingClientRect();
        const s = this.box.style;
        s.display = 'block';
        s.left = `${r.left}px`;
        s.top = `${r.top}px`;
        s.width = `${r.width}px`;
        s.height = `${r.height}px`;
    }

    setTarget(el) {
        this.cur = el;
        this.placeBox();
        const sel = buildSelector(el);
        let n = 0;
        try { n = document.querySelectorAll(sel).length; } catch {}
        this.info.textContent = `${sel} (${n} ${L().pk_found})`;
    }

    confirm() {
        if (!this.cur) return;
        const sel = buildSelector(this.cur);
        try { document.querySelector(sel); } catch { return; }
        addCustom(sel);
        applyHideCSS();
        this.stop();
    }
}

const textEl = (cls, text, tag = 'div') => { const e = mk(tag, cls); e.textContent = text; return e; };
const firstMatch = c => {
    for (const x of c.sel) { try { const e = document.querySelector(x); if (e) return e; } catch {} }
    return null;
};

class HideManager {
    constructor(uiController) {
        this.ui = uiController;
        this.build();
        this.picker = new PickManager(uiController, () => this.open());
    }

    build() {
        this.overlay = mk('div', 'bm-overlay');
        this.overlay.onclick = e => { if (e.target === this.overlay && Date.now() - (this._opAt || 0) > 500) this.close(); };

        const modal = mk('div', 'bm-modal');
        const hdr = mk('div', 'bm-hdr');
        this.title = mk('span', 'bm-title');
        const closeBtn = mk('button', 'bm-close');
        closeBtn.innerHTML = '×';
        closeBtn.onclick = () => this.close();
        hdr.append(this.title, closeBtn);

        this.list = mk('div', 'bm-list');

        const foot = mk('div', 'bm-foot');
        this.btnPick = mk('button', 'bm-add');
        this.btnPick.onclick = () => { this.close(); this.picker.start(); };
        this.btnReset = mk('button', 'bm-btn');
        this.btnReset.style.gridColumn = 'span 2';
        this.btnReset.onclick = () => {
            const cfgNow = Store.get('bc_hide_cfg', {});
            HIDE_CATS.forEach(c => { if (c.site === SITE) delete cfgNow[c.id]; });
            Store.set('bc_hide_cfg', cfgNow);
            setCustom([]);
            applyHideCSS();
            this.render();
        };
        foot.append(this.btnPick, this.btnReset);

        modal.append(hdr, this.list, foot);
        this.overlay.appendChild(modal);
        this.ui.shadow.appendChild(this.overlay);
    }

    updateLabels() {
        this.render();
    }

    open() {
        this.render();
        this._opAt = Date.now();
        this.overlay.classList.add('open');
    }

    close() {
        this.overlay.classList.remove('open');
    }

    render() {
        const l = L();
        this.title.innerHTML = `${icons.eyeOff} ${l.hd_title}`;
        this.btnPick.innerHTML = `${icons.target} ${l.hd_pick}`;
        this.btnReset.textContent = l.hd_reset;
        this.list.replaceChildren();
        const frag = document.createDocumentFragment();
        this.renderCats(frag, l);
        this.renderRules(frag, l);
        this.list.append(frag);
    }

    renderCats(frag, l) {
        const plat = detectPlatform();
        const cats = HIDE_CATS.filter(c => c.site === SITE && (c.plat === 'b' || c.plat === plat));
        const cfg = Store.get('bc_hide_cfg', {});
        const rows = [];
        const setAll = fn => {
            const cur = Store.get('bc_hide_cfg', {});
            cats.forEach(c => { cur[c.id] = fn(c); });
            Store.set('bc_hide_cfg', cur);
            rows.forEach(({ c, row }) => row.classList.toggle('on', catOn(c, cur)));
            applyHideCSS();
        };
        const bulk = (defs, cols) => {
            const box = mk('div', 'hd-bulk');
            if (cols) box.style.gridTemplateColumns = `repeat(${cols},1fr)`;
            defs.forEach(([label, fn]) => {
                const b = textEl('bm-btn', label, 'button');
                b.onclick = () => setAll(fn);
                box.append(b);
            });
            return box;
        };
        frag.append(
            textEl('hd-sec', l.hd_cats),
            bulk([[l.hd_p_min, c => HIDE_PRESETS.min.includes(c.id)], [l.hd_p_clean, c => HIDE_PRESETS.clean.includes(c.id)]], 2),
            bulk([[l.hd_all, () => true], [l.hd_off, () => false]], 2),
            textEl('hd-hint', l.hd_peek)
        );
        cats.forEach(c => {
            const row = this.catRow(c, cfg, l);
            rows.push({ c, row });
            frag.append(row);
        });
    }

    catRow(c, cfg, l) {
        const found = !!firstMatch(c);
        const pair = HIDE_L[AppState.lang]?.[c.id] || (AppState.lang === 'RU' ? [c.ru, c.dru] : [c.en, c.den]);
        const row = mk('div', `hd-row${catOn(c, cfg) ? ' on' : ''}${found ? '' : ' na'}`);
        const txt = mk('span', 'hd-txt');
        txt.append(textEl('', pair[0], 'b'));
        const desc = pair[1];
        if (desc) txt.append(textEl('', desc, 'small'));
        if (!found) txt.append(textEl('hd-na', l.hd_na, 'small'));
        row.append(txt, mk('span', 'hd-sw'));
        this.bindCatRow(row, c);
        return row;
    }

    bindCatRow(row, c) {
        let timer = null, peeking = false, savedY = 0;
        const peekOn = () => {
            const el = firstMatch(c);
            if (!el) return;
            peeking = true;
            savedY = window.scrollY;
            applyHideCSS(c.id);
            let st = document.getElementById('bc-unchained-peek');
            if (!st) { st = mk('style'); st.id = 'bc-unchained-peek'; (document.head || document.documentElement).appendChild(st); }
            st.textContent = c.sel.map(x => `${x}{outline:3px solid #ff2d95!important;outline-offset:-3px!important}`).join('\n');
            this.overlay.classList.add('peek');
            const r = el.getBoundingClientRect();
            if (r.bottom < 0 || r.top > window.innerHeight) el.scrollIntoView({ block: 'center' });
        };
        const peekOff = () => {
            clearTimeout(timer);
            if (!peeking) return;
            document.getElementById('bc-unchained-peek')?.remove();
            applyHideCSS();
            this.overlay.classList.remove('peek');
            if (Math.abs(window.scrollY - savedY) > 1) window.scrollTo(0, savedY);
            setTimeout(() => { peeking = false; }, 350);
        };
        row.addEventListener('pointerdown', () => { clearTimeout(timer); timer = setTimeout(peekOn, 450); });
        ['pointerup', 'pointercancel', 'pointerleave'].forEach(ev => row.addEventListener(ev, peekOff));
        row.addEventListener('contextmenu', e => e.preventDefault());
        row.onclick = () => {
            if (peeking) return;
            const cur = Store.get('bc_hide_cfg', {});
            cur[c.id] = !catOn(c, cur);
            Store.set('bc_hide_cfg', cur);
            row.classList.toggle('on', cur[c.id]);
            applyHideCSS();
        };
    }

    renderRules(frag, l) {
        frag.append(textEl('hd-sec', l.hd_rules));
        const rules = getCustom();
        if (!rules.length) return frag.append(textEl('hd-empty', l.hd_none));
        const clearAll = () => { setCustom([]); applyHideCSS(); this.render(); };
        rules.forEach(sel => {
            const row = mk('div', 'hd-row hd-rule');
            const t = textEl('hd-sel', sel, 'span');
            t.title = sel;
            const del = mk('button', 'bm-del');
            del.innerHTML = icons.del;
            del.onclick = () => { removeCustom(sel); applyHideCSS(); this.render(); };
            row.append(t, del);
            frag.append(row);
        });
        const clr = textEl('bm-btn', l.hd_clear, 'button');
        clr.onclick = clearAll;
        frag.append(clr);
    }
}

let HS_AV_TRIED = null, HS_AV_Q = Promise.resolve();
const HIST_CAP = 1000;
const histOn = () => Store.get('bc_hist_on', true) !== false;
const histLoad = () => {
    const h = Store.get('bc_hist', {});
    return {
        m: h && h.m && typeof h.m === 'object' && !Array.isArray(h.m) ? h.m : {},
        s: h && Array.isArray(h.s) ? h.s : []
    };
};
const pruneHistModels = (h, cap) => {
    const keys = Object.keys(h.m);
    if (keys.length > cap) { keys.sort((a, b) => h.m[a].l - h.m[b].l).slice(0, keys.length - cap).forEach(k => { delete h.m[k]; }); h.s = h.s.filter(x => h.m[x.k]); }
};
const histPos = v => (Number.isFinite(v) && v > 0 ? v : 0);
const mergeHistModel = (h, k, e) => {
    if (!e || !isStr(e.n) || !isStr(e.u)) return;
    const num = histPos, c = h.m[k];
    if (!c) { h.m[k] = { n: clip(e.n, 100), u: e.u, a: toHttps(e.a), s: num(e.s), v: num(e.v), f: num(e.f), l: num(e.l) }; return; }
    c.s = Math.max(c.s, num(e.s));
    c.v = Math.max(c.v, num(e.v));
    c.f = Math.min(c.f || Infinity, num(e.f) || Infinity);
    if (!Number.isFinite(c.f)) c.f = 0;
    if (num(e.l) > c.l) { c.l = num(e.l); c.n = clip(e.n, 100); c.u = e.u; if (e.a) c.a = toHttps(e.a); }
};
const mergeHistSessions = (h, list) => {
    const seen = new Set(h.s.map(x => `${x.k}|${x.t}`));
    (Array.isArray(list) ? list : []).forEach(x => {
        if (!x || !isStr(x.k) || !histPos(x.t) || seen.has(`${x.k}|${x.t}`)) return;
        h.s.push({ k: x.k, n: clip(x.n, 100), t: x.t, d: histPos(x.d) });
    });
};
const histMerge = src => {
    const h = histLoad();
    const m = src.m && typeof src.m === 'object' && !Array.isArray(src.m) ? src.m : {};
    Object.keys(m).forEach(k => mergeHistModel(h, k, m[k]));
    mergeHistSessions(h, src.s);
    h.s.sort((a, b) => a.t - b.t);
    if (h.s.length > HIST_CAP) h.s.splice(0, h.s.length - HIST_CAP);
    Store.set('bc_hist', h);
};
const fmtDur = sec => {
    const s = Math.max(0, Math.round(sec) || 0), h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60), p = n => String(n).padStart(2, '0');
    return h ? `${h}:${p(m)}:${p(s % 60)}` : `${m}:${p(s % 60)}`;
};
const fmtStamp = ts => {
    if (!ts) return '';
    const d = new Date(ts), p = n => String(n).padStart(2, '0');
    return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
};
const csvCell = v => {
    let s = String(v ?? '');
    if (s[0] === '-' && s.length <= 250 && !/[\r\n\t]/.test(s)) {
        return `"${`="${s.replace(/"/g, '""')}"`.replace(/"/g, '""')}"`;
    }
    if (/^[=+\-@\t\r]/.test(s)) s = `'${s}`;
    return `"${s.replace(/"/g, '""')}"`;
};
const csvText = rows => `\ufeff${rows.map(r => r.map(csvCell).join(',')).join('\r\n')}`;

const askConfirm = (ui, text, onYes) => {
    const ov = mk('div', 'cf-ov'), card = mk('div', 'cf-card'), btns = mk('div', 'cf-btns');
    const unbindEsc = bindEscape(() => close());
    const close = () => { ov.remove(); unbindEsc(); };
    const no = textEl('', L().cf_cancel, 'button'), yes = textEl('cf-yes', L().cf_ok, 'button');
    no.onclick = close;
    yes.onclick = () => { close(); onYes(); };
    btns.append(no, yes);
    card.append(textEl('cf-txt', text), btns);
    card.onclick = e => e.stopPropagation();
    ov.onclick = close;
    ov.append(card);
    ui.shadow.appendChild(ov);
};

class CalendarManager {
    constructor(ui, bm) {
        this.ui = ui;
        this.bm = bm;
        const now = new Date();
        this.y = now.getFullYear();
        this.m = now.getMonth();
        this.sel = this.dkey(now);
        Object.assign(this, CalendarManager.loadPrefs());
        this.pick = false;
        this.dd = null;
        this.wOpen = false;
        this.pane = mk('div', 'cal-pane');
        this.bm.modal.appendChild(this.pane);
        this.sk = '';
        this.sn = 0;
        setInterval(() => this.scan(), 8000);
        onRemoteChange('bc_hist', () => { if (this.isOpen()) this.render(); });
    }

    static loadPrefs() {
        const lay = Store.get('bc_cal_lay', 3);
        const wf = Store.get('bc_cal_wf', -1);
        const ms = Store.get('bc_cal_models', []);
        return {
            lay: Number.isInteger(lay) && lay >= 0 && lay <= 3 ? lay : 3,
            wf: [0, 1].includes(wf) ? wf : null,
            grp: Store.get('bc_cal_grp', '') || '',
            tag: Store.get('bc_cal_tag', '') || '',
            models: new Set(Array.isArray(ms) ? ms.filter(isStr) : [])
        };
    }

    scan() {
        const key = pageKey();
        if (!key || document.hidden) return;
        if (this.sk !== key) { this.sk = key; this.sn = 0; }
        if (this.sn >= 6) return;
        this.sn++;
        if (this.bm.scanPage()) this.sn = 99;
    }

    isOpen() { return this.bm.overlay.classList.contains('open') && this.bm.mode === 'cal'; }

    show() {
        this.render();
        this.bm.checkStatuses().then(() => { if (this.isOpen()) this.render(); }).catch(() => {});
        (async () => {
            for (let i = 0; i < 60 && this.isOpen(); i++) {
                const r = await this.bm.bgExtra(true);
                if (r === 'none') break;
                if (r === 'busy') { await new Promise(res => setTimeout(res, 1500)); continue; }
                if (r && this.isOpen()) this.render();
            }
        })();
    }

    dkey(d) { const p = n => String(n).padStart(2, '0'); return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`; }

    fmt(opts, d) {
        let s;
        try { s = new Intl.DateTimeFormat((AppState.lang || 'en').toLowerCase(), opts).format(d); }
        catch { s = new Intl.DateTimeFormat('en', opts).format(d); }
        return s;
    }

    cap(s) { return s ? s.charAt(0).toUpperCase() + s.slice(1) : s; }

    dur(sec) {
        const l = L();
        if (sec < 60) return fmtDur(sec);
        const m = Math.round(sec / 60), h = Math.floor(m / 60);
        return h ? `${h} ${l.u_h} ${m % 60} ${l.u_m}` : `${m} ${l.u_m}`;
    }

    ib(cls, svg, text, tag = 'button') {
        const e = mk(tag, cls);
        e.innerHTML = text ? `${svg}<span>${escHTML(text)}</span>` : svg;
        return e;
    }

    span(x) {
        const m = String(x).match(/^(\d{1,2}):(\d{2})-(\d{1,2}):(\d{2})/);
        if (!m) return [0, 0];
        const s = +m[1] * 60 + +m[2];
        let e = +m[3] * 60 + +m[4];
        if (e <= s) e = 1440;
        return [s, e];
    }

    hm(min) { const p = n => String(n).padStart(2, '0'); return `${p(Math.floor(min / 60))}:${p(min % 60)}`; }

    rangesText(r, l) {
        return r.split(',').map(x => {
            const [s, e] = this.span(x);
            return s === 0 && e >= 1440 ? l.cal_allday : `${this.hm(s)}\u2013${this.hm(e)}`;
        }).join(' \u00b7 ');
    }

    bar(r, nowMin) {
        const bar = mk('div', 'cal-bar');
        r.split(',').forEach(x => {
            const [s, e] = this.span(x);
            if (e <= s) return;
            const seg = mk('i', 'cal-seg');
            seg.style.left = `${s / 14.4}%`;
            seg.style.width = `${Math.max((e - s) / 14.4, 1)}%`;
            bar.append(seg);
        });
        if (nowMin != null) { const n = mk('i', 'cal-now'); n.style.left = `${nowMin / 14.4}%`; bar.append(n); }
        return bar;
    }

    startMin(r) { const m = String(r).match(/^(\d{1,2}):(\d{2})/); return m ? +m[1] * 60 + +m[2] : 0; }

    favs(hist) {
        return AppState.bookmarks.filter(b => isObj(b) && isStr(b.url)
            && (this.wf == null || bmWatch(b, hist) === this.wf)
            && (!this.grp || b.g === this.grp)
            && bmTagMatch(b, this.tag)
            && (!this.models.size || this.models.has(bmKey(b.url))));
    }

    filtersOn() { return this.wf != null || !!this.grp || !!this.tag || this.models.size > 0; }

    collect() {
        const hist = histLoad();
        const favs = this.favs(hist), fk = new Set(favs.map(b => bmKey(b.url)));
        const on = this.filtersOn();
        const sess = (this.lay & 1) ? this.groupSessions(hist, on, fk) : new Map();
        const sched = (this.lay & 2) ? this.buildSched(favs) : [[], [], [], [], [], [], []];
        const anySched = AppState.bookmarks.some(b => Array.isArray(b.sch) && b.sch.some(x => this.clean(x)));
        return { hist, sess, sched, anySched };
    }

    groupSessions(hist, on, fk) {
        const sess = new Map();
        for (const s of hist.s) {
            if (on && !fk.has(s.k)) continue;
            const dk = this.dkey(new Date(s.t));
            if (!sess.has(dk)) sess.set(dk, []);
            sess.get(dk).push(s);
        }
        return sess;
    }

    buildSched(favs) {
        const sched = [[], [], [], [], [], [], []];
        for (const b of favs) if (Array.isArray(b.sch)) b.sch.forEach((x, i) => {
            const r = this.clean(x);
            if (r && i < 7) sched[i].push({ b, r, s: this.startMin(r) });
        });
        sched.forEach(a => a.sort((x, y) => x.s - y.s));
        return sched;
    }

    clean(r) {
        return String(r || '').split(',').filter(x => {
            const m = x.match(/^(\d{1,2}):(\d{2})-(\d{1,2}):(\d{2})/);
            return m && !(+m[1] === +m[3] && m[2] === m[4]);
        }).join(',');
    }

    shift(d) { const x = new Date(this.y, this.m + d, 1); this.y = x.getFullYear(); this.m = x.getMonth(); this.render(); }

    save(k, v) { Store.set(k, v); this.render(); }

    render() {
        const l = L(), { hist, sess, sched, anySched } = this.collect();
        const pane = this.pane, keepTop = pane.scrollTop;
        pane.replaceChildren();
        pane.append(this.renderHead(l));
        pane.append(this.renderFilters(l, hist));
        const now = new Date(), tk = this.dkey(now);
        pane.append(this.renderGrid(sess, sched, now, tk));
        pane.append(this.renderDetail(l, hist, sess, sched, anySched, now, tk));
        pane.scrollTop = keepTop;
    }

    renderHead(l) {
        const head = mk('div', 'cal-head');
        const prev = this.ib('cal-nav', icons.chevL, ''), next = this.ib('cal-nav', icons.chevR, '');
        prev.onclick = () => this.shift(-1);
        next.onclick = () => this.shift(1);
        const today = textEl('cal-today', l.cal_today, 'button');
        today.onclick = () => { const n = new Date(); this.y = n.getFullYear(); this.m = n.getMonth(); this.sel = this.dkey(n); this.render(); };
        head.append(prev, textEl('cal-title', this.cap(this.fmt({ month: 'long', year: 'numeric' }, new Date(this.y, this.m, 1)))), next, today);
        return head;
    }

    filterRow1(l) {
        const r1 = mk('div', 'cal-frow');
        const layers = mk('div', 'bm-seg');
        [[1, icons.eye, l.cal_hist], [2, icons.clock, l.cal_sched]].forEach(([bit, ic, t]) => {
            const b = this.ib(`bm-tbtn${this.lay & bit ? ' on' : ''}`, ic, t);
            b.onclick = () => { const v = this.lay ^ bit; this.lay = v; this.save('bc_cal_lay', v); };
            layers.append(b);
        });
        const wseg = mk('div', 'bm-seg');
        WMARKS.forEach(([v, ic, key]) => {
            const b = this.ib(`bm-tbtn${this.wf === v ? ' on' : ''}`, icons[ic], l[key]);
            b.title = l[key];
            b.onclick = () => { this.wf = this.wf === v ? null : v; this.save('bc_cal_wf', this.wf == null ? -1 : this.wf); };
            wseg.append(b);
        });
        r1.append(layers, wseg);
        return r1;
    }

    mkDD(kind, icon, label, on) {
        const b = this.ib(`cal-dd${on ? ' on' : ''}${this.dd === kind ? ' open' : ''}`, icon, label);
        b.onclick = () => { this.dd = this.dd === kind ? null : kind; this.pick = false; this.render(); };
        return b;
    }

    mkPanel(opts, cur, set) {
        const box = mk('div', 'cal-panel');
        opts.forEach(o => {
            if (o.sep) { box.append(mk('div', 'cal-sep')); return; }
            const c = this.ib(`cal-opt${o.v === cur ? ' on' : ''}${o.all ? ' all' : ''}`, o.ic || '', o.t);
            if (o.n) c.insertAdjacentHTML('beforeend', `<i>${o.n}</i>`);
            c.onclick = () => { this.dd = null; set(o.v); };
            box.append(c);
        });
        return box;
    }

    grpDropdown(l, r2) {
        const groups = bmGroups();
        if (this.grp && !groups.includes(this.grp)) this.grp = '';
        if (!groups.length) return null;
        r2.append(this.mkDD('grp', icons.folder, this.grp || l.grp_all, !!this.grp));
        if (this.dd !== 'grp') return null;
        return this.mkPanel([{ v: '', t: l.grp_all, all: true }, ...groups.map(g => ({ v: g, t: g }))], this.grp, v => { this.grp = v; this.save('bc_cal_grp', v); });
    }

    countTags(hidePT) {
        const noteTags = new Map(), profTags = new Map();
        AppState.bookmarks.forEach(b => {
            noteHashTags(b).forEach(x => countInto(noteTags, x));
            if (!hidePT) (b.ptags || []).forEach(x => countInto(profTags, x));
        });
        return { noteTags, profTags };
    }

    tagDropdown(l, r2) {
        const hidePT = Store.get('bc_bm_hide_ptags', false) === true;
        const pim = ptIcoMap();
        const { noteTags, profTags } = this.countTags(hidePT);
        if (this.tag && !noteTags.has(this.tag) && !profTags.has(this.tag)) this.tag = '';
        if (!noteTags.size && !profTags.size) return null;
        r2.append(this.mkDD('tag', ptImg(pim.get(this.tag), 'cal-tic') || icons.tag, this.tag || l.cal_all_tag, !!this.tag));
        if (this.dd !== 'tag') return null;
        const srt = m => [...m.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([v, n]) => ({ v, t: v, n, ic: ptImg(pim.get(v), 'cal-tic') }));
        return this.mkPanel([
            { v: '', t: l.cal_all_tag, all: true },
            ...srt(noteTags),
            ...(noteTags.size && profTags.size ? [{ sep: true }] : []),
            ...srt(profTags)
        ], this.tag, v => { this.tag = v; this.save('bc_cal_tag', v); });
    }

    modelPicker(l, hist) {
        const box = mk('div', 'cal-models');
        if (this.models.size) {
            const rs = this.ib('cal-mrow reset', icons.undo, l.cal_reset);
            rs.onclick = () => { this.models.clear(); this.save('bc_cal_models', []); };
            box.append(rs);
        }
        const nk = s => String(s).replace(/^[^\p{L}\p{N}]+/u, '');
        AppState.bookmarks.filter(b => isObj(b) && isStr(b.url)).slice()
            .sort((a, b) => nk(a.name).localeCompare(nk(b.name), undefined, { sensitivity: 'base', numeric: true }))
            .forEach(b => {
                const k = bmKey(b.url), on = this.models.has(k);
                const r = mk('button', `cal-mrow${on ? ' on' : ''}`);
                const img = mk('img', 'cal-ava sm');
                bindAvatar(img, b.name, () => [toHttps(b.avatar), toHttps(hist.m[k]?.a)]);
                r.append(img, textEl('', b.name, 'span'));
                if (on) r.insertAdjacentHTML('beforeend', icons.check);
                r.onclick = () => { if (on) this.models.delete(k); else this.models.add(k); this.save('bc_cal_models', [...this.models]); };
                box.append(r);
            });
        return box;
    }

    renderFilters(l, hist) {
        const flt = mk('div', 'cal-filters');
        const r2 = mk('div', 'cal-frow');
        const grpPanel = this.grpDropdown(l, r2);
        const tagPanel = this.tagDropdown(l, r2);
        const ddPanel = tagPanel || grpPanel;
        flt.append(this.filterRow1(l));
        if (r2.children.length) flt.append(r2);
        if (ddPanel) flt.append(ddPanel);
        const mb = textEl(`cal-pill${this.models.size ? ' on' : ''}`, `${l.cal_models}${this.models.size ? ` (${this.models.size})` : ''}`, 'button');
        mb.onclick = () => { this.pick = !this.pick; this.dd = null; this.render(); };
        const r3 = mk('div', 'cal-frow');
        r3.append(mb);
        flt.append(r3);
        if (this.pick) flt.append(this.modelPicker(l, hist));
        return flt;
    }

    renderGrid(sess, sched, now, tk) {
        const grid = mk('div', 'cal-grid');
        for (let i = 0; i < 7; i++) grid.append(textEl('cal-wd', this.fmt({ weekday: 'short' }, new Date(2024, 0, 1 + i))));
        const first = new Date(this.y, this.m, 1), off = (first.getDay() + 6) % 7, dim = new Date(this.y, this.m + 1, 0).getDate();
        const t0 = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
        for (let i = 0; i < off; i++) grid.append(mk('div', 'cal-day blank'));
        for (let d = 1; d <= dim; d++) grid.append(this.dayCell(d, sess, sched, tk, t0));
        return grid;
    }

    dayCell(d, sess, sched, tk, t0) {
        const dt = new Date(this.y, this.m, d), key = this.dkey(dt), wd = (dt.getDay() + 6) % 7;
        const cell = mk('button', `cal-day${key === tk ? ' today' : ''}${key === this.sel ? ' sel' : ''}${dt.getTime() < t0 ? ' past' : ''}`);
        cell.type = 'button';
        cell.append(textEl('cal-n', String(d), 'span'));
        const bs = mk('div', 'cal-bs'), sn = new Set((sess.get(key) || []).map(s => s.k)).size, sc = sched[wd].length;
        if (sn) bs.append(textEl('cal-b', String(sn), 'i'));
        if (sc) bs.append(textEl('cal-b s', String(sc), 'i'));
        cell.append(bs);
        cell.onclick = () => { this.sel = key; this.render(); };
        return cell;
    }

    watchedBox(l, hist, sess, ctx) {
        const wbox = mk('div', 'cal-wsec');
        const agg = new Map();
        (sess.get(this.sel) || []).forEach(s => {
            const e = agg.get(s.k) || { k: s.k, n: s.n, first: s.t, d: 0, c: 0 };
            e.d += s.d || 0;
            e.c++;
            e.first = Math.min(e.first, s.t);
            agg.set(s.k, e);
        });
        const list = [...agg.values()].sort((a, b) => a.first - b.first);
        const total = list.reduce((s, x) => s + x.d, 0);
        const fh = this.ib(`cal-sec cal-fold${this.wOpen ? ' open' : ''}`, '', `${l.cal_watched}${total ? ` · ${this.dur(total)}` : ''}`);
        fh.onclick = () => { this.wOpen = !this.wOpen; this.render(); };
        wbox.append(fh);
        if (!this.wOpen) return wbox;
        if (!list.length) wbox.append(textEl('cal-muted', l.cal_none));
        else wbox.append(this.watchedTable(l, hist, list, total, ctx));
        return wbox;
    }

    watchedTable(l, hist, list, total, { favMap, href, ava }) {
        const p2 = n => String(n).padStart(2, '0');
        const tbl = mk('div', 'cal-tbl');
        const hd = mk('div', 'cal-trow cal-thead');
        [l.cal_c_model, l.cal_c_time, l.cal_c_dur, l.cal_c_n].forEach(x => hd.append(textEl('', x, 'span')));
        tbl.append(hd);
        list.forEach(e => {
            const b = favMap.get(e.k), row = mk('div', 'cal-trow'), name = b ? b.name : e.n;
            const who = mk('div', 'cal-who');
            const a = textEl('', name, 'a');
            a.href = href(b ? b.url : hist.m[e.k]?.u);
            who.append(ava(b, e.k, name), a);
            const t = new Date(e.first);
            row.append(who, textEl('', `${p2(t.getHours())}:${p2(t.getMinutes())}`, 'span'), textEl('', this.dur(e.d), 'span'), textEl('', `×${e.c}`, 'span'));
            tbl.append(row);
        });
        const ft = mk('div', 'cal-trow cal-tfoot');
        ft.append(textEl('', `${l.cal_total} · ${list.length}`, 'span'), textEl('', '', 'span'), textEl('', this.dur(total), 'span'), textEl('', `×${list.reduce((s, x) => s + x.c, 0)}`, 'span'));
        tbl.append(ft);
        return tbl;
    }

    schedRow(l, b, r, nowMin, { href, ava }) {
        const row = mk('div', 'cal-row'), line = mk('div', 'cal-line'), body = mk('div', 'cal-body');
        if (nowMin != null && (b.status ?? 0) > 0) line.append(mk('span', 'cal-dot'));
        const a = textEl('', b.name, 'a');
        a.href = href(b.url);
        line.append(a, textEl('cal-t', this.rangesText(r, l), 'span'));
        body.append(line, this.bar(r, nowMin));
        row.append(ava(b, bmKey(b.url), b.name), body);
        return row;
    }

    appendSched(det, l, list, anySched, nowMin, ctx) {
        det.append(textEl('cal-sec', l.cal_sched));
        if (!list.length) det.append(textEl('cal-muted', anySched ? l.cal_none : l.cal_no_sched));
        else {
            const ax = mk('div', 'cal-axis');
            ['00', '06', '12', '18', '24'].forEach(h => ax.append(textEl('', h, 'span')));
            det.append(ax);
        }
        list.forEach(({ b, r }) => det.append(this.schedRow(l, b, r, nowMin, ctx)));
        const bc = AppState.bookmarks.filter(b => isObj(b) && isStr(b.url) && urlSite(b.url) === 'bc');
        const got = bc.filter(b => Array.isArray(b.sch)).length;
        if (bc.length && got < bc.length) det.append(textEl('cal-muted', l.cal_loaded.replace('{a}', got).replace('{b}', bc.length)));
    }

    renderDetail(l, hist, sess, sched, anySched, now, tk) {
        const sp = this.sel.split('-').map(Number), sd = new Date(sp[0], sp[1] - 1, sp[2]), swd = (sd.getDay() + 6) % 7;
        const det = mk('div', 'cal-det');
        det.append(textEl('cal-dtitle', this.cap(this.fmt({ weekday: 'long', day: 'numeric', month: 'long' }, sd))));
        const favMap = new Map(AppState.bookmarks.filter(b => isObj(b) && isStr(b.url)).map(b => [bmKey(b.url), b]));
        const href = u => (u && isSafeUrl(u) ? linkFor(u) : '#');
        const ava = (b, k, name) => {
            const img = mk('img', 'cal-ava');
            bindAvatar(img, name, () => [toHttps(b?.avatar), toHttps(hist.m[k]?.a)]);
            return img;
        };
        const ctx = { favMap, href, ava };
        const wbox = (this.lay & 1) ? this.watchedBox(l, hist, sess, ctx) : null;
        if (this.lay & 2) {
            const nowMin = this.sel === tk ? now.getHours() * 60 + now.getMinutes() : null;
            this.appendSched(det, l, sched[swd], anySched, nowMin, ctx);
        }
        if (wbox) det.append(wbox);
        return det;
    }
}

class HistoryManager {
    constructor(ui, bookmarks) {
        this.ui = ui;
        this.bm = bookmarks;
        this.cur = null;
        this.pend = 0;
        this.fresh = false;
        this.lastTick = Date.now();
        const sort = Store.get('bc_hist_sort', 'last');
        this.sort = ['last', 'time', 'visits'].includes(sort) ? sort : 'last';
        this.build();
        setInterval(() => this.tick(), 5000);
        onPageEvent('pagehide', () => this.endSession(), window);
        onPageEvent('visibilitychange', () => { if (realHidden()) this.flush(); });
        onRemoteChange('bc_hist', () => { if (this.isOpen()) this.render(); });
    }

    build() {
        this.list = mk('div', 'hs-pane');
        this.bm.modal.appendChild(this.list);
    }

    isOpen() {
        return this.bm.overlay.classList.contains('open') && this.bm.mode === 'hist';
    }

    show() {
        this.flush();
        this.render();
    }

    open() {
        this.bm.open('hist');
    }

    hide() {
        this.bm.hide();
    }

    updateLabels() {
        if (this.isOpen()) this.render();
    }

    tick() {
        const now = Date.now(), dt = Math.min(65, (now - this.lastTick) / 1000);
        this.lastTick = now;
        if (!histOn()) return;
        const key = pageKey(), name = key ? currentSite.getName() : '';
        if (!key || !name) { this.endSession(); return; }
        this.ensureSession(key, name, now);
        if (isPlaying(selectorVideo())) this.pend += dt;
        if (this.pend >= 15) this.flush();
    }

    ensureSession(key, name, now) {
        if (!this.cur || this.cur.k !== key) {
            this.endSession();
            this.cur = { k: key, t: now, name, url: normUrl(location.href), avatar: '' };
            this.fresh = true;
        }
        this.cur.name = name;
        if (!this.cur.avatar) this.cur.avatar = toHttps(pageAvatar(name)) || AppState.bookmarks.find(b => bmKey(b.url) === key)?.avatar || '';
    }

    flush() {
        const c = this.cur, secs = Math.round(this.pend);
        if (!c || secs < 1) return;
        this.pend = 0;
        const h = histLoad();
        this.recordSession(h, c, secs, Date.now());
        if (h.s.length > HIST_CAP) h.s.splice(0, h.s.length - HIST_CAP);
        pruneHistModels(h, 2000);
        Store.set('bc_hist', h);
        if (this.isOpen()) this.render();
    }

    recordSession(h, c, secs, now) {
        const e = h.m[c.k] || (h.m[c.k] = { n: c.name, u: c.url, a: '', s: 0, v: 0, f: c.t, l: c.t });
        e.n = c.name;
        e.u = c.url;
        if (c.avatar) e.a = c.avatar;
        e.s += secs;
        e.l = now;
        if (this.fresh) { e.v++; this.fresh = false; }
        let s = h.s.find(x => x.k === c.k && x.t === c.t);
        if (!s) { s = { k: c.k, n: c.name, t: c.t, d: 0 }; h.s.push(s); }
        s.d += secs;
    }

    endSession() {
        this.flush();
        this.cur = null;
        this.pend = 0;
    }

    remove(k) {
        const h = histLoad();
        delete h.m[k];
        h.s = h.s.filter(x => x.k !== k);
        Store.set('bc_hist', h);
        if (this.cur?.k === k) { this.cur = null; this.pend = 0; }
        this.render();
    }

    clear() {
        askConfirm(this.ui, L().hist_clear_q, () => {
            Store.set('bc_hist', { m: {}, s: [] });
            this.cur = null;
            this.pend = 0;
            this.render();
        });
    }

    exportCsv(sessions) {
        const h = histLoad();
        const rows = sessions
            ? [['name', 'url', 'start', 'seconds', 'duration'],
                ...h.s.slice().sort((a, b) => b.t - a.t).map(x => [x.n, h.m[x.k]?.u || '', fmtStamp(x.t), x.d, fmtDur(x.d)])]
            : [['name', 'url', 'seconds', 'duration', 'visits', 'first_seen', 'last_seen'],
                ...Object.keys(h.m).map(k => h.m[k]).sort((a, b) => b.l - a.l).map(e => [e.n, e.u, e.s, fmtDur(e.s), e.v, fmtStamp(e.f), fmtStamp(e.l)])];
        Helpers.download(new Blob([csvText(rows)], { type: 'text/csv;charset=utf-8' }), `BC_${sessions ? 'Sessions' : 'History'}_${Helpers.getTimestamp().slice(0, 10)}.csv`);
    }

    loadAvatar(e, img) {
        HS_AV_TRIED ||= new Set();
        if (!e.u || HS_AV_TRIED.has(e.k)) return;
        HS_AV_TRIED.add(e.k);
        HS_AV_Q = HS_AV_Q.then(async () => {
            const av = extractAvatar((await withBackoff(() => requestOnce(e.u))) || '');
            if (!av) return;
            const h = histLoad();
            if (h.m[e.k]) { h.m[e.k].a = av; Store.set('bc_hist', h); }
            if (img.isConnected) bindAvatar(img, e.n || '?', () => [av]);
        }).catch(() => {});
    }

    row(e, l) {
        const row = mk('div', 'hs-row');
        const img = mk('img', 'hs-ava');
        bindAvatar(img, e.n || '?', () => {
            const bmk = AppState.bookmarks.find(x => bmKey(x.url) === e.k);
            return [toHttps(e.a), toHttps(bmk?.avatar)];
        }, () => this.loadAvatar(e, img));
        const info = mk('div', 'hs-info');
        info.append(textEl('hs-name', e.n || e.k), textEl('hs-meta', `${fmtDur(e.s)} · ${e.v} ${l.hist_visits} · ${fmtAgo(e.l)}`));
        const fav = isFavKey(e.k);
        const favBtn = mk('button', `hs-btn${fav ? ' on' : ''}`);
        favBtn.innerHTML = icons.star;
        favBtn.title = fav ? l.star_del : l.star_add;
        favBtn.onclick = ev => {
            ev.stopPropagation();
            if (fav) return this.bm.removeKey(e.k, () => this.render());
            this.bm.addEntry({ name: e.n, url: e.u, avatar: e.a });
            this.render();
        };
        const delBtn = mk('button', 'hs-btn del');
        delBtn.innerHTML = icons.del;
        delBtn.title = l.hist_del;
        delBtn.onclick = ev => { ev.stopPropagation(); this.remove(e.k); };
        row.onclick = () => { if (isSafeUrl(e.u)) location.href = linkFor(e.u); };
        row.append(img, info, favBtn, delBtn);
        return row;
    }

    vbars(vals, labels, tips) {
        const max = Math.max(...vals, 1), bars = mk('div', 'ch-bars'), axis = mk('div', 'ch-axis');
        vals.forEach((v, i) => {
            const col = mk('div', 'ch-col'), bar = mk('div', `ch-bar${v > 0 ? '' : ' zero'}`);
            bar.style.height = `${v > 0 ? Math.max(3, Math.round(v / max * 100)) : 0}%`;
            col.title = tips[i];
            col.append(bar);
            bars.append(col);
            axis.append(textEl('', labels[i], 'span'));
        });
        return [bars, axis];
    }

    charts(h, entries, l) {
        const DAY = 864e5, HOUR = 36e5, now = Date.now();
        const base = new Date(); base.setHours(0, 0, 0, 0);
        const start0 = base.getTime() - 13 * DAY;
        const days = new Array(14).fill(0), hours = new Array(24).fill(0);
        h.s.forEach(x => {
            let a = x.t, rem = x.d * 1000;
            while (rem > 0 && a <= now + DAY) {
                const dt = new Date(a), hs = new Date(a);
                hs.setMinutes(0, 0, 0);
                const part = Math.min(rem, hs.getTime() + HOUR - a);
                hours[dt.getHours()] += part;
                dt.setHours(0, 0, 0, 0);
                const di = Math.round((dt.getTime() - start0) / DAY);
                if (di >= 0 && di < 14) days[di] += part;
                a += part;
                rem -= part;
            }
        });
        const sec = ms => Math.round(ms / 1000);
        const box = (title, extra) => {
            const b = mk('div', 'ch-box'), t = mk('div', 'ch-ttl');
            t.append(textEl('', title, 'span'));
            if (extra) t.append(textEl('', extra, 'span'));
            b.append(t);
            return b;
        };
        const wrap = document.createDocumentFragment();

        const dayLbl = days.map((_, i) => new Date(start0 + i * DAY + DAY / 2).getDate());
        const dayTip = days.map((v, i) => `${this.dayName(start0 + i * DAY + DAY / 2)}: ${fmtDur(sec(v))}`);
        const avg = days.reduce((a, v) => a + v, 0) / 14;
        const b1 = box(l.ch_days, `${l.ch_avg}: ${fmtDur(sec(avg))}`);
        b1.append(...this.vbars(days, dayLbl, dayTip));
        wrap.append(b1);

        const hMax = Math.max(...hours);
        const peak = hMax > 0 ? hours.indexOf(hMax) : -1;
        const hrLbl = hours.map((_, i) => (i % 6 === 0 ? String(i) : ''));
        const hrTip = hours.map((v, i) => `${String(i).padStart(2, '0')}:00: ${fmtDur(sec(v))}`);
        const b2 = box(l.ch_hours, peak >= 0 ? `${l.ch_peak}: ${String(peak).padStart(2, '0')}:00` : '');
        b2.append(...this.vbars(hours, hrLbl, hrTip));
        wrap.append(b2);

        const top = entries.slice().sort((x, y) => y.s - x.s).slice(0, 5);
        if (top.length) {
            const b3 = box(l.ch_top), tMax = Math.max(top[0].s, 1);
            top.forEach(e => {
                const row = mk('div', 'ch-row'), track = mk('div', 'ch-track'), fill = mk('div', 'ch-fill');
                fill.style.width = `${Math.max(2, Math.round(e.s / tMax * 100))}%`;
                track.append(fill);
                row.append(textEl('ch-name', e.n || e.k, 'span'), track, textEl('ch-val', fmtDur(e.s), 'span'));
                b3.append(row);
            });
            wrap.append(b3);
        }
        return wrap;
    }

    dayName(ts) {
        try { return new Date(ts).toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }); } catch { return ''; }
    }

    render() {
        const l = L(), h = histLoad(), keep = this.list.scrollTop;
        const entries = Object.keys(h.m).map(k => ({ k, ...h.m[k] }));
        const total = entries.reduce((a, e) => a + e.s, 0);
        const cmps = {
            last: (x, y) => y.l - x.l,
            time: (x, y) => y.s - x.s,
            visits: (x, y) => (y.v - x.v) || (y.s - x.s)
        };
        entries.sort(cmps[this.sort]);
        const frag = document.createDocumentFragment();
        const sorts = mk('div', 'st-chips');
        [['last', l.hist_s_last], ['time', l.hist_s_time], ['visits', l.hist_s_vis]].forEach(([id, t]) => {
            const b = textEl(`bm-tbtn${this.sort === id ? ' on' : ''}`, t, 'button');
            b.onclick = () => { this.sort = id; Store.set('bc_hist_sort', id); this.render(); };
            sorts.append(b);
        });
        const chOn = Store.get('bc_hist_ch', false) === true;
        const chBtn = textEl(`bm-tbtn${chOn ? ' on' : ''}`, l.ch_btn, 'button');
        chBtn.onclick = () => { Store.set('bc_hist_ch', !chOn); this.render(); };
        sorts.append(mk('span', 'hs-sep'), chBtn);
        const clr = mk('button', 'bm-tbtn hs-clear');
        clr.innerHTML = icons.del;
        clr.append(textEl('', l.hist_clear, 'span'));
        clr.onclick = () => this.clear();
        const top = mk('div', 'st-chips hs-top');
        top.append(textEl('hd-hint', l.hist_total.replace('{n}', entries.length).replace('{t}', fmtDur(total))), clr);
        frag.append(top, sorts);
        if (!entries.length) frag.append(textEl('bm-empty', l.hist_empty));
        else if (chOn) frag.append(this.charts(h, entries, l));
        entries.slice(0, 300).forEach(e => frag.append(this.row(e, l)));
        this.list.replaceChildren(frag);
        this.list.scrollTop = keep;
    }
}

const STAR_SVG = '<svg viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>';
const THUMB_CFG = {
    bc: { links: ['a.thm_a', 'a.lst_link'], box: '.mls_item, .ls_thumb', views: '.bage_viewers, .lst_viewers', name: '' },
    sc: { links: ['a[data-model-list-link="true"]'], box: '[data-testid="model-list-item"]', views: '[class*="iewers"]', name: '[data-testid="model-list-item-username"]' },
    cb: { links: ['a.RoomCardThumbnail', 'a[data-testid="room-card-image-anchor"]'], box: '.RoomCard, li.room_list_room, li.roomCard', views: '.viewers', name: '[data-testid="room-card-username"], .username a' }
}[SITE] || { links: [], box: '', views: '', name: '' };
const THUMB_LINKS = THUMB_CFG.links;
const THUMB_BOX = THUMB_CFG.box;
const viewersOf = a => {
    const t = THUMB_CFG.views ? ((THUMB_BOX && a.closest(THUMB_BOX)) || a).querySelector(THUMB_CFG.views)?.textContent || '' : '';
    const n = parseCount(t);
    return Number.isFinite(n) ? n : null;
};

class ThumbStars {
    constructor(bookmarks) {
        this.bm = bookmarks;
        this.on = Store.get('bc_star', true) !== false;
        this.timer = 0;
        const st = document.createElement('style');
        st.id = 'bcu-star-css';
        st.textContent = STAR_CSS;
        (document.head || document.documentElement).appendChild(st);
        this.bindGlobal();
        const resync = () => {
            try { syncBookmarks(); } catch {}
            this.scan();
        };
        window.addEventListener('pageshow', e => { if (e.persisted) resync(); });
        onPageEvent('visibilitychange', () => { if (!realHidden()) resync(); });
        this.mo = new MutationObserver(recs => { if (!onlyOwnNodes(recs)) this.schedule(); });
        this.mo.observe(document.documentElement, { childList: true, subtree: true });
        setInterval(() => { if (!document.hidden) { this.scan(); this.checkPage(); } }, 2500);
        this.schedule();
    }

    checkPage() {
        const key = pageKey();
        if (!key || !isFavKey(key)) return;
        const v = document.querySelector('video');
        if (v && isPlaying(v)) this.bm.markLive(key);
    }

    bindGlobal() {
        const starOf = e => (e.target && e.target.closest ? e.target.closest('.bcu-star') : null);
        const opt = { capture: true, passive: false };
        let down = null;
        const fire = star => {
            const a = star.parentElement;
            if (a) this.toggle(a);
        };
        const block = e => { e.stopImmediatePropagation(); e.stopPropagation(); if (e.cancelable) e.preventDefault(); };
        ['mousedown', 'mouseup', 'dblclick', 'auxclick', 'contextmenu'].forEach(t =>
            window.addEventListener(t, e => { if (starOf(e)) block(e); }, opt));
        ['touchstart', 'touchend', 'touchmove'].forEach(t =>
            window.addEventListener(t, e => { if (starOf(e)) { e.stopImmediatePropagation(); e.stopPropagation(); } }, { capture: true, passive: true }));
        window.addEventListener('pointerdown', e => {
            const st = starOf(e); if (!st) return;
            down = { st, x: e.clientX, y: e.clientY };
            block(e);
        }, opt);
        window.addEventListener('pointerup', e => {
            const st = starOf(e); if (!st) return;
            block(e);
            const ok = down && down.st === st && Math.abs(e.clientX - down.x) < 12 && Math.abs(e.clientY - down.y) < 12;
            down = null;
            if (!ok || (e.button != null && e.button > 0)) return;
            st._t = Date.now();
            fire(st);
        }, opt);
        window.addEventListener('click', e => {
            const st = starOf(e); if (!st) return;
            block(e);
            if (Date.now() - (st._t || 0) > 800) fire(st);
        }, opt);
    }

    schedule() {
        if (this.timer || !this.on) return;
        this.timer = setTimeout(() => { this.timer = 0; this.scan(); }, 350);
    }

    setEnabled(v) {
        this.on = !!v;
        Store.set('bc_star', this.on);
        if (this.on) return this.scan();
        document.querySelectorAll('.bcu-star,.bcu-ring').forEach(x => x.remove());
        THUMB_LINKS.forEach(sel => document.querySelectorAll(sel).forEach(a => { a._bcu = null; a.classList.remove('bcu-fav'); }));
    }

    scan() {
        if (!this.on) return;
        const idx = new Map(AppState.bookmarks.map(b => [bmKey(b.url), b]));
        const links = THUMB_LINKS.flatMap(sel => [...document.querySelectorAll(sel)]);
        const pos = links.map(a => (a._bcu ? null : getComputedStyle(a).position));
        links.forEach((a, i) => this.sync(a, idx, pos[i]));
    }

    keyOf(a) {
        const s = modelSlug(a.href);
        return s ? `${SITE}|${s.toLowerCase()}` : '';
    }

    sync(a, idx, pos) {
        const key = this.keyOf(a);
        if (!key) return;
        const st = this.ensureStar(a, key, pos);
        const b = idx.get(key);
        this.paintFav(a, st, !!b);
        if (b) this.syncViewers(a, key, b);
    }

    ensureStar(a, key, pos) {
        const st = a._bcu;
        if (st && st.key === key && st.star.isConnected) return st;
        if (st) { st.star.remove(); st.ring.remove(); }
        return (a._bcu = this.make(a, key, pos ?? getComputedStyle(a).position));
    }

    paintFav(a, st, fav) {
        if (st.fav !== fav) {
            st.fav = fav;
            st.star.classList.toggle('on', fav);
            a.classList.toggle('bcu-fav', fav);
        }
        const tip = fav ? L().star_del : L().star_add;
        if (st.star.title !== tip) st.star.title = tip;
    }

    syncViewers(a, key, b) {
        const n = viewersOf(a);
        if (n == null) return;
        this.bm.markLive(key, b);
        if (n !== b.viewers) this.bm.setViewers(key, n, b);
    }

    make(a, key, pos) {
        if (pos === 'static') a.classList.add('bcu-host');
        const ring = document.createElement('span');
        ring.className = 'bcu-ring';
        const star = document.createElement('span');
        star.className = 'bcu-star';
        star.setAttribute('role', 'button');
        star.innerHTML = STAR_SVG;
        ['pointerdown', 'pointerup', 'mousedown', 'mouseup', 'touchstart', 'touchend', 'dblclick', 'contextmenu'].forEach(ev => star.addEventListener(ev, e => e.stopPropagation()));
        star.addEventListener('click', e => {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            this.toggle(a);
        });
        a.append(ring, star);
        return { key, star, ring, fav: null };
    }

    thumbImg(a) {
        return a.querySelector('img:not([class*="Blur"])') || a.querySelector('img');
    }

    attrName(a) {
        return a.getAttribute('data-name') || a.dataset.room || a.closest('[data-name]')?.getAttribute('data-name');
    }

    boxName(a) {
        const box = THUMB_BOX ? a.closest(THUMB_BOX) : null;
        return THUMB_CFG.name && box?.querySelector(THUMB_CFG.name)?.textContent.trim();
    }

    thumbName(a, img) {
        return this.attrName(a) || this.boxName(a) || (IS_BC && img?.alt) || modelSlug(a.href);
    }

    toggle(a) {
        const key = this.keyOf(a);
        if (!key) return;
        if (isFavKey(key)) return this.bm.removeKey(key, () => this.scan());
        const img = this.thumbImg(a);
        this.bm.addEntry({ name: this.thumbName(a, img), url: a.href, avatar: '', viewers: viewersOf(a) });
        this.scan();
    }
}

const THEME_SWATCHES = ['rgba(220, 20, 60, 0.9)', 'rgba(233, 30, 99, 0.9)', 'rgba(156, 39, 176, 0.9)', 'rgba(63, 81, 181, 0.9)', 'rgba(3, 155, 229, 0.9)', 'rgba(0, 150, 136, 0.9)', 'rgba(67, 160, 71, 0.9)', 'rgba(245, 124, 0, 0.9)', 'rgba(96, 125, 139, 0.9)'];
const TILE_ICONS = {
    bBg: 'bgOn', bMute: 'vol', bShot: 'snap', bRec: 'rec', vol: 'volMed', bQual: 'qual', bPip: 'pip', bFs: 'fs', bThtr: 'thtr',
    bSearch: 'search', bHls: 'hls', bCopy: 'copy', bFav: 'fav', stats: 'eye', bHome: 'home', bRel: 'rel',
    bColor: 'color', bHideMgr: 'eyeOff', scale: 'grid', bDark: 'moon', bBkEx: 'dl', bBkIm: 'ul', bDon: 'coffee', hints: 'menu'
};
const colorToHsl = c => {
    try {
        const s = document.createElement('span');
        s.style.color = c;
        document.documentElement.appendChild(s);
        const v = getComputedStyle(s).color;
        s.remove();
        const m = v.match(/(\d+)\D+(\d+)\D+(\d+)/);
        if (!m) return [348, 83, 47];
        const r = m[1] / 255, g = m[2] / 255, b = m[3] / 255;
        const mx = Math.max(r, g, b), mn = Math.min(r, g, b), d = mx - mn, l = (mx + mn) / 2;
        let h = 0, sat = 0;
        if (d) {
            sat = d / (1 - Math.abs(2 * l - 1));
            h = mx === r ? ((g - b) / d) % 6 : mx === g ? (b - r) / d + 2 : (r - g) / d + 4;
            h = (h * 60 + 360) % 360;
        }
        return [Math.round(h), Math.round(sat * 100), Math.round(l * 100)];
    } catch { return [348, 83, 47]; }
};

const noFade = (...els) => {
    const list = els.filter(Boolean);
    list.forEach(e => e.classList.add('bm-nofade'));
    requestAnimationFrame(() => requestAnimationFrame(() => list.forEach(e => e.classList.remove('bm-nofade'))));
};

const stBack = (ui, overlay) => {
    if (!overlay) return;
    const modal = overlay.querySelector('.bm-modal'), hdr = overlay.querySelector('.bm-hdr');
    if (!modal || !hdr) return;
    if (!overlay._bk) {
        const btn = mk('button', 'bm-close bm-back');
        btn.innerHTML = icons.back;
        btn.style.display = 'none';
        const sync = () => {
            btn.style.display = overlay._fromSt ? 'flex' : 'none';
            modal.classList.toggle('has-back', !!overlay._fromSt);
            btn.title = L().st_back || '';
        };
        btn.onclick = e => {
            e.stopPropagation();
            overlay._fromSt = false;
            sync();
            noFade(overlay, ui.settingsManager?.overlay);
            ui.settingsManager?.open();
            overlay.classList.remove('open');
        };
        overlay.addEventListener('click', e => {
            if (!overlay._fromSt) return;
            const t = e.target;
            const leave = t === overlay
                ? Date.now() - (overlay._stAt || 0) > 400
                : !!(t.closest && t.closest('.bm-close') && !t.closest('.bm-back'));
            if (leave) { overlay._fromSt = false; sync(); }
        }, true);
        hdr.appendChild(btn);
        overlay._bk = sync;
    }
    overlay._fromSt = true;
    overlay._stAt = Date.now();
    overlay._bk();
};

class SettingsManager {
    constructor(ui) {
        this.ui = ui;
        this.hslOpen = false;
        this.build();
    }

    build() {
        this.overlay = mk('div', 'bm-overlay');
        this.overlay.onclick = e => { if (e.target === this.overlay && Date.now() - (this._opAt || 0) > 500) this.close(); };
        const modal = mk('div', 'bm-modal rs-modal st-modal');
        const hdr = mk('div', 'bm-hdr');
        this.title = mk('span', 'bm-title');
        const closeBtn = mk('button', 'bm-close');
        closeBtn.innerHTML = '×';
        closeBtn.onclick = () => this.close();
        hdr.append(this.title, closeBtn);
        this.body = mk('div', 'bm-list');
        modal.append(hdr, this.body);
        this.overlay.appendChild(modal);
        this.ui.shadow.appendChild(this.overlay);
    }

    open() {
        this.render();
        this._opAt = Date.now();
        this.overlay.classList.add('open');
    }

    close() {
        this.overlay.classList.remove('open');
    }

    go(open, getOverlay) {
        const prev = this.overlay;
        noFade(prev);
        open();
        const next = getOverlay();
        noFade(next);
        prev.classList.remove('open');
        stBack(this.ui, next);
    }

    updateLabels() {
        if (this.overlay.classList.contains('open')) this.render();
        this.ui.hideManager?.overlay?._bk?.();
        this.ui.recorder?._rs?.overlay?._bk?.();
        this.ui.sleepTimer?.modal?.overlay?._bk?.();
        this.ui.bookmarkManager?.overlay?._bk?.();
    }

    setTheme(c) {
        AppState.theme = c;
        Store.set('bc_theme', c);
        this.ui.host.style.setProperty('--th', c);
    }

    randomTheme() {
        const r = (a, b) => Math.floor(a + Math.random() * (b - a));
        this.setTheme(`hsla(${r(0, 360)},${r(35, 55)}%,${r(35, 50)}%,0.85)`);
    }

    hslPicker(l, swRow) {
        const [h0, s0, l0] = colorToHsl(AppState.theme);
        const st = { h: h0, s: s0, l: clamp(l0, 15, 85) };
        const box = mk('div', 'st-hsl');
        const prev = mk('div', 'st-prev');
        const tracks = [];
        const slider = (label, key, max, min = 0) => {
            const wrap = mk('div', 'st-hrow');
            const inp = mk('input');
            inp.type = 'range';
            inp.min = String(min);
            inp.max = String(max);
            inp.step = '1';
            inp.value = String(st[key]);
            inp.oninput = () => {
                st[key] = +inp.value;
                this.setTheme(`hsla(${st.h},${st.s}%,${st.l}%,0.9)`);
                swRow.querySelectorAll('.st-swatch.sel').forEach(x => x.classList.remove('sel'));
                swRow.querySelector('.st-custom')?.classList.add('sel');
                paint();
            };
            wrap.append(textEl('', label, 'span'), inp);
            tracks.push([key, inp]);
            return wrap;
        };
        const paint = () => {
            tracks.forEach(([key, inp]) => {
                inp.style.background = key === 'h'
                    ? 'linear-gradient(90deg,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)'
                    : key === 's'
                        ? `linear-gradient(90deg,hsl(${st.h},0%,${st.l}%),hsl(${st.h},100%,${st.l}%))`
                        : `linear-gradient(90deg,hsl(${st.h},${st.s}%,15%),hsl(${st.h},${st.s}%,50%),hsl(${st.h},${st.s}%,85%))`;
            });
        };
        box.append(slider(l.st_hue, 'h', 360), slider(l.st_sat, 's', 100), slider(l.st_lig, 'l', 85, 15), prev);
        paint();
        return box;
    }

    render() {
        const l = L(), ui = this.ui, keep = this.body.scrollTop;
        this.title.innerHTML = `${icons.gear} ${escHTML(l.settings)}`;
        const frag = document.createDocumentFragment();
        const ic = k => `<span class="st-ic">${icons[k] || ''}</span>`;
        const sec = (k, t) => {
            const e = mk('div', 'hd-sec');
            e.innerHTML = `${ic(k)}<span>${escHTML(t)}</span>`;
            frag.append(e);
        };
        const lbl = (k, t) => {
            const e = mk('span', 'st-lbl');
            e.innerHTML = `${ic(k)}<span>${escHTML(t)}</span>`;
            return e;
        };
        const row = (k, label, ...ctl) => {
            const r = mk('div', 'st-row');
            r.append(lbl(k, label), ...ctl);
            frag.append(r);
        };
        const pill = (t, fn, k, extra = '') => {
            const b = mk('button', `st-pill${extra}`);
            b.innerHTML = `${k ? icons[k] : ''}<span>${escHTML(t)}</span>`;
            b.onclick = fn;
            return b;
        };
        const sw = (on, fn) => {
            const b = mk('button', `bm-sw${on ? ' on' : ''}`);
            b.onclick = () => { on = !on; b.classList.toggle('on', on); fn(on); };
            return b;
        };

        sec('color', l.st_look);
        row('globe', l.st_lang, pill(`${AppState.lang} · ${LANG_NAMES[AppState.lang] || ''}`, () => ui.openLangPicker()));
        const colBox = mk('div', 'st-block');
        const swRow = mk('div', 'st-sw-row');
        const known = THEME_SWATCHES.includes(AppState.theme);
        THEME_SWATCHES.forEach(c => {
            const s = mk('button', `st-swatch${AppState.theme === c ? ' sel' : ''}`);
            s.style.background = c;
            s.onclick = () => { this.setTheme(c); this.hslOpen = false; this.render(); };
            swRow.append(s);
        });
        const custom = mk('button', `st-swatch st-custom${!known ? ' sel' : ''}`);
        custom.title = l.st_custom;
        custom.onclick = () => { this.hslOpen = !this.hslOpen; this.render(); };
        swRow.append(custom, pill(l.st_color_rnd, () => { this.randomTheme(); this.hslOpen = false; this.render(); }, 'dice'));
        colBox.append(lbl('color', l.st_color), swRow);
        if (this.hslOpen) colBox.append(this.hslPicker(l, swRow));
        frag.append(colBox);
        const rng = mk('input', 'st-range');
        rng.type = 'range';
        rng.min = '60';
        rng.max = '150';
        rng.step = '10';
        rng.value = String(Math.round(AppState.scale * 100));
        const val = textEl('st-val', `${rng.value}%`, 'span');
        rng.oninput = () => { val.textContent = `${rng.value}%`; ui.setScale(rng.value / 100); };
        row('grid', l.st_scale, rng, val);
        row('moon', l.st_site_dark, sw(AppState.dark, v => ui.toggleDark(v)));
        row('eyeOff', l.hd_title, pill(l.st_open, () => this.go(() => ui.hideManager?.open(), () => ui.hideManager?.overlay)));

        sec('grid', l.st_btns);
        frag.append(textEl('hd-hint', l.st_btns_hint));
        const tiles = mk('div', 'st-tiles');
        const hid = ui.hiddenButtons();
        ui.panelItems().forEach(([id, el, key]) => {
            if (!el) return;
            const name = l[key] || key;
            const t = mk('button', `st-tile${hid[id] ? '' : ' on'}`);
            t.title = name;
            t.innerHTML = `${ic(TILE_ICONS[id])}<span class="st-tl">${escHTML(name)}</span>`;
            t.onclick = () => {
                ui.setButtonHidden(id, t.classList.contains('on'));
                t.classList.toggle('on');
            };
            tiles.append(t);
        });
        frag.append(tiles, pill(l.st_btns_reset, () => { ui.resetButtons(); this.render(); }, 'rel', ' st-wide'));

        sec('rec', l.st_rec);
        row('rec', l.rs_title, pill(l.st_open, () => this.go(() => ui.recorder?.openSettings(), () => ui.recorder?._rs?.overlay)));

        sec('sleep', l.sleep_title);
        const slp = ui.sleepTimer;
        row('sleep', slp?.end ? `${l.sleep_left}: ${slp.fmt()}` : l.rs_off, pill(l.st_open, () => this.go(() => ui.sleepTimer?.open(), () => ui.sleepTimer?.modal?.overlay)));

        sec('target', l.rad_title);
        row('target', l.rad_title, sw(ui.radial?.on === true, v => ui.radial?.setEnabled(v)));
        row('rel', l.rad_reset, pill(l.cal_reset, () => ui.radial?.resetPos()));

        sec('fav', l.st_fav);
        row('star', l.st_star, sw(ui.thumbStars?.on !== false, v => ui.thumbStars?.setEnabled(v)));
        row('bookmark', l.st_list, pill(l.st_open, () => this.go(() => ui.bookmarkManager?.open(), () => ui.bookmarkManager?.overlay)));

        sec('history', l.st_hist);
        row('eye', l.st_hist_on, sw(histOn(), v => Store.set('bc_hist_on', v)));
        row('list', l.st_list, pill(l.st_open, () => this.go(() => ui.historyManager?.open(), () => ui.bookmarkManager?.overlay)));
        row('cal', l.cal_title, pill(l.st_open, () => this.go(() => ui.bookmarkManager?.open('cal'), () => ui.bookmarkManager?.overlay)));

        sec('dl', l.st_data);
        const bkBox = mk('div', 'st-block');
        const bkChips = mk('div', 'st-chips');
        const bkParts = Backup.parts();
        [['s', l.bk_p_set], ['f', l.bk_p_fav], ['h', l.bk_p_hist]].forEach(([k, t]) => {
            const b = textEl(`bm-tbtn${bkParts[k] ? ' on' : ''}`, t, 'button');
            b.onclick = () => { if (Backup.setPart(k, !bkParts[k])) this.render(); };
            bkChips.append(b);
        });
        bkBox.append(lbl('dl', l.bk_parts), bkChips);
        frag.append(bkBox);
        row('dl', l.bk_exp, pill('JSON', () => Backup.export()));
        row('ul', l.bk_imp, pill('JSON', () => ui.backupImport()));
        const csvBox = mk('div', 'st-block');
        const csvChips = mk('div', 'st-chips');
        csvChips.append(
            pill(l.bk_csv_fav, () => Backup.exportFavCsv()),
            pill(l.bk_csv_hist, () => ui.historyManager?.exportCsv(false)),
            pill(l.bk_csv_ses, () => ui.historyManager?.exportCsv(true))
        );
        csvBox.append(lbl('table', l.bk_csv), csvChips);
        frag.append(csvBox);

        this.body.replaceChildren(frag);
        this.body.scrollTop = keep;
    }
}

class UIController {
    constructor() {
        this.elements = {};
        this.hasMoved = false;

        this.host = document.createElement('div');
        this.host.id = 'bc-unchained-host';
        this.shadow = this.host.attachShadow({ mode: 'open' });
        if (document.documentElement.classList.contains('bc-dark-fb')) this.host.setAttribute('data-dfb', '');

        const style = document.createElement('style');
        style.textContent = CSS_UI + CSS_X;
        this.shadow.appendChild(style);

        this.panel = mk('div', 'panel');
        this.panel.style.transform = `scale(${AppState.scale})`;
        this.shadow.appendChild(this.panel);

        this.ghostBtn = mk('div', 'ghost');
        this.ghostBtn.innerHTML = icons.menu;
        this.ghostBtn.onclick = () => this.toggleHide(false);
        this.shadow.appendChild(this.ghostBtn);

        this.restoreBtn = mk('div', 'restore');
        this.restoreBtn.innerHTML = icons.menu;
        this.restoreBtn.onclick = () => { if (!this.hasMoved) this.toggleMinimize(false); };
        this.restoreBtn.onpointerdown = e => this.onDragStart(e);
        this.panel.appendChild(this.restoreBtn);

        this.fullContainer = mk('div', 'col');
        this.panel.appendChild(this.fullContainer);

        this.buildHeader();
        this.buildMediaRow();
        this.buildVolume();
        this.buildControls();
        this.buildMisc();
        this.buildSettings();
        this.applyButtons();

        this.setupDrag();
        this.setupResize();
        this.applyPosition();
        this.setupFilterDrag();

        document.documentElement.appendChild(this.host);
    }

    setupFilterDrag() {
        let hasMoved = false, dragTarget = null, iL = 0, iT = 0;
        let cFx = Store.get('bc_fx', null), cFb = readFb();
        const clampX = (bar, x) => `${clamp(parseFloat(x) || 0, 0, Math.max(0, window.innerWidth - 40))}px`;
        const clampB = (bar, v) => `${clamp(Math.round(parseFloat(v) || 0), 0, Math.max(0, window.innerHeight - 40))}px`;
        const setImp = (el, props) => {
            const st = el.style;
            for (const k in props) {
                if (st.getPropertyValue(k) !== props[k] || st.getPropertyPriority(k) !== 'important') st.setProperty(k, props[k], 'important');
            }
        };
        const applyPos = () => {
            const b = document.querySelector('.bc_sticky_bar');
            if (!b || dragTarget || document.hidden || window.innerHeight < 200) return;
            if (!(cFx && cFb)) return setImp(b, { left: '50%', transform: 'translateX(-50%)' });
            const x = clampX(b, cFx), v = clampB(b, cFb);
            setImp(b, { left: x, top: 'auto', bottom: v, right: 'auto', transform: 'none', margin: '0px', width: 'max-content' });
            if (!b.hasAttribute('data-bcu')) b.setAttribute('data-bcu', '1');
            if (!watched.has(b)) { watched.add(b); barObs.observe(b, { attributes: true, attributeFilter: ['style', 'class'] }); }
        };
        const watched = new WeakSet();
        let pend = false;
        const schedule = () => { if (pend) return; pend = true; requestAnimationFrame(() => { pend = false; applyPos(); }); };
        const barObs = new MutationObserver(schedule);
        new MutationObserver(muts => {
            for (const m of muts) for (const n of m.addedNodes) {
                if (n.nodeType === 1 && (n.matches?.('.bc_sticky_bar') || n.querySelector?.('.bc_sticky_bar'))) return schedule();
            }
        }).observe(document.documentElement, { childList: true, subtree: true });
        const css0 = document.getElementById('bc-unchained-site-css');
        if (cFx && cFb && css0 && !css0.textContent.includes('data-bcu')) { css0.remove(); injectSiteCSS(); }
        setInterval(() => { if (!document.hidden) applyPos(); }, 2000);
        window.addEventListener('resize', applyPos, { passive: true });
        applyPos();

        window.addEventListener('pointerdown', e => {
            if (!isPrimaryPress(e)) return;
            const handle = e.target.closest('.js-filter_button, .bc_sticky_bar'), bar = document.querySelector('.bc_sticky_bar');
            if (!handle || !bar) return;
            if (e.pointerType !== 'mouse') e.preventDefault();
            dragTarget = bar;
            const r = bar.getBoundingClientRect();
            iL = r.left; iT = r.top;
            bar.style.cssText += `;transform:none!important;margin:0!important;bottom:auto!important;right:auto!important;width:max-content!important;left:${iL}px!important;top:${iT}px!important;`;
            handle.style.setProperty('cursor', 'grabbing', 'important');

            Helpers.trackDrag(e, {
                minDist: 4,
                onMove: (dx, dy) => {
                    if (!dragTarget.isConnected) return;
                    dragTarget.style.setProperty('left', `${iL + dx}px`, 'important');
                    dragTarget.style.setProperty('top', `${iT + dy}px`, 'important');
                },
                onEnd: (moved) => {
                    hasMoved = moved;
                    if (moved && dragTarget?.isConnected) {
                        const r = dragTarget.getBoundingClientRect();
                        cFx = clampX(dragTarget, r.left);
                        cFb = clampB(dragTarget, window.innerHeight - r.bottom);
                        Store.set('bc_fx', cFx); Store.set('bc_fb', cFb);
                    }
                    handle.style.setProperty('cursor', 'grab', 'important');
                    dragTarget = null;
                    applyPos();
                }
            });
        }, { passive: false, capture: true });

        window.addEventListener('click', e => {
            if (hasMoved && e.target.closest('.js-filter_button, .bc_sticky_bar')) {
                swallow(e);
            }
        }, { capture: true });
    }

    buildHeader() {
        const hdr = mk('div', 'hdr');
        this.elements.dragZone = mk('div', 'drag');
        let dClicks = 0, dTimer = null;
        hdr.addEventListener('pointerdown', e => {
            if (e.target.closest('button, .stats')) return;
            dClicks++;
            if (dClicks === 1) dTimer = setTimeout(() => dClicks = 0, 500);
            else if (dClicks === 3) {
                clearTimeout(dTimer); dClicks = 0;
                AppState.posX = '15px'; AppState.posY = '10%'; AppState.hasPos = false;
                Store.set('bc_pos', false); this.applyPosition();
            }
            this.onDragStart(e);
        });
        this.elements.stats = mk('div', 'stats');
        this.elements.stats.innerHTML = `${icons.eye}<span>–</span>`;
        const makeHBtn = (html, cls, click) => {
            const b = mk('button', `h-btn ${cls}`.trim());
            b.innerHTML = html;
            b.onclick = click;
            return b;
        };
        this.elements.bLang = makeHBtn(icons.gear, 'lang', () => this.settingsManager?.open());
        this.elements.bHome = makeHBtn(icons.home, '', () => location.href = '/');
        this.elements.bRel = makeHBtn(icons.rel, '', () => location.reload());
        this.elements.bMin = makeHBtn(icons.min, '', () => this.toggleMinimize(true));
        this.elements.bHide = makeHBtn(icons.close, 'close', () => this.toggleHide(true));
        const btns = mk('div', 'hdr-btns');
        btns.append(this.elements.stats, mk('span', 'hsep'), this.elements.bLang, mk('span', 'hsep'), this.elements.bHome, this.elements.bRel, mk('span', 'hsep'), this.elements.bMin, this.elements.bHide);
        hdr.append(this.elements.dragZone, btns);
        this.fullContainer.appendChild(hdr);
    }

    buildMediaRow() {
        const row = mk('div', 'grid-4');

        this.elements.bBg = Helpers.createButton(AppState.bgPlay ? icons.bgOn : icons.bgOff, '');
        if (AppState.bgPlay) this.elements.bBg.classList.add('on');
        this.elements.bBg.onclick = () => {
            AppState.bgPlay = !AppState.bgPlay;
            Store.set('bc_bg', AppState.bgPlay);
            this.elements.bBg.firstChild.innerHTML = AppState.bgPlay ? icons.bgOn : icons.bgOff;
            this.elements.bBg.querySelector('sub').textContent = L().bg;
            this.elements.bBg.classList.toggle('on', AppState.bgPlay);
            this.enforceBackgroundPlay();
        };

        this.elements.bMute = Helpers.createButton(icons.vol, '');
        this.elements.bShot = Helpers.createButton(icons.snap, '');
        this.elements.bRec = Helpers.createButton(icons.rec, '');

        row.append(this.elements.bBg, this.elements.bMute, this.elements.bShot, this.elements.bRec);
        this.fullContainer.appendChild(row);
    }

    buildVolume() {
        const row = mk('div', 'v-cap');

        this.elements.vIco = mk('span', 'vico');
        this.elements.vIco.innerHTML = icons.vol;

        this.elements.vSlider = mk('input', 'vslider');
        this.elements.vSlider.type = 'range';
        this.elements.vSlider.min = '0';
        this.elements.vSlider.max = '1';
        this.elements.vSlider.step = '0.02';
        this.elements.vSlider.value = '1';

        this.elements.vVal = mk('span', 'vval');
        this.elements.vVal.textContent = '100%';

        row.append(this.elements.vIco, this.elements.vSlider, this.elements.vVal);
        this.fullContainer.appendChild(row);
    }

    buildControls() {
        this.fullContainer.appendChild(mk('div', 'sep'));
        const row = mk('div', 'grid-4');

        this.elements.bQual = Helpers.createButton(icons.qual, '');
        this.elements.bQual.onclick = () => this.toggleQuality();

        this.elements.bPip = Helpers.createButton(icons.pip, '');
        this.elements.bFs = Helpers.createButton(icons.fs, '');
        this.elements.bThtr = Helpers.createButton(icons.thtr, '');

        row.append(this.elements.bQual, this.elements.bPip, this.elements.bFs, this.elements.bThtr);
        this.fullContainer.appendChild(row);
    }

    bindQualityClose(qBlock) {
        if (qBlock._bcCloseBound) return;
        qBlock._bcCloseBound = true;
        qBlock.addEventListener('click', e => {
            if (!e.target.closest('.js-qsb_close, .qsb_close, .qsb_list_wrp, [class*="qsb"]')) return;
            setTimeout(() => { qBlock.classList.add('__hidden'); qBlock.style.display = 'none'; }, 50);
        });
    }

    clickQualityFallback() {
        const q = document.querySelector('#quality-btn, .player-resolution, button.vjs-icon-hd, .vjs-resolution-button, .vjs-cog-menu-button, .vjs-icon-cog, [class*="quality"], [class*="resolution"]');
        return q ? q.click() : this.flash(this.elements.bQual, `! ${L().err}`);
    }

    toggleQuality() {
        const qBlock = document.querySelector('#quality_settings_block, .js-quality_settings_block');
        if (!qBlock) return this.clickQualityFallback();
        this.bindQualityClose(qBlock);
        const vis = isQualityShown(qBlock);
        qBlock.classList.toggle('__hidden', vis);
        qBlock.style.display = vis ? 'none' : 'block';
        if (vis) return;
        qBlock.style.zIndex = '2147483645';
        try { jq()?.('#quality-btn').trigger('click'); } catch {}
    }

    buildMisc() {
        const row = mk('div', 'grid-4');
        this.elements.bSearch = Helpers.createButton(icons.search, '');
        this.elements.bHls = Helpers.createButton(icons.hls, 'HLS');
        const hlsFlash = ok => this.flash(this.elements.bHls, ok ? 'OK' : 'ERR');
        Helpers.bindLongPress(this.elements.bHls,
            () => copyHls(getStreamUrl(), hlsFlash),
            () => shareHls(getStreamUrl(), `${currentSite.getName()} Stream`, hlsFlash)
        );
        this.elements.bCopy = Helpers.createButton(icons.copy, '');
        this.elements.bCopy.onclick = () => {
            const name = currentSite.getName();
            if (!name) return this.flash(this.elements.bCopy, 'ERR');
            const link = modelSlug(location.href) ? linkFor(location.href) : `${location.origin}${location.pathname}`;
            Helpers.copy(link, () => this.flash(this.elements.bCopy, 'OK'), () => this.flash(this.elements.bCopy, 'ERR'));
        };
        this.elements.bFav = Helpers.createButton(icons.fav, '');
        row.append(this.elements.bSearch, this.elements.bHls, this.elements.bCopy, this.elements.bFav);
        this.fullContainer.appendChild(row);
        const navRow = mk('div', 'favnav');
        this.elements.bFavPrev = Helpers.createButton(icons.favPrev, '');
        this.elements.bFavNext = Helpers.createButton(icons.favNext, '');
        navRow.append(this.elements.bFavPrev, this.elements.bFavNext);
        this.fullContainer.appendChild(navRow);
        this.elements.favNavRow = navRow;
        FavNav.hook = on => navRow.classList.toggle('on', on);
        FavNav.apply();
    }

    buildSettings() {
        this.fullContainer.appendChild(mk('div', 'sep'));
        const row = mk('div', 'row-4');
        const btnCol = mk('button', 'z-btn');
        btnCol.innerHTML = icons.color;
        btnCol.style.cssText = 'width:100%;height:24px;';
        this.elements.bColor = btnCol;
        const rnd = (min, max) => Math.floor(min + Math.random() * (max - min));
        btnCol.onclick = () => {
            const c = `hsla(${rnd(0, 360)},${rnd(35, 55)}%,${rnd(35, 50)}%,0.85)`;
            AppState.theme = c;
            Store.set('bc_theme', c);
            this.host.style.setProperty('--th', c);
        };

        const scaleCtrl = mk('div', 'scale-ctrl');
        const btnZoomOut = mk('button', 'z-btn');
        btnZoomOut.innerHTML = '−';
        const btnZoomIn = mk('button', 'z-btn');
        btnZoomIn.innerHTML = '+';
        const scaleVal = mk('span', 's-val');
        scaleVal.textContent = `${Math.round(AppState.scale * 100)}%`;

        const setScale = s => {
            s = clamp(s, 0.6, 1.5);
            AppState.scale = s;
            Store.set('bc_scale', s);
            scaleVal.textContent = `${Math.round(s * 100)}%`;
            this.panel.style.transform = `scale(${s})`;
            if (AppState.hasPos) this.clampPosition();
        };
        this.setScale = setScale;
        this.elements.scaleCtrl = scaleCtrl;
        btnZoomOut.onclick = () => setScale(AppState.scale - 0.1);
        btnZoomIn.onclick = () => setScale(AppState.scale + 0.1);

        scaleCtrl.append(btnZoomOut, scaleVal, btnZoomIn);
        const btnHide = mk('button', 'z-btn');
        btnHide.innerHTML = icons.eyeOff;
        btnHide.style.cssText = 'width:100%;height:24px;';
        btnHide.onclick = () => this.hideManager?.open();
        this.elements.bHideMgr = btnHide;
        row.style.cssText = 'display:grid;grid-template-columns:repeat(4,1fr);gap:6px;align-items:center';
        scaleCtrl.style.cssText = 'grid-column:span 2;justify-content:space-between';
        row.append(btnCol, btnHide, scaleCtrl);
        this.fullContainer.appendChild(row);

        const row2 = mk('div', 'row-2');
        row2.style.cssText = 'display:flex;gap:6px';
        const sBtn = (key, fn) => {
            const b = mk('button', 'z-btn');
            b.style.cssText = 'flex:1;height:24px;font-size:10px;font-weight:700;display:flex;align-items:center;justify-content:center;white-space:nowrap';
            b.onclick = fn;
            this.elements[key] = b;
            return b;
        };
        row2.append(
            sBtn('bDark', () => this.toggleDark()),
            sBtn('bBkEx', () => { Backup.export(); this.flash(this.elements.bBkEx, 'OK'); }),
            sBtn('bBkIm', () => this.backupImport()),
            sBtn('bDon', () => this.openDonate())
        );
        this.fullContainer.appendChild(row2);

        this.elements.hints = mk('div', 'hotkeys');
        this.fullContainer.appendChild(this.elements.hints);
    }

    panelItems() {
        const e = this.elements;
        return [
            ['bBg', e.bBg, 'bg'], ['bMute', e.bMute, 'sound'], ['bShot', e.bShot, 'snap'], ['bRec', e.bRec, 'rec'],
            ['vol', e.vIco?.parentElement, 'bt_vol'], ['bQual', e.bQual, 'qual'], ['bPip', e.bPip, 'pip'], ['bFs', e.bFs, 'fs'], ['bThtr', e.bThtr, 'thtr'],
            ['bSearch', e.bSearch, 'search'], ['bHls', e.bHls, 'HLS'], ['bCopy', e.bCopy, 'copy'], ['bFav', e.bFav, 'favs'],
            ['stats', e.stats, 'bt_stats'], ['bHome', e.bHome, 'home'], ['bRel', e.bRel, 'rel'],
            ['bColor', e.bColor, 'st_color'], ['bHideMgr', e.bHideMgr, 'hd_title'], ['scale', e.scaleCtrl, 'st_scale'],
            ['bDark', e.bDark, 'st_site_dark'], ['bBkEx', e.bBkEx, 'bk_exp'], ['bBkIm', e.bBkIm, 'bk_imp'], ['bDon', e.bDon, 'don_tip'],
            ['hints', e.hints, 'bt_hints']
        ];
    }

    hiddenButtons() {
        const o = Store.get('bc_btnhide', {});
        return o && typeof o === 'object' && !Array.isArray(o) ? o : {};
    }

    setButtonHidden(id, hide) {
        const o = { ...this.hiddenButtons() };
        if (hide) o[id] = true; else delete o[id];
        Store.set('bc_btnhide', o);
        this.applyButtons();
    }

    resetButtons() {
        Store.set('bc_btnhide', {});
        this.applyButtons();
    }

    applyButtons() {
        const hid = this.hiddenButtons();
        this.panelItems().forEach(([id, el]) => { if (el) el.classList.toggle('off', hid[id] === true); });
        [...this.fullContainer.children].filter(c => c.matches('.grid-4,.row-4,.row-2')).forEach(r => {
            const n = [...r.children].filter(c => !c.classList.contains('off')).length;
            r.classList.toggle('off', n === 0);
            if (r.matches('.grid-4')) r.style.gridTemplateColumns = n > 0 && n < 4 ? `repeat(${n},1fr)` : '';
        });
    }

    openLangPicker() {
        if (!this._lp) {
            const overlay = mk('div', 'bm-overlay');
            const modal = mk('div', 'bm-modal rs-modal lp-modal');
            const hdr = mk('div', 'bm-hdr');
            const title = mk('span', 'bm-title');
            const closeBtn = mk('button', 'bm-close');
            closeBtn.innerHTML = '×';
            hdr.append(title, closeBtn);
            const list = mk('div', 'bm-list lp-grid');
            modal.append(hdr, list);
            overlay.appendChild(modal);
            this.shadow.appendChild(overlay);
            closeBtn.onclick = () => overlay.classList.remove('open');
            overlay.onclick = e => { if (e.target === overlay && Date.now() - (this._lpAt || 0) > 400) overlay.classList.remove('open'); };
            this._lp = { overlay, title, list };
        }
        const { overlay, title, list } = this._lp;
        title.textContent = L().lang_title;
        const choose = (code, auto) => {
            AppState.langAuto = auto;
            Store.set('bc_lang_auto', auto);
            AppState.lang = auto ? detectLang() : code;
            if (!auto) Store.set('bc_lang', code);
            this.updateLabels();
            overlay.classList.remove('open');
        };
        const item = (code, text, on, fn, extra) => {
            const b = mk('button', `lp-btn${on ? ' sel' : ''}${extra ? ' ' + extra : ''}`);
            const c = mk('span', 'lp-code');
            c.textContent = code;
            const n = mk('span', 'lp-name');
            n.textContent = text;
            b.append(c, n);
            b.onclick = fn;
            return b;
        };
        const dl = detectLang();
        list.replaceChildren(
            item(dl, `${L().lang_auto} · ${LANG_NAMES[dl]}`, AppState.langAuto, () => choose('', true), 'lp-auto'),
            ...LANGS.map(c => item(c, LANG_NAMES[c], !AppState.langAuto && AppState.lang === c, () => choose(c, false)))
        );
        this._lpAt = Date.now();
        overlay.classList.add('open');
    }

    updateLabels() {
        const l = L();
        this.host.toggleAttribute('data-rtl', RTL_LANGS.includes(AppState.lang));
        this.elements.dragZone.textContent = '';
        this.elements.bLang.title = l.settings;
        this.elements.bHome.title = l.home;
        this.elements.bRel.title = l.rel;
        this.elements.bMin.title = l.min;
        this.elements.bHide.title = l.hide;

        const subs = [
            ['bBg', 'bg'], ['bMute', 'sound'], ['bShot', 'snap'], ['bRec', 'rec'],
            ['bQual', 'qual'], ['bPip', 'pip'], ['bFs', 'fs'], ['bThtr', 'thtr'],
            ['bSearch', 'search'], ['bCopy', 'copy'], ['bFav', 'favs']
        ];
        subs.forEach(([k, lk]) => {
            const s = this.elements[k]?.querySelector('sub');
            if (s) s.textContent = l[lk];
        });

        this.elements.hints.innerHTML = l.hints;
        if (this.elements.bRec) this.elements.bRec.title = l.rec_tip;
        const e = this.elements;
        if (e.bDark) { e.bDark.innerHTML = (AppState.dark ? icons.moon : icons.sun); e.bDark.title = l.dark; e.bDark.style.background = AppState.dark ? 'linear-gradient(145deg,var(--th),rgba(255,255,255,.14))' : ''; e.bDark.style.boxShadow = AppState.dark ? 'inset 0 0 0 1px rgba(255,255,255,.22)' : ''; }
        [['bBkEx', 'dl', 'bk_exp'], ['bBkIm', 'ul', 'bk_imp'], ['bDon', 'coffee', 'don_tip']].forEach(([k, ico, tk]) => {
            if (e[k]) { e[k].innerHTML = icons[ico]; e[k].title = l[tk]; }
        });
        if (e.bDon) e.bDon.style.color = '#ffb347';
        this.bookmarkManager?.updateLabels();
        this.hideManager?.updateLabels();
        this.settingsManager?.updateLabels();
        this.historyManager?.updateLabels();
    }

    toggleDark(on = !AppState.dark) {
        AppState.dark = !!on;
        Store.set('bc_dark', AppState.dark);
        applyDark();
        this.updateLabels();
    }

    backupImport() {
        Backup.import(
            () => { this.flash(this.elements.bBkIm, 'OK'); setTimeout(() => location.reload(), 700); },
            () => this.flash(this.elements.bBkIm, 'ERR')
        );
    }

    openDonate() {
        const l = L();
        const tx = { title: l.don_title, sub: l.don_sub, copied: l.don_copied, fail: l.don_fail, tap: l.don_tap };
        if (this._donate && this._donate.lang !== AppState.lang) { this._donate.overlay.remove(); this._donate = null; }
        if (this._donate) {
            this._donate.overlay.classList.add('open');
            return;
        }
        const wallets = [
            { name: 'TON', net: 'Gram · USDT', sym: 'T', svg: '<svg viewBox="12 14 32 32" width="26" height="26" xmlns="http://www.w3.org/2000/svg" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.3))"><path fill="#fff" d="M37.56 15.63H18.44c-3.52 0-5.75 3.79-3.98 6.86l11.8 20.45c.77 1.34 2.7 1.34 3.47 0l11.8-20.45c1.77-3.06-.46-6.86-3.97-6.86zM26.25 36.81l-2.57-4.98-6.2-11.09c-.41-.71.1-1.62.95-1.62h7.82v17.69zm12.26-16.07-6.2 11.1-2.57 4.97V19.12h7.82c.86 0 1.36.91.95 1.62z"/></svg>', c1: '#2aa6f0', c2: '#0b6fc2', addr: 'UQAhsfD61tpWIWI_VUnvJzDXE5LkfZQd1uZoWFO0uDEY81Nq' },
            { name: 'Litecoin', net: 'LTC', sym: 'Ł', svg: '<svg viewBox="0 0 24 24" width="26" height="26" xmlns="http://www.w3.org/2000/svg" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.3))"><path d="M10.8 4.8 8.6 16.4h7.4" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/><path d="M6.4 12.9l8.2-3.3" fill="none" stroke="#fff" stroke-width="2.1" stroke-linecap="round"/></svg>', c1: '#9aa7b8', c2: '#4b5a70', addr: 'ltc1q7kdhehwusk6qupe325trqe9xjhp6qq4rpgy88j' },
            { name: 'BNB Smart Chain', net: 'BEP-20 · USDT · BNB', sym: 'B', svg: '<svg viewBox="0 0 24 24" width="26" height="26" xmlns="http://www.w3.org/2000/svg" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.3))"><g fill="#fff"><path d="M12 3 7.5 7.5l1.7 1.7L12 6.4l2.8 2.8 1.7-1.7zM12 21l-4.5-4.5 1.7-1.7 2.8 2.8 2.8-2.8 1.7 1.7z"/><path d="M5.2 9.9 7.3 12l-2.1 2.1L3.1 12zM18.8 9.9 20.9 12l-2.1 2.1-2.1-2.1zM12 9.2 14.8 12 12 14.8 9.2 12z"/></g></svg>', c1: '#f8cf4d', c2: '#c9930a', addr: '0xC1602C8CE455A4f7E694DF8524f59317de375310' },
            { name: 'Ethereum', net: 'ERC-20 · ETH', sym: 'Ξ', svg: '<svg viewBox="0 0 256 417" width="17" height="28" xmlns="http://www.w3.org/2000/svg" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.3))"><path fill="#fff" fill-opacity=".6" d="M127.96 0v154.16l128 56.16z"/><path fill="#fff" d="M127.96 0 0 210.32l127.96-56.16z"/><path fill="#fff" fill-opacity=".6" d="M127.96 312.19V417L256 236.59z"/><path fill="#fff" d="M127.96 417V312.19L0 236.59z"/><path fill="#fff" fill-opacity=".2" d="m127.96 287.96 128-75.64-128-58.16z"/><path fill="#fff" fill-opacity=".6" d="m0 212.32 127.96 75.64V154.16z"/></svg>', c1: '#8a9bff', c2: '#4a5bd0', addr: '0xC1602C8CE455A4f7E694DF8524f59317de375310' },
            { name: 'Solana', net: 'SOL · USDT', sym: 'S', svg: '<svg viewBox="0 0 398 312" width="24" height="19" xmlns="http://www.w3.org/2000/svg" style="display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.3))"><g fill="#fff"><path d="M64.6 237.9c2.4-2.4 5.7-3.8 9.2-3.8h317.4c5.8 0 8.7 7 4.6 11.1l-62.7 62.7c-2.4 2.4-5.7 3.8-9.2 3.8H6.5c-5.8 0-8.7-7-4.6-11.1l62.7-62.7z"/><path d="M64.6 3.8C67.1 1.4 70.4 0 73.8 0h317.4c5.8 0 8.7 7 4.6 11.1l-62.7 62.7c-2.4 2.4-5.7 3.8-9.2 3.8H6.5c-5.8 0-8.7-7-4.6-11.1L64.6 3.8z"/><path d="M333.1 120.1c-2.4-2.4-5.7-3.8-9.2-3.8H6.5c-5.8 0-8.7 7-4.6 11.1l62.7 62.7c2.4 2.4 5.7 3.8 9.2 3.8h317.4c5.8 0 8.7-7 4.6-11.1l-62.7-62.7z"/></g></svg>', c1: '#9945ff', c2: '#14c9a0', addr: '7gp6seGi5aVJiKbMKxztPX8NBbtFsySRPfwmWmDEFM6P' }
        ];
        const icCopy = '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
        const icOk = '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#3ddc84" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
        const short = a => a.length > 20 ? `${a.slice(0, 8)}…${a.slice(-8)}` : a;

        const overlay = mk('div', 'bm-overlay');
        overlay.onclick = ev => { if (ev.target === overlay) overlay.classList.remove('open'); };
        const css = document.createElement('style');
        css.textContent = '@keyframes dnSteam{0%{transform:translateY(6px) scaleX(.8);opacity:0}25%{opacity:.55}60%{transform:translateY(-6px) scaleX(1.15);opacity:.35}100%{transform:translateY(-16px) scaleX(.9);opacity:0}}@keyframes dnFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}@keyframes dnPop{0%{transform:scale(.92);opacity:0}100%{transform:scale(1);opacity:1}}.dn-steam i{position:absolute;bottom:100%;width:2px;height:14px;border-radius:2px;background:linear-gradient(rgba(255,226,180,0),rgba(255,226,180,.75) 55%,rgba(255,226,180,0));filter:blur(.4px);animation:dnSteam 3.4s cubic-bezier(.45,0,.55,1) infinite}.dn-row{transition:border-color .25s,background .25s,transform .15s}.dn-row:active{transform:scale(.985)}.dn-cp{transition:background .2s,color .2s}.dn-cp:hover{background:rgba(255,255,255,.14)!important;color:#fff!important}.dn-cp svg{margin:0!important;vertical-align:baseline!important;display:block}.dn-row:hover:not(.dn-ok){background:rgba(255,255,255,.075)!important;border-color:var(--c)!important}.dn-row:active:not(.dn-ok){background:rgba(255,255,255,.1)!important;border-color:var(--c)!important}.dn-row.dn-ok{background:rgba(61,220,132,.08)!important;border-color:rgba(61,220,132,.7)!important}';
        overlay.appendChild(css);

        const modal = mk('div', 'bm-modal');
        modal.style.cssText = 'position:relative;height:auto;min-height:0;max-height:92vh;width:370px;max-width:94vw;overflow:hidden auto;border:1px solid rgba(255,179,71,.28);border-radius:22px;background:linear-gradient(180deg,#2a1d14 0%,#17161b 38%,#131317 100%)!important;box-shadow:0 20px 60px rgba(0,0,0,.65),0 0 60px rgba(255,159,28,.12);animation:dnPop .28s ease';

        const close = mk('button', 'bm-close');
        close.innerHTML = '×';
        close.style.cssText += ';position:absolute;top:10px;right:10px;inset-inline-end:10px;transform:none;z-index:2';
        close.onclick = () => overlay.classList.remove('open');

        const top = mk('div');
        top.style.cssText = 'position:relative;display:flex;flex-direction:column;align-items:center;text-align:center;padding:26px 20px 14px';
        const cup = mk('div');
        cup.style.cssText = 'position:relative;width:68px;height:68px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;background:linear-gradient(145deg,#ffb347,#ff7a18);box-shadow:0 8px 24px rgba(255,122,24,.45),inset 0 1px 0 rgba(255,255,255,.35);margin-bottom:14px';
        cup.innerHTML = icons.coffee.replace(/width="\d+" height="\d+"/, 'width="34" height="34"').replace('stroke-width="2"', 'stroke-width="1.8"');
        const cupSvg = cup.querySelector('svg');
        if (cupSvg) cupSvg.style.transform = 'translateX(2px)';
        const steam = mk('div', 'dn-steam');
        steam.style.cssText = 'position:absolute;left:0;right:0;top:6px;height:0;pointer-events:none';
        [[26, 0], [32, .7], [38, 1.4]].forEach(([x, d]) => { const i = document.createElement('i'); i.style.cssText = `left:${x}px;animation-delay:${d}s`; steam.appendChild(i); });
        cup.appendChild(steam);
        const h = mk('div');
        h.style.cssText = 'color:#fff;font-size:18px;font-weight:800;letter-spacing:.2px';
        h.textContent = tx.title;
        const p = mk('div');
        p.style.cssText = 'color:#b9b3ad;font-size:12.5px;line-height:1.45;margin-top:6px;max-width:290px';
        p.textContent = tx.sub;
        const mascot = mk('div');
        mascot.style.cssText = 'position:absolute;left:calc(50% + 30px);top:20px;width:24px;height:24px;pointer-events:none;filter:drop-shadow(0 2px 6px rgba(255,93,115,.55));animation:dnFloat 2.6s ease-in-out infinite';
        mascot.innerHTML = '<svg viewBox="0 0 24 24" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"><path d="M12 21s-8-5.2-8-11a4.6 4.6 0 0 1 8-3.1A4.6 4.6 0 0 1 20 10c0 5.8-8 11-8 11z" fill="#ff5d73"/><path d="M7.5 8.5c.4-1.2 1.4-1.8 2.5-1.7" fill="none" stroke="#fff" stroke-width="1.4" stroke-linecap="round" opacity=".6"/></svg>';
        top.append(mascot, cup, h, p);

        const list = mk('div');
        list.style.cssText = 'display:flex;flex-direction:column;gap:9px;padding:6px 14px 8px';
        wallets.forEach(w => {
            const row = mk('div', 'dn-row');
            row.style.cssText = 'display:flex;align-items:center;gap:12px;padding:11px 12px;border-radius:14px;background:rgba(255,255,255,.045);border:1px solid rgba(255,255,255,.08)';
            row.style.setProperty('--c', w.c1);
            const badge = mk('div');
            badge.style.cssText = `flex:0 0 40px;width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:18px;background:linear-gradient(145deg,${w.c1},${w.c2});box-shadow:0 4px 12px rgba(0,0,0,.35)`;
            if (w.svg) badge.innerHTML = w.svg; else badge.textContent = w.sym;
            const mid = mk('div');
            mid.style.cssText = 'flex:1;min-width:0;display:flex;flex-direction:column;gap:2px';
            const nm = mk('div');
            nm.style.cssText = 'color:#fff;font-size:13.5px;font-weight:700;line-height:1.2';
            nm.textContent = w.name;
            const ad = mk('div');
            ad.style.cssText = 'margin-top:3px;color:#ffc87a;font:12px/1.35 ui-monospace,Menlo,Consolas,monospace;cursor:pointer;word-break:break-all';
            let full = false;
            ad.textContent = short(w.addr);
            ad.onclick = () => { full = !full; ad.textContent = full ? w.addr : short(w.addr); };
            mid.append(nm, ad);
            const cp = mk('button', 'dn-cp');
            cp.innerHTML = icCopy;
            cp.style.cssText = 'flex:0 0 44px;width:44px;height:44px;border-radius:12px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.07);color:#ddd;display:flex;align-items:center;justify-content:center;cursor:pointer';
            cp.onclick = () => Helpers.copy(w.addr, () => {
                cp.innerHTML = icOk;
                row.classList.add('dn-ok');
                setTimeout(() => { if (cp.isConnected) { cp.innerHTML = icCopy; row.classList.remove('dn-ok'); } }, 1400);
            }, () => toast(tx.fail, false));
            row.append(badge, mid, cp);
            list.appendChild(row);
        });

        const hint = mk('div');
        hint.style.cssText = 'text-align:center;color:#6f6a64;font-size:10.5px;padding:2px 16px 8px';
        hint.textContent = tx.tap;
        const toastEl = mk('div');
        toastEl.style.cssText = 'position:sticky;bottom:0;height:0;display:flex;justify-content:center;overflow:visible';
        const toastIn = mk('div');
        toastIn.style.cssText = 'position:absolute;bottom:12px;padding:8px 16px;border-radius:999px;font-size:12.5px;font-weight:700;color:#fff;background:#1f9d5c;box-shadow:0 6px 18px rgba(0,0,0,.5);opacity:0;transform:translateY(8px);transition:.25s;pointer-events:none;white-space:nowrap';
        toastEl.appendChild(toastIn);
        let tt = 0;
        const toast = (msg, ok) => {
            toastIn.textContent = msg;
            toastIn.style.background = ok ? '#1f9d5c' : '#c0392b';
            toastIn.style.opacity = '1';
            toastIn.style.transform = 'none';
            clearTimeout(tt);
            tt = setTimeout(() => { toastIn.style.opacity = '0'; toastIn.style.transform = 'translateY(8px)'; }, 1500);
        };

        modal.append(close, top, list, hint, toastEl);
        overlay.appendChild(modal);
        this.shadow.appendChild(overlay);
        this._donate = { overlay, lang: AppState.lang };
        requestAnimationFrame(() => overlay.classList.add('open'));
    }

    flash(btn, text) {
        const target = btn.querySelector('sub') || btn;
        const pending = !!target._bcFlashT;
        clearTimeout(target._bcFlashT);
        if (!pending) {
            target._bcOrig = target.innerHTML;
            target._bcPrevH = target.style.height;
            target._bcPrevO = target.style.overflow;
            const h = target.getBoundingClientRect().height;
            if (h > 0) { target.style.height = `${h}px`; target.style.overflow = 'visible'; }
        }
        const sz = target.tagName === 'SUB' ? 12 : 16;
        target.innerHTML = text === 'OK'
            ? `<svg viewBox="0 0 24 24" width="${sz}" height="${sz}" stroke="#2ecc71" fill="none" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="display:inline-block;vertical-align:middle;margin:0 auto"><polyline points="20 6 9 17 4 12"/></svg>`
            : text;
        target._bcFlashT = setTimeout(() => {
            target._bcFlashT = null;
            if (!target.isConnected) return;
            target.innerHTML = target._bcOrig;
            target.style.height = target._bcPrevH || '';
            target.style.overflow = target._bcPrevO || '';
        }, 1500);
    }

    toggleHide(hide) {
        AppState.isHidden = hide;
        Store.set('bc_hid', hide);
        this.panel.classList.toggle('hidden', hide);
        this.ghostBtn.style.display = hide ? 'flex' : 'none';
        if (!hide && AppState.hasPos) this.clampPosition();
    }

    savePos(x, y) {
        AppState.posX = x; AppState.posY = y; AppState.hasPos = true;
        Store.set('bc_x', x); Store.set('bc_y', y); Store.set('bc_pos', true);
    }

    toggleMinimize(minimized, initial = false) {
        AppState.isMinimized = minimized;
        Store.set('bc_min', minimized);

        if (!initial) {
            const rect = this.panel.getBoundingClientRect();
            const k = (minimized ? 1 : -1) * AppState.scale;
            const at = (p, d) => `${(parseFloat(this.panel.style[p]) || (p === 'top' ? rect.top - this.hostTop() : rect[p])) + k * d}px`;
            const newLeft = at('left', MINI_SHIFT_X), newTop = at('top', MINI_SHIFT_Y);
            this.panel.style.cssText += `;left:${newLeft};top:${newTop};right:auto;bottom:auto`;
            this.savePos(newLeft, newTop);
        }

        this.fullContainer.style.display = minimized ? 'none' : 'flex';
        this.restoreBtn.style.display = minimized ? 'flex' : 'none';
        this.restoreBtn.style.transformOrigin = 'top left';
        this.restoreBtn.style.transform = `scale(${1 / AppState.scale})`;
        this.panel.className = minimized ? 'panel mini' : 'panel';
        if (!initial) this.clampPosition();
    }

    hostTop() { return this.host.getBoundingClientRect().top || 0; }

    onDragStart(e) {
        if (!isPrimaryPress(e)) return;
        e.preventDefault();
        const rect = this.panel.getBoundingClientRect();
        const iL = rect.left, iT = rect.top - this.hostTop();
        this.panel.style.cssText += `;left:${iL}px;top:${iT}px;right:auto;bottom:auto`;

        Helpers.trackDrag(e, {
            minDist: 2,
            onMove: (dx, dy) => {
                this.hasMoved = true;
                this.panel.style.left = `${iL + dx}px`;
                this.panel.style.top = `${iT + dy}px`;
            },
            onEnd: (moved) => {
                this.hasMoved = moved;
                if (moved) {
                    this.clampPosition();
                    this.savePos(this.panel.style.left, this.panel.style.top);
                }
            }
        });
    }

    setupDrag() {
        let swallowClick = false;
        this.panel.addEventListener('click', ev => {
            if (!swallowClick) return;
            swallowClick = false;
            ev.stopPropagation();
            ev.preventDefault();
        }, true);
        this.panel.addEventListener('pointerdown', e => {
            if (AppState.isMinimized) return;
            if (!isPrimaryPress(e)) return;
            if (e.target.closest('input, textarea, .vslider, .resize-handle, .bm-overlay')) return;
            if (!e.target.closest('button, a, .btn, .h-btn, .z-btn')) { this.onDragStart(e); return; }
            const sx = e.clientX, sy = e.clientY, pid = e.pointerId, tgt = e.target;
            const stop = () => {
                window.removeEventListener('pointermove', mv, true);
                window.removeEventListener('pointerup', stop, true);
                window.removeEventListener('pointercancel', stop, true);
            };
            const mv = ev => {
                if (ev.pointerId !== pid || Math.hypot(ev.clientX - sx, ev.clientY - sy) < 10) return;
                stop();
                swallowClick = true;
                window.addEventListener('pointerup', () => setTimeout(() => { swallowClick = false; }, 350), { once: true, capture: true });
                try { tgt.dispatchEvent(new PointerEvent('pointercancel', { pointerId: pid, bubbles: true })); } catch {}
                this.onDragStart(e);
            };
            window.addEventListener('pointermove', mv, { capture: true, passive: true });
            window.addEventListener('pointerup', stop, true);
            window.addEventListener('pointercancel', stop, true);
        });
    }

    setupResize() {
        this.resizeHandle = mk('div', 'resize-handle');
        this.resizeHandle.dataset.edge = 'se';
        const edges = ['n', 's', 'e', 'w', 'nw', 'ne', 'sw'].map(k => {
            const d = mk('div', `rs-edge rs-${k}`);
            d.dataset.edge = k;
            return d;
        });
        this.panel.append(this.resizeHandle, ...edges);

        const start = e => {
            if (!isPrimaryPress(e)) return;
            e.preventDefault();
            e.stopPropagation();
            const edge = e.currentTarget.dataset.edge;
            const hasN = edge.includes('n'), hasS = edge.includes('s'), hasW = edge.includes('w'), hasE = edge.includes('e');
            const rect = this.panel.getBoundingClientRect();
            const s0 = AppState.scale, w0 = rect.width, h0 = rect.height;
            const scaleVal = this.shadow.querySelector('.s-val');
            const ht = this.hostTop();
            this.panel.style.left = `${rect.left}px`;
            this.panel.style.top = `${rect.top - ht}px`;
            this.panel.style.right = 'auto';
            this.panel.style.bottom = 'auto';

            let raf = 0, ns = s0;
            const paint = () => {
                raf = 0;
                const f = ns / s0;
                this.panel.style.transform = `scale(${ns})`;
                this.panel.style.left = `${hasW ? rect.right - w0 * f : rect.left}px`;
                this.panel.style.top = `${(hasN ? rect.bottom - h0 * f : rect.top) - ht}px`;
                if (scaleVal) scaleVal.textContent = `${Math.round(ns * 100)}%`;
            };
            Helpers.trackDrag(e, {
                minDist: 1,
                onMove: (dx, dy) => {
                    const kx = axisK(hasE, hasW, w0, dx), ky = axisK(hasS, hasN, h0, dy);
                    ns = clamp(s0 * (kx !== null && ky !== null ? (kx + ky) / 2 : kx ?? ky), 0.6, 1.5);
                    AppState.scale = ns;
                    if (!raf) raf = requestAnimationFrame(paint);
                },
                onEnd: moved => {
                    if (!moved) return;
                    if (raf) { cancelAnimationFrame(raf); paint(); }
                    Store.set('bc_scale', ns);
                    this.clampPosition();
                    this.savePos(this.panel.style.left, this.panel.style.top);
                }
            });
        };

        [this.resizeHandle, ...edges].forEach(el => el.addEventListener('pointerdown', start));
    }

    clampPosition(gap = 10) {
        if (this.panel.classList.contains('hidden')) return;
        if (document.hidden || window.innerHeight < 200 || window.innerWidth < 100) return;
        const rect = this.panel.getBoundingClientRect();
        const l = parseFloat(this.panel.style.left), t = parseFloat(this.panel.style.top);
        if (isNaN(l) || isNaN(t)) return;
        this.panel.style.left = `${clamp(l, gap, Math.max(gap, window.innerWidth - gap - rect.width))}px`;
        const vh = window.innerHeight;
        this.panel.style.top = `${clamp(t, gap - vh, Math.max(gap - vh, -gap - rect.height))}px`;
    }

    applyPosition() {
        if (AppState.hasPos && AppState.posX && AppState.posY) {
            const py = parseFloat(AppState.posY);
            if (py >= 0 && window.innerHeight >= 200) { AppState.posY = `${Math.round(py - window.innerHeight)}px`; Store.set('bc_y', AppState.posY); }
            this.panel.style.left = AppState.posX;
            this.panel.style.top = AppState.posY;
            this.panel.style.right = 'auto';
            this.panel.style.bottom = 'auto';
        } else {
            this.panel.style.right = '15px';
            this.panel.style.bottom = '10vh';
            this.panel.style.left = 'auto';
            this.panel.style.top = 'auto';
        }
    }

    enforceBackgroundPlay() {
        if (this._pbBound) return;
        this._pbBound = true;
        const pb = e => {
            if (!(AppState.bgPlay && e.isTrusted)) return;
            e.stopImmediatePropagation();
            const subs = BG_SUBS[e.type];
            if (subs && !e._bcRelayed) {
                e._bcRelayed = true;
                subs.forEach(fn => { try { fn(e); } catch {} });
            }
        };
        ['blur', 'visibilitychange', 'webkitvisibilitychange', 'pagehide'].forEach(evt => {
            window.addEventListener(evt, pb, true);
            document.addEventListener(evt, pb, true);
        });
        const hid = Object.getOwnPropertyDescriptor(Document.prototype, 'hidden');
        const vis = Object.getOwnPropertyDescriptor(Document.prototype, 'visibilityState');
        try {
            Object.defineProperties(document, {
                hidden: { get: () => AppState.bgPlay ? false : hid.get.call(document), configurable: true },
                visibilityState: { get: () => AppState.bgPlay ? 'visible' : vis.get.call(document), configurable: true }
            });
        } catch {}
    }

    injectSiteCSS() {
        injectSiteCSS();
        ensureHideCSS();
    }
}

class BgSaver {
    constructor(videoController, recorder) {
        this.vc = videoController;
        this.rec = recorder;
        this.timer = 0;
        this.paused = null;
        this.lowered = null;
        onPageEvent('visibilitychange', () => this.onVis());
    }

    busy() {
        return !!document.pictureInPictureElement || this.rec?.mRec?.state === 'recording';
    }

    onVis() {
        clearTimeout(this.timer);
        if (realHidden()) {
            this.timer = setTimeout(() => this.enter(), 10000);
        } else {
            this.leave();
        }
    }

    enter() {
        if (!realHidden() || this.busy()) return;
        try {
            if (AppState.bgPlay) {
                this.setLowest();
            } else {
                const v = this.vc.cachedVideo;
                if (v && !v.paused) { v.pause(); this.paused = v; }
            }
        } catch {}
    }

    leave() {
        try {
            const v = this.paused;
            this.paused = null;
            if (v?.isConnected) {
                const b = v.buffered;
                if (b.length) {
                    const end = b.end(b.length - 1);
                    if (end - v.currentTime > 3) v.currentTime = end - 0.5;
                }
                v.play().catch(() => {});
            }
            if (this.lowered) { const h = this.lowered.prev; this.lowered = null; this.pickQuality(h); }
        } catch {}
    }

    qualityItems() {
        const out = [];
        document.querySelectorAll('.js-qsb_list_wrp *, [class*="qsb_"] *, [class*="rendition"] *, [class*="quality_"] *, .vjs-menu-item *, [class*="resolution"] *, [class*="Resolution"] *, [role="menu"] *, [role="listbox"] *').forEach(el => {
            if (el.children.length || el.closest('button.player-resolution, button.vjs-icon-hd')) return;
            const m = (el.textContent || '').trim().match(/^(\d{3,4})\s*p?$/i);
            if (m) {
                const row = el.closest('li,a,button,div') || el;
                const mark = /(^|[\s_-])(active|selected|current|checked|__selected|__active)($|[\s_-])/;
                out.push({ el, h: +m[1], sel: mark.test(row.className) || mark.test(el.className) });
            }
        });
        return out;
    }

    openQualityMenu() {
        document.querySelector('.controls_current_rendition, #quality-btn, .player-resolution, button.vjs-icon-hd')?.click();
    }

    setLowest() {
        this.openQualityMenu();
        setTimeout(() => {
            try {
                const items = this.qualityItems();
                if (items.length < 2) return;
                const low = items.reduce((a, b) => b.h < a.h ? b : a);
                const cur = items.find(i => i.sel);
                if (cur && cur.h === low.h) return;
                this.lowered = { prev: cur ? cur.h : Math.max(...items.map(i => i.h)) };
                low.el.click();
            } catch {}
        }, 500);
    }

    pickQuality(h) {
        this.openQualityMenu();
        setTimeout(() => {
            try { this.qualityItems().find(i => i.h === h)?.el.click(); } catch {}
        }, 500);
    }
}

const autoAge = () => {
    if (!BC_RE.test(location.hostname)) return;
    const sel = '.js-18_plus_warning a.js-close_warning, #popup_18_plus a.button_18_plus';
    let clicked = false;
    const cleanup = () => {
        try { document.body?.classList.remove('bd_18plus'); document.documentElement.classList.remove('ht_18plus'); } catch {}
    };
    const accept = () => {
        const a = document.querySelector(sel);
        if (!a) return false;
        if (clicked) return true;
        clicked = true;
        a.addEventListener('click', e => e.preventDefault(), { once: true, capture: true });
        try { a.click(); } catch {}
        const done = () => setTimeout(cleanup, 150);
        try { fetch(a.href, { credentials: 'include', cache: 'no-store' }).then(done, done); } catch { done(); }
        return true;
    };
    if (accept()) return;
    const mo = new MutationObserver(() => { if (accept()) mo.disconnect(); });
    mo.observe(document.documentElement, { childList: true, subtree: true });
    setTimeout(() => mo.disconnect(), 20000);
};
autoAge();

const VIEWERS_SEL = '#bChatHeader .js-oc_count, .chat-header-inner .js-oc_count, #online-chat .js-oc_count, .chat-info-viewers, .v-viewers, .js-oc_count, .oc_count, .player-viewers-count, .HeaderRoomInfo__numViewers, [data-testid="viewers-count"]';
const readViewers = () => document.querySelector(VIEWERS_SEL)?.textContent.trim();
const markFav = (btn, on) => {
    if (!btn) return;
    btn.style.background = '';
    btn.style.borderColor = '';
    btn.classList.toggle('fav-on', !!on);
};

const SLEEP_OPTS = [0, 15, 30, 45, 60, 90, 120];

class SleepTimer {
    constructor(ui, rec, bg) {
        this.ui = ui;
        this.rec = rec;
        this.bg = bg;
        this.lock = false;
        this.guard = 0;
        this.cover = null;
        this.mo = null;
        this.end = 0;
        this.mins = 0;
        this.t = 0;
        this.iv = 0;
        this.modal = null;
        this.at = 0;
        const end = +Store.get('bc_sleep_end', 0) || 0;
        if (end > Date.now()) {
            this.mins = +Store.get('bc_sleep_min', 0) || 0;
            this.arm(end);
        } else if (end) {
            Store.set('bc_sleep_end', 0);
            Store.set('bc_sleep_min', 0);
        }
        const lockAt = +Store.get('bc_sleep_lock', 0) || 0;
        if (lockAt && Date.now() - lockAt < 7200000) this.engage(); else if (lockAt) Store.set('bc_sleep_lock', 0);
        ['play', 'playing', 'loadstart', 'loadedmetadata', 'canplay'].forEach(t => document.addEventListener(t, e => this.onPlay(e), true));
        document.addEventListener('timeupdate', () => this.check(), true);
        onPageEvent('visibilitychange', () => this.check());
    }

    left() { return Math.max(0, this.end - Date.now()); }

    fmt() {
        const t = Math.ceil(this.left() / 1000), p = n => String(n).padStart(2, '0');
        return t >= 3600 ? `${Math.floor(t / 3600)}:${p(Math.floor(t / 60) % 60)}:${p(t % 60)}` : Helpers.formatTime(t);
    }

    set(min) { this.setMs(min * 60000); }

    setMs(ms) {
        if (!(ms > 0)) return this.cancel();
        ms = Math.min(Math.round(ms), 86400000);
        this.mins = ms / 60000;
        const end = Date.now() + ms;
        Store.set('bc_sleep_end', end);
        Store.set('bc_sleep_min', this.mins);
        this.arm(end);
    }

    arm(end) {
        clearTimeout(this.t);
        clearInterval(this.iv);
        this.end = end;
        this.t = setTimeout(() => this.check(), Math.max(0, end - Date.now()) + 50);
        this.iv = setInterval(() => { this.paint(); this.check(); }, 1000);
        this.paint();
    }

    cancel() {
        clearTimeout(this.t);
        clearInterval(this.iv);
        this.t = this.iv = 0;
        this.end = 0;
        this.mins = 0;
        Store.set('bc_sleep_end', 0);
        Store.set('bc_sleep_min', 0);
        this.paint();
    }

    check() {
        if (this.end && Date.now() >= this.end) this.fire();
    }

    engage() {
        this.lock = true;
        this.strip();
        this.showCover();
        clearInterval(this.guard);
        this.guard = setInterval(() => this.strip(), 2000);
        if (!this.mo) {
            const hasMedia = n => n.nodeType === 1 && (n.matches('video,audio') || !!n.querySelector('video,audio'));
            this.mo = new MutationObserver(recs => {
                for (const r of recs) for (const n of r.addedNodes) if (hasMedia(n)) return this.strip();
            });
            this.mo.observe(document.documentElement, { childList: true, subtree: true });
        }
    }

    unlock() {
        this.lock = false;
        clearInterval(this.guard);
        this.guard = 0;
        this.mo?.disconnect();
        this.mo = null;
        this.cover?.remove();
        this.cover = null;
        Store.set('bc_sleep_lock', 0);
    }

    wake() {
        this.unlock();
        location.reload();
    }

    strip() {
        try { window.dispatchEvent(new Event('bc_sleep_kill')); } catch {}
        try {
            document.querySelectorAll('video,audio').forEach(v => {
                try {
                    v.pause();
                    v.srcObject?.getTracks?.().forEach(t => t.stop());
                    v.srcObject = null;
                    v.removeAttribute('src');
                    v.load();
                } catch {}
                v.remove();
            });
        } catch {}
    }

    showCover() {
        if (this.cover?.isConnected) return;
        const c = mk('div', '');
        c.style.cssText = 'position:fixed;inset:0;z-index:0;background:#000;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;text-align:center;padding:24px;color:#8a8a90;font-size:15px;pointer-events:auto;touch-action:manipulation;cursor:pointer';
        String(L().sleep_wake).split('\n').forEach(t => c.append(textEl('', t, 'div')));
        c.onclick = () => this.wake();
        this.ui.shadow.insertBefore(c, this.ui.shadow.firstChild);
        this.cover = c;
    }

    onPlay(e) {
        if (!this.lock || !(e.target instanceof HTMLMediaElement)) return;
        this.strip();
    }

    fire() {
        this.cancel();
        Store.set('bc_sleep_lock', Date.now());
        let wasRec = false;
        try {
            const btn = this.ui.elements.bRec;
            if (this.rec?.mRec && this.rec.mRec.state !== 'inactive') { wasRec = true; this.rec.stop(btn, btn.querySelector('sub')); }
        } catch {}
        if (this.bg) this.bg.paused = null;
        try { this.ui.flash(this.ui.elements.bBg, 'OK'); } catch {}
        if (wasRec) setTimeout(() => { if (Store.get('bc_sleep_lock', 0)) this.engage(); }, 2000);
        else this.engage();
    }

    paint() {
        const sub = this.ui.elements.bBg?.querySelector('sub');
        if (sub && !sub._bcFlashT) {
            if (this.end) {
                sub._slp = true;
                sub.textContent = this.fmt();
            } else if (sub._slp) {
                sub._slp = false;
                sub.textContent = L().bg;
            }
        }
        this.paintModal();
    }

    paintModal() {
        const info = this.modal?.info;
        if (!info || !info.isConnected) return;
        info.textContent = this.end ? `${L().sleep_left}: ${this.fmt()}` : '';
    }

    open() {
        if (!this.modal) {
            const overlay = mk('div', 'bm-overlay');
            const modal = mk('div', 'bm-modal rs-modal');
            const hdr = mk('div', 'bm-hdr');
            const title = mk('span', 'bm-title');
            const closeBtn = mk('button', 'bm-close');
            closeBtn.innerHTML = '×';
            hdr.append(title, closeBtn);
            const body = mk('div', 'bm-list');
            modal.append(hdr, body);
            overlay.appendChild(modal);
            this.ui.shadow.appendChild(overlay);
            const close = () => { overlay.classList.remove('open'); overlay._fromSt = false; overlay._bk?.(); };
            closeBtn.onclick = close;
            overlay.onclick = e => { if (e.target === overlay && Date.now() - this.at > 400) close(); };
            this.modal = { overlay, title, body, close, info: null };
        }
        this.at = Date.now();
        this.render();
        this.modal.overlay.classList.add('open');
    }

    render() {
        const m = this.modal;
        if (!m) return;
        const l = L();
        m.title.innerHTML = `${icons.sleep} ${escHTML(l.sleep_title)}`;
        const chips = mk('div', 'rs-chips');
        SLEEP_OPTS.forEach(v => {
            const on = v === 0 ? !this.end : !!this.end && v === this.mins;
            const b = mk('button', `bm-tbtn${on ? ' on' : ''}`);
            b.textContent = v ? `${v} ${l.u_m}` : l.rs_off;
            b.onclick = () => { this.set(v); m.close(); };
            chips.append(b);
        });
        const field = (unit, max) => {
            const wrap = mk('label', 'rs-note');
            wrap.style.cssText = 'flex:1;display:flex;flex-direction:column;gap:4px;min-width:0';
            const inp = mk('input', 'bm-note');
            inp.type = 'number';
            inp.min = '0';
            inp.max = String(max);
            inp.step = '1';
            inp.placeholder = '0';
            inp.inputMode = 'numeric';
            inp.style.textAlign = 'center';
            inp.onkeydown = e => e.stopPropagation();
            wrap.append(textEl('', unit, 'span'), inp);
            return { wrap, inp };
        };
        const fh = field(l.u_h, 24), fm = field(l.u_m, 1440), fs = field(l.sleep_sec, 86400);
        const row = mk('div', '');
        row.style.cssText = 'display:flex;gap:8px';
        row.append(fh.wrap, fm.wrap, fs.wrap);
        const go = mk('button', 'bm-btn sel');
        go.textContent = l.sleep_start;
        const start = () => {
            const n = f => Math.max(0, parseInt(f.inp.value, 10) || 0);
            const ms = (n(fh) * 3600 + n(fm) * 60 + n(fs)) * 1000;
            if (!ms) return;
            this.setMs(ms);
            m.close();
        };
        go.onclick = start;
        [fh, fm, fs].forEach(f => { f.inp.onkeydown = e => { e.stopPropagation(); if (e.key === 'Enter') { e.preventDefault(); start(); } }; });
        m.info = mk('div', 'rs-info');
        m.body.replaceChildren(chips, textEl('hd-sec', l.sleep_custom), row, go, m.info, textEl('rs-note', l.sleep_hint));
        this.paintModal();
    }
}


const RAD = { NODE: 42, R0: 84, RSTEP: 62, DEAD: 26, ARC: 0.44, HOLD: 380, FAB: 48 };
const radDiff = (a, b) => {
    let d = (a - b) % (Math.PI * 2);
    if (d > Math.PI) d -= Math.PI * 2;
    if (d < -Math.PI) d += Math.PI * 2;
    return d;
};
const RAD_CSS = `.rm-fab{position:fixed;width:48px;height:48px;border-radius:50%;display:none;align-items:center;justify-content:center;color:#fff;background:var(--th);border:2px solid rgba(255,255,255,.35);box-shadow:0 4px 15px rgba(0,0,0,.6);pointer-events:auto;touch-action:none!important;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;cursor:pointer;opacity:.85;z-index:2147483640;transition:transform .15s,opacity .15s,box-shadow .15s}
.rm-fab.on{display:flex}.rm-fab:hover{opacity:1}.rm-fab.moving{transform:scale(1.25);opacity:1;box-shadow:0 0 0 6px rgba(255,255,255,.2),0 8px 24px rgba(0,0,0,.7)}.rm-fab svg{width:24px;height:24px;pointer-events:none}
.rm-ov{position:fixed;inset:0;display:none;pointer-events:none;touch-action:none;z-index:2147483645;background:rgba(0,0,0,.38)}.rm-ov.open{display:block}.rm-ov.sticky{pointer-events:auto}
.rm-stage{position:absolute;width:0;height:0;transform-origin:0 0}
.rm-ring{position:absolute;border-radius:50%;box-sizing:content-box;border-style:solid;border-color:rgba(255,255,255,.07);transform:translate(-50%,-50%);pointer-events:none;z-index:0}
.rm-hub{position:absolute;z-index:1;width:64px;height:64px;margin:-32px 0 0 -32px;border-radius:50%;background:rgba(15,15,18,.95);border:2px solid rgba(255,255,255,.25);color:#fff;font:700 10px/1.1 system-ui,sans-serif;display:flex;align-items:center;justify-content:center;text-align:center;padding:4px;overflow:hidden;word-break:break-word;pointer-events:auto;cursor:pointer;transition:background .1s}
.rm-hub.lit{background:var(--th)}.rm-hub svg{width:24px;height:24px}
.rm-node{position:absolute;z-index:2;width:42px;height:42px;margin:-21px 0 0 -21px;border-radius:50%;background:rgba(15,15,18,.95);border:1px solid rgba(255,255,255,.2);color:#fff;display:flex;align-items:center;justify-content:center;pointer-events:auto;cursor:pointer;box-shadow:0 3px 10px rgba(0,0,0,.5);animation:rmPop .14s ease-out;transition:transform .1s,background .1s}
.rm-node svg{width:20px;height:20px;pointer-events:none}
.rm-node.grp::after{content:'';position:absolute;right:2px;bottom:2px;width:8px;height:8px;border-radius:50%;background:var(--th);border:1px solid #fff}
.rm-node.hot{background:var(--th);transform:scale(1.28);border-color:#fff;z-index:3}
@keyframes rmPop{from{transform:scale(.3);opacity:0}to{transform:scale(1);opacity:1}}`;

class RadialMenu {
    constructor(ui, app) {
        this.ui = ui;
        this.app = app;
        this.on = Store.get('bc_rad', false) === true;
        this.mode = '';
        this.path = [];
        this.lv = [];
        this.items = [];
        this.scale = 1;
        const st = document.createElement('style');
        st.textContent = RAD_CSS;
        ui.shadow.appendChild(st);
        this.fab = mk('div', 'rm-fab');
        this.fab.innerHTML = icons.target;
        this.ov = mk('div', 'rm-ov');
        this.stage = mk('div', 'rm-stage');
        this.hubEl = mk('div', 'rm-hub');
        this.ov.appendChild(this.stage);
        ui.shadow.append(this.ov, this.fab);
        this.bind();
        this.placeFab();
        this.fab.classList.toggle('on', this.on);
        window.addEventListener('resize', () => { this.close(); this.placeFab(); }, { passive: true });
        window.addEventListener('keydown', e => { if (e.key === 'Escape' && this.mode) this.close(); }, true);
    }

    setEnabled(v) {
        this.on = !!v;
        Store.set('bc_rad', this.on);
        this.fab.classList.toggle('on', this.on);
        if (!this.on) this.close();
        this.placeFab();
    }

    resetPos() {
        Store.set('bc_rad_x', null);
        Store.set('bc_rad_y', null);
        this.placeFab();
    }

    fabPos() {
        const W = window.innerWidth, H = window.innerHeight, S = RAD.FAB;
        const x = parseFloat(Store.get('bc_rad_x', null)), y = parseFloat(Store.get('bc_rad_y', null));
        return {
            x: clamp(Number.isFinite(x) ? x : W - S - 14, 4, Math.max(4, W - S - 4)),
            y: clamp(Number.isFinite(y) ? y : Math.round(H * 0.55), 4, Math.max(4, H - S - 4))
        };
    }

    placeFab() {
        const p = this.fabPos();
        this.fab.style.left = `${p.x}px`;
        this.fab.style.top = `${p.y}px`;
    }

    tree() {
        const l = L(), ui = this.ui, app = this.app, vc = app.videoController, el = ui.elements;
        const press = b => {
            if (!b) return;
            if (b.onpointerup) {
                const o = { button: 0, pointerType: 'touch', isPrimary: true, bubbles: true };
                b.dispatchEvent(new PointerEvent('pointerdown', o));
                b.dispatchEvent(new PointerEvent('pointerup', o));
            } else b.click();
        };
        const vol = d => () => { const v = vc.cachedVideo; if (v) vc.setVolume(v.volume + d); };
        const addFav = () => {
            const name = currentSite.getName();
            if (name && !isFavName(name)) { app.bookmarks.add(); ui.flash(el.bFav, 'OK'); app.updateViewersCount(); }
            else ui.flash(el.bFav, 'ERR');
        };
        return [
            { icon: icons.vol, label: l.rad_media, kids: [
                { icon: icons.bgOn, label: l.bg, run: () => press(el.bBg) },
                { icon: icons.mute, label: l.sound, run: () => press(el.bMute) },
                { icon: icons.volMed, label: l.rad_vup, run: vol(0.1) },
                { icon: icons.volLow, label: l.rad_vdn, run: vol(-0.1) },
                { icon: icons.snap, label: l.snap, run: () => vc.takeScreenshot() },
                { icon: icons.rec, label: l.rec, run: () => app.recorder.toggle() }
            ] },
            { icon: icons.fs, label: l.rad_view, kids: [
                { icon: icons.qual, label: l.qual, run: () => ui.toggleQuality() },
                { icon: icons.pip, label: l.pip, run: () => vc.togglePiP() },
                { icon: icons.fs, label: l.fs, run: () => vc.toggleFullscreen() },
                { icon: icons.thtr, label: l.thtr, run: () => vc.toggleTheater() }
            ] },
            { icon: icons.fav, label: l.rad_nav, kids: [
                { icon: icons.search, label: l.search, run: () => app.search.open() },
                { icon: icons.bookmark, label: l.favs, run: () => app.bookmarks.open() },
                { icon: icons.fav, label: l.bm_add, run: addFav },
                { icon: icons.favPrev, label: l.rad_prev, run: () => el.bFavPrev?.click() },
                { icon: icons.favNext, label: l.rad_next, run: () => el.bFavNext?.click() },
                { icon: icons.copy, label: l.copy, run: () => el.bCopy?.click() }
            ] },
            { icon: icons.grid, label: l.rad_page, kids: [
                { icon: icons.home, label: l.home, run: () => { location.href = '/'; } },
                { icon: icons.rel, label: l.rel, run: () => location.reload() },
                { icon: AppState.dark ? icons.sun : icons.moon, label: l.dark, run: () => ui.toggleDark() },
                { icon: icons.sleep, label: l.sleep_title, run: () => app.sleep.open() },
                { icon: icons.history, label: l.hist_title, run: () => app.history.open() },
                { icon: icons.min, label: l.min, run: () => ui.toggleMinimize(true) },
                { icon: icons.close, label: l.hide, run: () => ui.toggleHide(true) }
            ] },
            { icon: icons.gear, label: l.settings, run: () => app.settings.open() }
        ];
    }

    fan(r) {
        const { x: hx, y: hy } = this.hub, W = window.innerWidth, H = window.innerHeight, M = RAD.NODE / 2 + 4, b = this.base;
        const ok = a => { const x = hx + Math.cos(a) * r, y = hy + Math.sin(a) * r; return x >= M && x <= W - M && y >= M && y <= H - M; };
        let lo = 0, hi = 0;
        const st = 0.04;
        while (hi < Math.PI && ok(b + hi + st)) hi += st;
        while (lo > -Math.PI && ok(b + lo - st)) lo -= st;
        return { lo, hi, full: hi - lo >= Math.PI * 2 - 0.12 };
    }

    layout(list, d, parentAng) {
        const r = RAD.R0 + d * RAD.RSTEP, n = list.length, f = d === 0 ? this.f0 : this.f1, b = this.base;
        let step, angles;
        if (d === 0) {
            if (f.full) {
                step = (Math.PI * 2) / n;
                angles = list.map((_, i) => -Math.PI / 2 + i * step);
            } else {
                step = n > 1 ? Math.min(1.3, (f.hi - f.lo) / (n - 1)) : 0;
                const c = b + (f.lo + f.hi) / 2;
                angles = list.map((_, i) => c + (i - (n - 1) / 2) * step);
            }
        } else {
            step = RAD.ARC;
            let c = parentAng;
            if (!f.full) {
                const span = f.hi - f.lo;
                if ((n - 1) * step > span) step = n > 1 ? span / (n - 1) : 0;
                const w = ((n - 1) * step) / 2;
                c = b + clamp(radDiff(parentAng, b), f.lo + w, f.hi - w);
            }
            angles = list.map((_, i) => c + (i - (n - 1) / 2) * step);
        }
        const out = angles.map(a => ({ a, x: Math.cos(a) * r, y: Math.sin(a) * r }));
        out.step = step;
        return out;
    }

    pick(vx, vy) {
        const dist = Math.hypot(vx, vy);
        if (dist < RAD.DEAD) return [];
        const ang = Math.atan2(vy, vx), path = [];
        let list = this.items, parentAng = null;
        for (let d = 0; list; d++) {
            if (d > 0 && dist < RAD.R0 + d * RAD.RSTEP - RAD.NODE / 2 - 8) break;
            const pos = this.layout(list, d, parentAng);
            let best = -1, bd = 1e9;
            pos.forEach((p, i) => { const df = Math.abs(radDiff(ang, p.a)); if (df < bd) { bd = df; best = i; } });
            if (d === 0 && dist >= RAD.R0 + RAD.RSTEP - RAD.NODE / 2 - 8) {
                const c = this.path[0], cn = c != null ? list[c] : null;
                if (cn && cn.kids) {
                    const kp = this.layout(cn.kids, 1, pos[c].a), tol = Math.max(kp.step, 0.2) * 0.6;
                    const hit = kp.some(p => Math.abs(radDiff(ang, p.a)) <= tol);
                    if (hit) best = c;
                }
            }
            if (d > 0 && bd > Math.max(pos.step, 0.2) * 0.6) break;
            path.push(best);
            const node = list[best];
            if (!node.kids) break;
            parentAng = pos[best].a;
            list = node.kids;
        }
        return path;
    }

    nodeAtPath(path) {
        let list = this.items, node = null;
        for (const i of path) { node = list && list[i] || null; list = node && node.kids; }
        return node;
    }

    openMenu(c, mode) {
        this.items = this.tree();
        this.path = [];
        this.scale = 1;
        this.hub = { x: c.x, y: c.y };
        const cx = window.innerWidth / 2, cy = window.innerHeight / 2;
        this.base = Math.hypot(cx - c.x, cy - c.y) < 20 ? -Math.PI / 2 : Math.atan2(cy - c.y, cx - c.x);
        this.f0 = this.fan(RAD.R0);
        this.f1 = this.fan(RAD.R0 + RAD.RSTEP);
        this.stage.style.cssText = `left:${c.x}px;top:${c.y}px`;
        this.lv = [];
        this.stage.replaceChildren(this.hubEl);
        this.mode = mode;
        this.ov.className = `rm-ov open${mode === 'sticky' ? ' sticky' : ''}`;
        this.render();
        this.updateHub();
    }

    buildLevel({ list, pos, key, d }) {
        const el = mk('div', 'rm-lvl');
        const r = RAD.R0 + d * RAD.RSTEP, band = RAD.NODE + 12;
        const ring = mk('div', 'rm-ring');
        ring.style.cssText = `width:${2 * r - band}px;height:${2 * r - band}px;border-width:${band}px`;
        el.appendChild(ring);
        const nodes = list.map((it, i) => {
            const n = mk('div', `rm-node${it.kids ? ' grp' : ''}`);
            n.innerHTML = it.icon;
            n.title = it.label;
            n.dataset.d = d;
            n.dataset.i = i;
            n.style.left = `${pos[i].x}px`;
            n.style.top = `${pos[i].y}px`;
            el.appendChild(n);
            return n;
        });
        this.stage.appendChild(el);
        return { key, list, nodes, el };
    }

    render() {
        const levels = [];
        let list = this.items, parentAng = null, key = '';
        for (let d = 0; list; d++) {
            const pos = this.layout(list, d, parentAng);
            levels.push({ list, pos, key, d });
            const i = this.path[d];
            if (i == null || !list[i] || !list[i].kids) break;
            parentAng = pos[i].a;
            key += `/${i}`;
            list = list[i].kids;
        }
        let from = levels.findIndex((lv, d) => !this.lv[d] || this.lv[d].key !== lv.key);
        if (from < 0) from = levels.length;
        while (this.lv.length > from) this.lv.pop().el.remove();
        for (let d = from; d < levels.length; d++) this.lv.push(this.buildLevel(levels[d]));
        this.lv.forEach((lv, d) => lv.nodes.forEach((n, i) => n.classList.toggle('hot', this.path[d] === i)));
    }

    updateHub() {
        const n = this.nodeAtPath(this.path);
        this.hubEl.classList.toggle('lit', !!n);
        if (n) this.hubEl.textContent = n.label; else this.hubEl.innerHTML = icons.target;
    }

    setPath(p) {
        if (p.length === this.path.length && p.every((v, i) => v === this.path[i])) return;
        this.path = p;
        this.render();
        this.updateHub();
        if (p.length && navigator.vibrate) navigator.vibrate(8);
    }

    sticky() {
        this._stAt = Date.now();
        this.mode = 'sticky';
        this.ov.classList.add('sticky');
    }

    close() {
        if (!this.mode) return;
        this.mode = '';
        this.ov.className = 'rm-ov';
        this.path = [];
        this.lv = [];
        this.stage.replaceChildren();
    }

    run(it) {
        try { it.run(); } catch (err) { console.warn('[BCU radial]', err); }
    }

    bind() {
        const f = this.fab;
        let st = null;
        f.oncontextmenu = e => e.preventDefault();
        ['touchstart', 'touchmove', 'touchend'].forEach(t => f.addEventListener(t, e => { if (e.cancelable) e.preventDefault(); }, { passive: false }));
        ['touchstart', 'touchmove'].forEach(t => this.ov.addEventListener(t, e => { if (e.cancelable) e.preventDefault(); }, { passive: false }));
        window.addEventListener('contextmenu', e => {
            const path = e.composedPath ? e.composedPath() : [];
            if (this.mode || path.includes(f) || path.includes(this.ov)) { e.preventDefault(); e.stopImmediatePropagation(); }
        }, true);
        f.onpointerdown = e => {
            if (!isPrimaryPress(e)) return;
            swallow(e);
            this.close();
            try { f.setPointerCapture(e.pointerId); } catch {}
            const p = this.fabPos();
            st = { id: e.pointerId, ox: e.clientX, oy: e.clientY, moved: false, timer: 0 };
            this.openMenu({ x: p.x + RAD.FAB / 2, y: p.y + RAD.FAB / 2 }, 'drag');
            st.timer = setTimeout(() => {
                if (!st || st.moved || this.mode !== 'drag') return;
                this.close();
                this.mode = 'move';
                f.classList.add('moving');
                if (navigator.vibrate) navigator.vibrate(15);
            }, RAD.HOLD);
        };
        f.onpointermove = e => {
            if (!st || e.pointerId !== st.id) return;
            if (this.mode === 'move') {
                const S = RAD.FAB;
                f.style.left = `${clamp(e.clientX - S / 2, 4, window.innerWidth - S - 4)}px`;
                f.style.top = `${clamp(e.clientY - S / 2, 4, window.innerHeight - S - 4)}px`;
                return;
            }
            if (this.mode !== 'drag') return;
            const vx = e.clientX - st.ox, vy = e.clientY - st.oy;
            if (!st.moved && Math.hypot(vx, vy) > 10) { st.moved = true; clearTimeout(st.timer); }
            if (st.moved) this.setPath(this.pick(vx / this.scale, vy / this.scale));
            if (e.cancelable) e.preventDefault();
        };
        const end = e => {
            if (!st || e.pointerId !== st.id) return;
            clearTimeout(st.timer);
            const s = st;
            st = null;
            try { f.releasePointerCapture(e.pointerId); } catch {}
            if (this.mode === 'move') {
                f.classList.remove('moving');
                this.mode = '';
                Store.set('bc_rad_x', f.style.left);
                Store.set('bc_rad_y', f.style.top);
                return;
            }
            if (this.mode !== 'drag') return;
            if (e.type === 'pointercancel') return this.close();
            const node = this.nodeAtPath(this.path);
            if (node && !node.kids) { this.close(); this.run(node); return; }
            if (node || !s.moved) return this.sticky();
            this.close();
        };
        f.onpointerup = end;
        f.onpointercancel = end;
        f.onlostpointercapture = e => { if (st && e.pointerId === st.id) end({ type: 'pointercancel', pointerId: e.pointerId }); };
        window.addEventListener('blur', () => { if (st) end({ type: 'pointercancel', pointerId: st.id }); });
        document.addEventListener('visibilitychange', () => { if (document.hidden && st) end({ type: 'pointercancel', pointerId: st.id }); });
        this.ov.onpointerup = e => {
            if (this.mode !== 'sticky' || !isPrimaryPress(e) || Date.now() - (this._stAt || 0) < 150) return;
            swallow(e);
            const n = e.target.closest ? e.target.closest('.rm-node') : null;
            if (!n) return this.close();
            const d = +n.dataset.d, i = +n.dataset.i, it = this.lv[d] && this.lv[d].list[i];
            if (!it) return;
            if (it.kids) {
                const same = this.path[d] === i && this.path.length === d + 1;
                this.setPath(same ? this.path.slice(0, d) : this.path.slice(0, d).concat(i));
            } else { this.close(); this.run(it); }
        };
    }
}

class App {
    constructor() {
        this.ui = new UIController();
        this.videoController = new VideoController(this.ui);
        this.recorder = new MediaRecorderManager(this.videoController, this.ui);
        this.bgSaver = new BgSaver(this.videoController, this.recorder);
        this.bookmarks = new BookmarkManager(this.ui);
        this.search = new SearchManager(this.ui);

        this.ui.bookmarkManager = this.bookmarks;
        this.ui.searchManager = this.search;
        this.hideManager = new HideManager(this.ui);
        this.ui.hideManager = this.hideManager;
        this.history = new HistoryManager(this.ui, this.bookmarks);
        this.thumbStars = new ThumbStars(this.bookmarks);
        this.ui.historyManager = this.history;
        this.calendar = new CalendarManager(this.ui, this.bookmarks);
        this.ui.calendarManager = this.calendar;
        this.ui.thumbStars = this.thumbStars;
        this.ui.recorder = this.recorder;
        this.settings = new SettingsManager(this.ui);
        this.ui.settingsManager = this.settings;
        this.sleep = new SleepTimer(this.ui, this.recorder, this.bgSaver);
        this.ui.sleepTimer = this.sleep;
        this.ui.radial = new RadialMenu(this.ui, this);

        const vc = this.videoController, el = this.ui.elements;
        const bgClick = el.bBg.onclick;
        el.bBg.onclick = null;
        Helpers.bindLongPress(el.bBg, () => bgClick.call(el.bBg), () => this.sleep.open());
        Helpers.bindLongPress(el.bMute,
            () => {
                if (AppState.gmute) setGMute(false);
                vc.toggleMute();
            },
            () => {
                setGMute(true);
                const v = vc.cachedVideo;
                if (v) { v.muted = true; v.volume = 0; }
                this.ui.flash(el.bMute, 'LOCK');
                vc.syncUI();
            }
        );
        el.bPip.onclick = () => vc.togglePiP();
        el.bFs.onclick = () => vc.toggleFullscreen();
        el.bThtr.onclick = () => vc.toggleTheater();
        el.bShot.onclick = () => vc.takeScreenshot();
        el.vIco.onclick = () => vc.toggleMute();
        Helpers.bindLongPress(el.bRec, () => this.recorder.toggle(), () => this.recorder.openSettings());
        el.bSearch.onclick = () => this.search.open();
        const goFav = async (dir, btn) => {
            if (btn._busy) return;
            btn._busy = true;
            btn.style.opacity = '.5';
            try {
                await this.bookmarks.checkStatuses();
                const here = siteKey(location.hostname);
                const curName = currentSite.getName();
                const list = AppState.bookmarks
                    .filter(b => b.status === 1 && isSafeUrl(b.url) && urlSite(b.url) === here)
                    .sort((x, y) => (!!y.pin - !!x.pin) || x.name.localeCompare(y.name));
                const idx = list.findIndex(b => String(b.name).toLowerCase() === String(curName).toLowerCase());
                if (!list.length || (list.length === 1 && idx === 0)) return this.ui.flash(btn, 'ERR');
                const next = idx < 0 ? (dir > 0 ? list[0] : list[list.length - 1]) : list[(idx + dir + list.length) % list.length];
                location.href = linkFor(next.url);
            } catch { this.ui.flash(btn, 'ERR'); }
            finally { btn._busy = false; btn.style.opacity = ''; }
        };
        el.bFavPrev.onclick = () => goFav(-1, el.bFavPrev);
        el.bFavNext.onclick = () => goFav(1, el.bFavNext);
        el.bFavPrev.title = el.bFavNext.title = '';
        el.vSlider.oninput = e => vc.setVolume(parseFloat(e.target.value));
        el.vSlider.onwheel = e => {
            e.preventDefault();
            if (vc.cachedVideo) vc.setVolume(clamp(vc.cachedVideo.volume + (e.deltaY < 0 ? 0.05 : -0.05), 0, 1));
        };
        Helpers.bindLongPress(el.bFav,
            () => setTimeout(() => this.bookmarks.open(), 50),
            () => {
                const name = currentSite.getName();
                if (name && !isFavName(name)) {
                    this.bookmarks.add();
                    this.ui.flash(el.bFav, 'OK');
                    this.updateViewersCount();
                } else this.ui.flash(el.bFav, 'ERR');
            }
        );
        el.bFav.onclick = e => { e.preventDefault(); e.stopPropagation(); };

        this.ui.updateLabels();
        this.ui.injectSiteCSS();
        if (AppState.bgPlay) this.ui.enforceBackgroundPlay();
        if (AppState.isMinimized) this.ui.toggleMinimize(true, true);
        if (AppState.hasPos) this.ui.clampPosition();
        if (AppState.isHidden) this.ui.toggleHide(true);

        onRemoteChange('bc_bookmarks', v => this.bookmarks.applyRemote(v));
        onRemoteChange('bc_gmute', v => {
            try { AppState.gmute = JSON.parse(v) === true; } catch {}
            const cv = vc.cachedVideo;
            if (AppState.gmute && cv) { cv.muted = true; cv.volume = 0; }
            vc.syncUI();
        });

        window.addEventListener('resize', () => {
            if (AppState.hasPos) this.ui.clampPosition();
        }, { passive: true });
        onPageEvent('visibilitychange', () => {
            if (realHidden() || !AppState.hasPos) return;
            setTimeout(() => { this.ui.applyPosition(); this.ui.clampPosition(); }, 150);
        });

        let tick = 0;
        setInterval(() => {
            if (document.hidden) return;
            tick++;
            this.ui.injectSiteCSS();
            this.updateViewersCount();
            if (tick % 5 === 0) this.slowTasks();
        }, 3000);
        setTimeout(() => this.updateViewersCount(), 1000);
    }

    slowTasks() {
        try { applyDark(); } catch {}
        if (!this.ui.host.isConnected) document.documentElement.appendChild(this.ui.host);
    }

    updateViewersCount() {
        const name = currentSite.getName();
        const { stats, bFav } = this.ui.elements;
        if (stats) stats.style.visibility = name ? 'visible' : 'hidden';
        markFav(bFav, !!name && isFavName(name));
        if (!name) return;

        const txt = stats && readViewers();
        if (txt && stats._last !== txt) {
            stats.innerHTML = `${icons.eye}<span>${escHTML(txt)}</span>`;
            stats._last = txt;
        }
        const vn = parseCount(txt);
        if (Number.isFinite(vn)) this.bookmarks.setViewers(pageKey(), vn);
    }
}

const init = () => new App();
document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', init) : init();

})();